pax_global_header00006660000000000000000000000064132433416550014520gustar00rootroot0000000000000052 comment=36997d4d7a5bdc6670c1ce08acd17e23bfad8305 stella-5.1.1/000077500000000000000000000000001324334165500130105ustar00rootroot00000000000000stella-5.1.1/.gitignore000066400000000000000000000002401324334165500147740ustar00rootroot00000000000000config.log config.mak src/**/*/.deps src/**/*.o stella *.diff project.xcworkspace/ xcuserdata/ build/ src/macosx/M6502.ins *.dSYM .vscode/c_cpp_properties.json stella-5.1.1/.vscode/000077500000000000000000000000001324334165500143515ustar00rootroot00000000000000stella-5.1.1/.vscode/settings.json000066400000000000000000000015411324334165500171050ustar00rootroot00000000000000// Platzieren Sie Ihre Einstellungen in dieser Datei, um Standard- und Benutzereinstellungen zu überschreiben. { "editor.tabSize": 2, "files.trimTrailingWhitespace": true, "files.exclude": { "**/.git": true, "**/.svn": true, "**/.hg": true, "**/.DS_Store": true, "src/**/*.o": true }, "editor.trimAutoWhitespace": true, "editor.useTabStops": false, "C_Cpp.intelliSenseEngine": "Default", "files.insertFinalNewline": true, "files.associations": { "__split_buffer": "cpp", "__tree": "cpp", "atomic": "cpp", "deque": "cpp", "ios": "cpp", "list": "cpp", "map": "cpp", "set": "cpp", "string": "cpp", "string_view": "cpp", "system_error": "cpp", "vector": "cpp", "stdexcept": "cpp" } } stella-5.1.1/Announce.txt000066400000000000000000000041271324334165500153230ustar00rootroot00000000000000=========================================================================== SSSS tt lll lll SS SS tt ll ll SS tttttt eeee ll ll aaaa SSSS tt ee ee ll ll aa SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" SS SS tt ee ll ll aa aa SSSS ttt eeeee llll llll aaaaa =========================================================================== Release 5.1.1 for Linux, MacOSX and Windows =========================================================================== The Atari 2600 Video Computer System (VCS), introduced in 1977, was the most popular home video game system of the early 1980's. Now you can enjoy all of your favourite Atari 2600 games on your PC thanks to Stella! Stella is a multi-platform Atari 2600 VCS emulator. It allows you to play all of your favourite Atari 2600 games again! Stella was originally developed for Linux by Bradford W. Mott, however, it has been ported to a number of other platforms and is currently maintained by Stephen Anthony. This is the 5.1.1 release of Stella for Linux, Mac OSX and Windows. The distributions currently available are: * Binaries for Windows XP_SP3(*)/Vista/7/8/10 : Stella-5.1.1-win32.exe (32-bit EXE installer) Stella-5.1.1-x64.exe (64-bit EXE installer) Stella-5.1.1-windows.zip (32/64 bit versions) (*) Note: Support for Windows XP is problematic on some systems, and will probably be discontinued in a future release. * Binary distribution for MacOS X 10.7 and above : Stella-5.1.1-macosx.dmg (64-bit Intel) * Binary distribution in 32-bit & 64-bit Ubuntu DEB format : stella_5.1.1-1_i386.deb stella_5.1.1-1_amd64.deb * Binary distribution in 32-bit & 64-bit RPM format : stella-5.1.1-2.i386.rpm stella-5.1.1-2.x86_64.rpm * Source code distribution for all platforms : stella-5.1.1-src.tar.xz Distribution Site ================= The Stella distributions can be obtained from the Stella Website at: https://stella-emu.github.io stella-5.1.1/Changes.txt000066400000000000000000004413651324334165500151360ustar00rootroot00000000000000===========================================================================   SSSS tt lll lll  SS SS tt ll ll  SS tttttt eeee ll ll aaaa  SSSS tt ee ee ll ll aa  SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"  SS SS tt ee ll ll aa aa  SSSS ttt eeeee llll llll aaaaa  ===========================================================================  Release History ===========================================================================  5.1 to 5.1.1: (February 21, 2018) * Fixed bug in Stargunner ROM starting with a blank screen. -Have fun! 5.0.2 to 5.1: (February 4, 2018) * Added "Time Machine" mode, which automatically creates save states in user-defined intervals. The user can navigate back and forth within these states inside the emulator and the debugger. * Huge improvements to the disassembly view in the debugger and disassembly files created: - reformatting in debugger for better space utilization - much improved code and data detection - access tracking and indicators for TIA/IO/RAM adresses in disassembly - break vector is tracked (if used) - improved cycle count (page penalties, sums created in disassembly) - improved handling of instruction masking opcodes (e.g. BIT) * Fixed change tracking bug during rewind; changes were accumulated instead of being displayed only for the last rewind step. * Extended 'rewind' to take a second parameter which allows rewinding multiple states. * Added 'unwind' command, which undoes the latest rewind(s) * Added '<' (unwind) button to debugger. * Thumbulator support is not conditional any more. * Moved various developer related settings in new Developer Settings dialog. These settings now come in two groups (player/developer) and allow switching all settings at once. * Don't trap write accesses to the datastream pointers in CDF and BUS. This fixes -dev.thumb.trapfatal 1. * Complete rework of TV mode and ystart autodetection. The new implementation is more robust and reduces startup time. * Add two "grace lines" of black to the top of the frame when autodetecting ystart. * Fixed Genesis controller autodetect (Stay Frosty 2, Scramble, etc). * Fixed a bug in ystart autodetection that could cause screen jumps. * Fixed several bugs in holdselect, holdreset and holdjoyX commandline arguments; these now work as expected. * Fixed bug in TIA collision handling; it is now disabled in VBlank. * Improve TIA PF collision handling during hblank; this fixes a bug in Thrust ROM. * Fixed wrong display of HM values in debugger after 'HMCLR' has been executed. * Fixed bug with the debugger 'savedis' command in Windows; it wasn't actually saving the files at all. This has never been reported before, so I guess it shows how many people use that functionality. * The debugger 'savedis', 'saverom' and 'saveses' now save files in a default, user-visible directory (see the documentation for more information). In the case of 'saveses', the filename is now named based on the date and time of when the command was entered. * Fixed bug with saving snapshots in 1x mode; there was graphical corruption in some cases. Such snapshots also now include any TV effects / phosphor blending currently in use. * Fixed regular-sized snapshots when phosphor effect was enabled; sometimes the image was 'double-blended', resulting in a snapshot that was too dark. * Fixed crash when selecting 'CompuMate' as a controller type for a non- CompuMate ROM; this controller type can no longer be manually selected, and will be used automatically used for CompuMate ROMs. * Fixed cheat codes, so 7 digits codes are now accepted as described in the doc. * Fixed swapped ports being displayed wrong in System Logs and debugger. * Added options to erase the AtariVox/Savekey flash memory, either for all ROMs or only the current one. Also added a message (configurable) when the flash memory is accessed. * Access to the AtariVox/SaveKey can be signaled with a message. * Added new interface palette 'Light'. * Frame stats display made transparent. Also it now displays the real frame rate and if the developer settings group is enabled. * Improved tab auto-complete in debugger. * Added conditional traps and savestate creation to debugger. * Added 'Options...' button to debugger which gives access to the options menu during debugging. * Added debugger pseudo-register '_cyclesLo' and '_cyclesHi', which give the number of CPU cycles that have occurred since emulation started. * Added debugger pseudo-register '_fcycles', which gives the number of CPU cycles that have occurred since the frame started. * Added debugger pseudo-register '_icycles', which gives the number of CPU cycles of the last instruction. * Extended debugger 'dump' command to take a second argument, indicating the end of the range to dump data. * Improved change tracking; more values are tracked and change tracking now works in case of a break too. * Added widgets for trackball and SaveKey/AtariVox controllers. * Improved emulation of 'FE' bankswitch scheme (no user-visible changes, but internally the emulation is much more accurate compared to the real thing). Related to this, improved the debugger support for this scheme (you can now switch banks in the debugger view). * Added emulation of 7800 initial RAM values and Pause key. * Added ROM properties for 'Scramble' ROMs, and updated info for all "Champ Games" ROMs. * Added ROM properties for 'Zippy the Porcupine' ROMs, and updated info for all "Chris Spry (Sprybug)" ROMs. * Support UNIX style builds (configure / make) on OSX with both XCode / clang and g++. * Fixed error when building with uClibc-ng for ARM (thanks to Sergio Prado). * Updated included PNG library to latest stable version. 5.0.1 to 5.0.2: (August 20, 2017) * Improved emulation of Trakball controller, eliminating bias in left/ right directions. Thanks to Thomas Jentzsch for the idea and code. Related to this, added 'tsense' commandline argument and associated UI item, to allow changing sensitivity of mouse trackball emulation. * Added preliminary support for multi-threading in the Blargg TV effects code. This is still a WIP; more improvements are coming. Related to this, further optimized the TIA rendering code. Also added 'threads' commandline argument and associated UI item to enable/disable multi-threading. Thanks to Thomas Jentzsch for the bulk of the work in this area. * Blargg TV effects now no longer cut off the right side of the image (by several pixels) in certain cases. * Updated CDF scheme to latest version from Spiceware. In addition, this scheme now supports versioning, so older and newer ROMs will continue to work. * Fixed an annoying bug in Linux, where Alt-Tab'ing out of a window and then back again would pass a 'Tab' key event to the app, which in most cases would navigate to the next UI element. * Fixed potential issue with state file saving and the debugger; under certain circumstances a rewind would give a different state than before (note that the state file format has changed because of this). * Fixed lockups when entering the debugger under certain circumstances. * The debugger 'listtraps' command now shows all traps set, not just the first one(s). * Reverted joystick changes for Decathlon ROMs from last release, as it was added by mistake. 5.0 to 5.0.1: (July 23, 2017) * Fixed issues in keypad, Genesis and various other controllers that use INPTx registers; the emulation is now much more accurate in this area. * Various 'Bumper Bash' and 'Decathlon' ROMs are marked as always having all 4 directions on a joystick enabled, since they can't be played properly otherwise. * Added 'Hunchy II' from Chris Walton (cd-w) to ROM properties database. * Codebase now uses C++14 features. 4.7.3 to 5.0: (July 16, 2017) * Note: because of major TIA/6502/RIOT changes, the state file format has changed, and old state files will not work with this release. * Stella has moved from Sourceforge to Github. * Completely new TIA core is now available, ported from 6502ts by Christian Speckner (DirtyHairy). This new core is extremely accurate, and matches real hardware in almost every test we've performed. New features include: - Meltdown emulates correct - The lap number in Pole Positions displays correctly - Artifacts in the mountains on Snoopy and the Red baron are gone - Line artifacts in Title Match Pro Wrestling and Realsports Boxing are fixed - The spurious line at the left border of Video Chess now displays correctly - All 32 char text demos from AtariAge now work perfectly (Stella 4 shows artifacts on several of these) - Stella is now the only emulator to display the "Mega Bitmap Demo" (atext.bin) from AtariAge correctly - Improved starfield effect for missiles (still TODO for ball and players) - RSYNC emulation has improved, all testcases now match real hardware - Several other ROMs that have never worked in any emulator are now emulated correctly - RDY behavior with respect to write cycles is accurate - Optional YStart autodetect and more robust frame handling - NUSIZ during player draw matches hardware - RESMx during missile draw matches hardware - Paddle emulation is slightly more accurate. As a consequence, the "paddle feel" may be slightly different from Stella 4 - Fixed debug colors can now be set for each graphical object, from a choice of 'red', 'orange', 'yellow', 'green', 'blue' and 'purple'. This is accessible through the new 'tia.dbgcolors' commandline argument and within the UI. * Implemented new phosphor emulation mode, which is much closer to real TV output. Related to this, added ability to change the default phosphor blend level in the UI and through the new 'tv.phosblend' commandline argument. Special thanks to Thomas Jentzsch for the idea and implementation. * TV phosphor effect can now be force-enabled for all ROMs, instead of manually setting ROM properties for each ROM. This is accessible in the UI and through the 'tv.phosphor' commandline argument, and defaults to being off (or enabled per-ROM). * PAL color-loss and Blargg TV effects can now be enabled at the same time. Previously, when Blargg effects were enabled, PAL color-loss couldn't be shown. Related to this, the Blargg effects now use much less memory and in some cases run faster than before. * Much improved RIOT timer emulation never before seen in any emulator. Special thanks to Christian Speckner (DirtyHairy) for the implementation, and alex_79 for finding documentation that finally describes in more detail how the M6532 chip actually works. * Added BUS (experimental) and CDF bankswitching schemes, and also ARM Timer 1 support; special thanks to SpiceWare for the code. * Fixed bug with SaveKey and AtariVox not properly closing their memory files before starting another instance of the same ROM, when the ROM was opened in the ROM launcher. * Various improvements to the debugger and command prompt: - The 'cls' command now only clears the screen, not the history - The 'help' command now accepts other commands, and gives extra information about the command (ie, 'help breakif' prints extended information about the breakif command) - Added 'palette' command, which shows a color swatch of the currently active TIA palette - Added 'debugcolors' command, which shows a legend for 'fixed debug colors' mode - The previous trap'm' commands now work when setting TIA read addresses; previously they only worked for write addresses - The previous trap'm' commands are now renamed 'trap', 'trapread' and 'trapwrite' - The TIA tab now shows 'old' contents of player and ball registers - Various UI items are crossed out when disabled, to more clearly indicate their current state - Various UI items that previously required a double-click to toggle (pixel and bit widgets) now require only a single-click. - Command completion now works with internal functions and pseudo-ops (basically, anything starting with the '_' character) - System labels (aka, register names, etc) can now be typed in lower- case. Previously, these labels always had to be uppercase. - In general, input error checking is much more strictly enforced - Read-only UI items now have a different background color, to clearly indicate if an item can be modified. - Debugger '.lst' and '.sym' files are now searched based on the name of the ROM file, and not on the internal properties name. - Snapshots can now be saved by pressing the F12 key (the various other ways to save snapshots still exist). * Mouse grabbing is now enabled in windowed mode only when the ROM is using a virtual analog controller (paddles, trakball, etc). * Renamed various trakball-like controllers more accurately: AmigaMouse, AtariMouse (previously CX80) and Trakball (previously CX22). Related to this, reduced the resolution of the Trakball by half, to properly match real hardware. * The stack pointer (SP) is now initialized to $FD instead of $FF, to match research done in other 6502 projects. * Fixed bug in debugger tracing and displaying the partial TIA image; the first time entering the debugger and starting to trace, the image was blanked out (black) instead of being drawn in greyscale. Also, the image is now synchronized, instead of being two frames behind. * Fixed crash with zipped ROMs that are less than 4K in size; so far this bug has only ever occurred in Windows XP, but it's been there since Stella 4.1. * Fixed bug in 'Rom Audit' functionality; sometimes ROMs without a valid properties entry were being renamed as "Untitled.bin". * For the entire UI, removed colons and generally made the UI items easier to read. * When in 'ROM launcher mode', Stella now uses slightly less CPU time. More work is required in this area, though. * Added ROM properties for D.K. VCS homebrew ROM, thanks to Andreas Dietrich. * Added slight improvement for auto-detecting Superchip bankswitching; the new implementation now works for the NTSC 'Dig Dug' ROM. Special thanks for SpiceWare for the idea and modified implementation. * Fixed long-standing bug in 3-voice music in DPC+ bankswitching scheme; the music now sounds much more like the real thing. * For the Linux/UNIX port: - The settings directory now uses the XDG Base Directory Specification. In most cases, this means that your files will now be stored in '~/.config/stella' instead of '~/.stella'. To keep your old settings, run the following commands from the terminal: cd ~ mv .stella .config/stella You will probably need to edit '~/.config/stella/stellarc' and change some paths accordingly. * For the OSX port: - Always use the built-in png and zlib libraries instead of the system versions. - The preferences file has changed from 'net.sourceforge.Stella.plist' to 'Stella-emu.plist'. To keep your old settings, run the following commands from the terminal: cd ~/Library/Preferences mv net.sourceforge.Stella.plist Stella-emu.plist * Updated internal ROM properties database to ROM-Hunter version 13 (thanks go to RomHunter for his tireless research in this area). Related to this, updated the snapshot collection. * Updated included PNG and ZLIB libraries to latest stable version. Also, both libraries are now compiled into the app whenever one is selected. This fixes issues with a newer ZLIB not working with an older PNG, etc. * Updated build scripts for Visual Studio 2017 (Windows) and MacOS Sierra (latest version of Xcode), and make these the minimum supported versions for building Stella. * Updated UNIX configure script to work with the clang 5+ and gcc 7+ compiler versions, and fixed compile issues on AArch64 and ppc64le architectures. 4.7.2 to 4.7.3: (Nov. 21, 2016) * Added preliminary support for the 3E+ bankswitching scheme, developed by Thomas Jentzsch. * Fixed HMOVE positioning bug that occurred under certain circumstances. Thanks to Omegamatrix of AtariAge for the bug report and patch to fix the issue. * Added 'trapm', 'trapreadm', 'trapwritem' commands to debugger prompt. These are similar to the non-'m' versions, except that they also trap on all mirrors of the given address. * Fixed bug in debugger 'reset' command; it wasn't resetting the bankswitching, so after a reset the banks were in an undefined state. * Updated UNIX configure script to fix a bug where it fails in cross-compilation under certain circumstances. Thanks to Vlad Zakharov for providing a patch to fix this issue. 4.7.1 to 4.7.2: (Mar. 25, 2016) * Fixed bug when entering and exiting the debugger; sometimes the character corresponding to the '`' key would be output in the prompt area. * Updated DPC+ Thumb ARM emulation code to latest from David Welch. In particular, this fixes incorrect handling of the V flag when adding and subtracting, but also fixes compile-time warnings that I couldn't get rid of before. * Updated UNIX configure script to work with GCC 6.x compilers, and to remove references to obsolete compiler versions that can no longer be used to compile Stella. 4.7 to 4.7.1: (Feb. 13, 2016) * Improved TV 'jitter' emulation; the recovery time can now be spread over multiple frame, to simulate a real TV taking multiple frames to recover. Related to this, added new commandline argument 'tv.jitter_recovery' to set the recovery time. Finally, enabling the jitter effect and the recovery time are now accessible through the UI. Special thanks to SpiceWare of AtariAge for the initial idea and implementation. * Fixed bug with 'Medieval Mayhem' ROMs; the paddle range was set too low, and as a result the number of players couldn't be selected. * Fixed bug when using more than two input controllers with the same name; each controller after the second one was named the same as the second one. This caused the joystick mappings to be lost, since there was only information about two controllers being saved. * Indirectly fixed issues with Stelladaptor/2600-daptor devices and paddles having too large of a deadzone in Linux. Currently, this involves running an external application to set the deadzone, since SDL2 does not yet expose this information. The program is called 'evdev-joystick', and will be released separately from Stella. * Updated internal ROM properties database to ROM-Hunter version 11 (thanks go to RomHunter for his tireless research in this area). Related to this, updated the snapshot collection. 4.6.7 to 4.7: (January 25, 2016) * Improved paddle emulation in several ways: - Added ability to specify the maximum range of movement for paddles when using a mouse or digital device to emulate the paddle. This is useful since on a real console most paddle games use very little of the paddle range, and could result in moving the mouse onscreen with nothing appearing to happen (when in effect it was as if you turned a real paddle all the way to the end of the range). This eliminates issues in (for example) Kaboom, where there was a huge 'deadzone' when moving to the left. All applicable ROMS in the internal database have been updated. - The range for paddle emulation now takes an integer from 1 - 20, indicating how much to scale movement (ie, how fast the onscreen paddle will move when you move the mouse). The movement itself is now also smoother than before. * Fixed bug in 'Score mode' in TIA emulation; the TIA object colours were correct, but the associated priority was sometimes incorrect. * Fixed bug in ROM launcher; selecting 'Options -> Game Properties' after loading a ROM would always point to the last opened ROM, not to the one currently selected. * Fixed bug in storing ROM properties; in some cases, a copy of the ROM properties was being stored in the external file when it was exactly the same as the internal entry. * Added 'CV+' bankswitching scheme, developed by myself and LS_Dracon (of AtariAge). This scheme contains RAM like the CV scheme, and also switchable 2K ROM segments by writing to $3D. * Added more C++11 updates all over the codebase, and ran Stella through Coverity for the first time. I'm proud to say that Stella now has a 0.00 defect rate! 4.6.6 to 4.6.7: (October 28, 2015) * Fixed bug when using real paddles plugged into a Stelladaptor 2600-daptor device; the movement was very erratic. * Fixed small logic error in 'MDM' bankswitching scheme. 4.6.5 to 4.6.6: (October 11, 2015) * Added 'Alt/Cmd + j' shortcut key and 'tv.jitter' commandline argument to toggle the TV scanline jittering emulation added in the last release. Also, this jittering now defaults to off. * Fixed bug in 'MDM' bankswitch scheme; bankswitching wasn't being done under certain circumstances. 4.6.1 to 4.6.5: (September 26, 2015) * Added mappable events for toggling TV color/BW, left difficulty A/B and right difficulty A/B. This means that one key, joystick button, etc. can be used to toggle each event. Thanks to Buzbard of AtariAge for the suggestion. * Added ability to edit values in more widgets in the debugger. For now, this applies mainly to the various decimal and binary fields. More widgets will be made editable in future releases. * The TIA now emulates the jitter that occurs when scanline counts are not consistent frame-over-frame. Also, the DPC+ scheme now emulates jitter that can occur when using its Fractional Datafetchers if the DFxFRACINC registers are not re-initialized every frame. Special thanks to SpiceWare for this implementation. * Tweaked 'MDM' scheme autodetection to detect that the identification string can be in either bank 0 or bank 1. * Changed 'hidecursor' commandline argument (and associated UI item) to 'cursor'. The new argument allows to set mouse cursor visibility separately for both UI and emulation modes. * Fixed snapshot bug most noticeable in MacOSX, where taking a snapshot of a TIA image sometimes left parts of the UI onscreen (and in the resulting picture). * Fixed memory leak; the game console wasn't being closed after exiting a ROM. * For the Windows port: added an application icon for Stella in the Control Panel "Add/Remove Programs" list. * For the OSX port: Updated build scripts to be compatible with Xcode 7. * Updated included PNG library to latest stable version. 4.6 to 4.6.1: (April 22, 2015) * Fixed bug whereby text input could not be entered in certain widgets in the debugger. * Updated UNIX configure script to work with GCC 5.x compilers. 4.5 to 4.6: (March 21, 2015) * Finally fixed fullscreen rendering issues on some OpenGL implementations in Linux (mostly Intel-specific). Basically, the concept of 'dirty updates' has been removed; the window is now updated continuously. This may also fix issues some people were having with triple-buffering in Windows Direct3D, etc. * Fixed sound corruption that happened when running a ROM for the first time. This was most obvious under OSX, but occasionally happened on other systems too. * Reverted some minor C++11 features (std::regex and cbegin/cend iterators) in a few places, since otherwise GCC 4.9 is required to compile Stella, and it isn't available on many systems yet. These changes allow Stella to be built with GCC 4.8, which is present in the latest 'long term release' of Ubuntu. * Fixed error messages on state loading; sometimes multiple messages were being added together and displayed. * Fixed bug when running ROMs using AtariVox controllers; the app would crash upon exiting the ROM. * Snapshot functionality now works while the emulation is paused. * Certain textfields in the UI now have filtering enabled, preventing insertion of illegal characters. This will be extended throughout the code in future releases. * DataGridWidgets in the debugger now respond to keypad '+' and '-'. * Updated included PNG library to latest stable version. 4.2 to 4.5: (January 1, 2015) * The conversion to C++11 has begun :) From this point on, to build Stella you will need a C++11 compatible compiler (Visual Studio 2013, Clang 3.3, gcc 4.9, Xcode 6, etc). Eventually, this will bring more bug-free and (hopefully) faster code. * Fixed major bug with joysticks, where mapping was being lost on reset, the app would crash when plugging/unplugging certain sticks, etc. * Fixed major (but rare) crash that could occur when state files were zero'ed or corrupted. * Added dialog which shows the internal joystick database (all the joysticks that Stella knows about) and the ability to remove (currently unplugged) joysticks from this database. * Added preliminary support for 'WD' (Wickstead Design) bankswitching scheme, used for a previously unreleased prototype ROM. * Improved ZIP file handling, so that it now works as a normal filesystem does (it properly shows nested files and directories). * The debugger 'reset' command now does a complete system reset, instead of simply setting the PC to the reset vector address. * The 'listdelay' command now accepts a value of zero, indicating that list-skipping (jumping to a line in a list by keypress) is disabled. * The 'ctrlcombo' command now has a GUI item, allowing it to be changed from within the application. * Added 'Shift-Alt/Shift-Cmd s' keyboard shortcut, to enable continuous snapshot mode for each frame. This is really only useful if you save snapshots in 1x mode; using it in high-resolution mode is not recommended. Special thanks to SvOlli for the idea and code. * The minimum supported version for the OSX port is now OSX 10.7. Because of this, the 32-bit version is also discontinued, as 10.7 supports 64-bit Intel only apps. * Updated internal ROM properties database to ROM-Hunter version 10 (thanks go to RomHunter for his tireless research in this area). Related to this, updated the snapshot collection. * Updated included PNG library to latest stable version. 4.1.1 to 4.2: (October 28, 2014) * Text input from non-US keyboard layouts is now supported. Note that all text in Stella is still ASCII-only, but at least it can now be entered using a native layout. * Related to the text input changes, the debugger Alt-combo shortcuts have been changed; they now use the same key but with Control instead of Alt (Control-F for frame advance, etc). * Controllers are now detected dynamically by Stella. This means that you can plug/unplug joysticks/paddles/etc while Stella is running, and they will be added and removed automatically. Also fixed is a bug whereby sometimes custom joystick mappings weren't being saved. * The 'cpurandom' option is now broken down by register type, so you can selectively enable/disable randomization for each one. The default is to disable randomization for all registers. * Fixed 'MDM' scheme to trigger bankswitching on writes to hotspots (previously it only triggered on reads). Also, the scheme has been modified as originally designed by E. Blink; hotspots are now in the range $800-$BFF instead of $800-$FFF. * The OSX app-icon now includes 32x32 and 16x16 versions, so 'small' icons will be viewable in 'Finder', 'Get Info', etc. * The Linux port now uses an app-icon; this seems to be needed for some window managers. 4.1 to 4.1.1: (September 14, 2014) * Re-added 'uipalette' option due to popular demand (of at least one person :)). * Fixed bug in Windows port where pressing 'Alt' key combos resulted in an annoying system beep. Currently this is fixed by patching the SDL2 library and including a modified version with Stella. 4.0 to 4.1: (September 1, 2014) * Improved 'DASH' bankswitching scheme support; there is now a debugger tab for changing banks and viewing internal cart RAM, and autodetection is now implemented. * Added 'MDM' (Menu Driven Megacart) bankswitch scheme as described on AtariAge and originally developed by Edwin Blink. * Improved snapshot viewing in the ROM launcher; snapshots are now scaled to the available space, and can better accommodate sizes other than those generated by Stella itself. * Improved support on multi-monitor systems. Stella will now use the same monitor for fullscreen-windowed mode switches. Special thanks to Magnus Lind for patches that added this functionality. * Removed the 'bank' command from the debugger prompt, as it only worked (inconsistently) with certain bankswitch types. The bankswitch UI should now be used to query/set bank state. * Fixed bug in disassembly output; instructions at $F000 were never being highlighted during execution. * The UNIX configure script now supports newer versions of Hurd. Special thanks to Stephen Kitt for the patch. 3.9.3 to 4.0: (July 1, 2014) * Ported Stella to SDL2, which brings many new features. Among the largest improvements is native hardware acceleration support for Windows (Direct3D) and Linux/OSX (OpenGL). It is also now possible to port Stella to iOS and Android devices using OpenGLES. Hardware acceleration is now required, which means up-to-date drivers are needed. Software rendering is still present, but is somewhat unoptimized and unsupported going forward. * Fullscreen video modes now use the desktop resolution. Switching to fullscreen and back to windowed mode no longer rearranges icons on your desktop. * TIA TV effects are now available in all video modes, since hardware acceleration is a requirement. * Added a much more detailed view of cart extended RAM to a new debugger tab. Special thanks to SpiceWare for this implementation. * Added preliminary support for 'DASH' bankswitching scheme by A. Davie. * The AtariVox and SaveKey controllers now have the ability in the debugger to completely erase the virtual EEPROM data. * Added 'savesnap' debugger prompt command, and also associated context menu item to the debugger TIA output area. This saves the current TIA image to a PNG file. * Added 'hidecursor' commandline option, which allows to completely disable showing the mouse cursor (useful on systems that don't have a mouse). * Removed 'uipalette' option, as the original palette is no longer supported. * Updated included PNG library to latest stable version. 3.9.2 to 3.9.3: (January 20, 2014) * Added bankswitch schemes BF, BFSC, DF, DFSC and 4KSC, thanks to RevEng and CPUWIZ of AtariAge. * Updated ROM properties for several ROMs, thanks to Omegamatrix of AtariAge. * Fixed program crash when specifying a bankswitch type that Stella didn't recognize; an error message is now displayed. 3.9.1 to 3.9.2: (August 31, 2013) * Improved parsing of the DASM lst file for the debugger disassembly; it sometimes missed constant declarations. * Changed 'usemouse' argument from a true/false option to accept 'always', 'analog' and 'never'. This allows to use the mouse as a controller under more specific circumstances. The default is 'analog', which means the mouse is only used to emulate analog-like devices (paddles, trackball, etc). * Added ability to use bold fonts within the debugger window, which can be set with the 'dbg.fontstyle' commandline argument as well as in the debugger UI Settings dialog. This is useful for those that find the current font too narrow. * Renamed 'debuggerres' argument to 'dbg.res'. All future debugger- specific options will start with 'dbg.'. * The TIA 'zoom' area in the debugger now supports scrolling the mouse wheel (currently up/down only, as I don't have a sideways scrolling mouse to test with). 3.9 to 3.9.1: (August 21, 2013) * Note: because of TIA/6502 changes, the state file format has changed again, and old state files will not work with this release. * Several bugfixes and improvements to the debugger: - Improved display of debugger when using larger video modes. There are now three font sizes, which are automatically selected when the debugger is sized accordingly. When using larger fonts, the extra space is now used more efficiently. - Fixed bug in disassembly when the mirror used for the current PC didn't match the mirror for the current bank. In this case, the disassembler became confused and didn't properly track the PC address. - Fixed bug in display of current TIA frame number in the UI; depending on how breakpoints were set, it was sometimes off by one. - Fixed RAM widget Search/Compare textboxes; entering any data and then pressing 'Enter' / clicking 'OK' locked the UI until exiting and re-entering the debugger. - Changed display for various TIA position counters to decimal (from hex) in the TIA tab. Related to this, all data input widgets in the UI now have the ability to enter binary, decimal or hex values by using the proper leading character (\, #, $, respectively). - Added 'INTIM Clks' to the 'I/O' tab. which shows the number of clocks between each 'step' of the INTIM timer. - Added ability to modify 'tiadriven' commandline argument to the 'TIA' tab, and 'ramrandom' to the 'I/O' tab. These options were available for quite some time, but they weren't exposed in the UI. - Added 'cpurandom' commandline argument, and associated UI item to the 'I/O' tab. This works similar to 'ramrandom', and randomizes the contents of the CPU registers on ROM startup. - Added 'uhex' debugger prompt command, which toggles all hexadecimal display between upper/lower case. This setting is also saved in the settings file as argument 'dbg.uhex'. - Removed 'loadsym' command from the debugger prompt, since the DASM symbol file is always loaded anyway, making the command redundant. Related to this, fixed loading symbols with ###.name convention; the leading number is now stripped. - Added support for DASM lst files (created with the -l option). For now, the contents are only partially used, to detect constants vs. symbolic addresses in the symbol file. Eventually, further information from the lst file may be used. - The GRPx and PFx registers in the TIA output now show inactive background pixels as either blanked or with the underlying object colour, instead of always being black. This gives a more accurate representation of how the registers are actually drawn onscreen. Thanks to Tjoppen of AtariAge for this idea and sample code. - The 'Source Address' locations for the CPU registers now show labels where appropriate. * Renamed 'Override properties' dialog (accessible from the ROM launcher by a right-mouse-button click) to 'Power-on options', with the following new options: - Set start-up state for both joysticks as well as console select/ reset buttons. Related to this, added 'holdjoy01' and 'holdjoy1' commandline arguments, and removed 'holdbutton0' argument. - The ability to load the ROM directly from this dialog, after changing any settings, and also to start in the debugger. - Added more detailed information as to how to use this functionality to the UI. - Buttons held down are reset approx. 0.5 seconds after starting the ROM, to simulate pressing and releasing the buttons on a real console. * Fixed bug when using event remapping; changes were being saved only when launching a ROM from the launcher, not in standalone mode. * Improved bankswitch autodetection for newer EF and EFSC ROMs generated by batari Basic, thanks to RevEng of AtariAge. * Added properties database info for "Princess Rescue" ROM. * For the Linux/UNIX port: - Fixed bug whereby a maximize button was always present in the window title bar. Stella could not be expanded in this way, so the button was removed. - Added Startup notification protocol patch to the .desktop file from Dan Fandrich. * Updated included PNG library to latest stable version. 3.8.1 to 3.9: (June 27, 2013) * Greatly extended functionality of the debugger disassembly: - There is now a new tab which lists information specific to the cartridge bankswitching scheme in use. This includes the ability to modify internal state even for esoteric ROMs which don't follow the standard layout of 4K per bank. - The debugger now generates DASM-compatible disassembled code, which can be saved to an external file. This disassembly is based on both a static and runtime analysis, and is extremely accurate. It also automatically differentiates between CODE/PGFX/GFX/DATA/ROW areas, whereas normal Distella only differentiates between CODE/GFX/ROW. For now, only single-bank (4K and smaller) ROMs are supported; support for multi-bank ROMs will come in a future release. - The disassembly now recognizes various TIA/RIOT read/write mirrors, and marks them as such (for example, INPT4|$30 instead of INPT4 for address $3C). Special thanks to Omegamatrix for sample code and idea for this feature. - ROMS less than 2K in size (so called 'Sub2K' ROMs) now show only the actual data in the binary. This means, for example, that a 256 byte ROM will show only 256 bytes in the disassembly, instead of padding duplicated data to 2K boundary. - Fixed bug when entering patched bytes; the current number base wasn't being used. - Fixed labelling in ROW directives; it wasn't accurately setting a label in the case where it occurred in the middle of the data. - Added a new dialog for changing Distella settings, located by right-clicking the disassembly code. - The commandline option 'dis.resolvedata' has been renamed to 'dis.resolve', with new usage (see manual for further details). * Fixed regression in handling ZIP files (as compared to version 3.7.5) created with newer versions of the ZIP program. Related to this, added better error messages for invalid/missing/unreadable ROM files. * Added 'snapname' commandline argument and associated UI item, for specifying whether snapshots should be saved using either the internal ROM database name or the actual ROM filename. This feature was present in older releases of Stella, and due to popular demand it's now back again. Related to this, added a new dialog specifically for the numerous snapshot-related items. * Fixed bug in Linux/OSX versions when starting Stella for the first time; it was previously creating mislabeled directories to store settings, snapshots, etc. * Fixed redundant "New console created" message when entering the same ROM multiple times from the ROM launcher. * Updated profile database for "BasketBall" ROMs; the joysticks are now swapped by default, which allows one and two-player games to work correctly. * SuperCharger/AR ROMs now ignore the 'ramrandom' setting, and start with RAM containing all zeroes. This seems to fix issues with Dragonstomper always starting in exactly the same state. * Fixed issue when debugging CompuMate ROMs; keystrokes entered while debugging would be interpreted as typing on the CompuMate keyboard. * Changed colour of the 'current PC indicator' in the debugger to match the one used for line selection. This makes it easier to see for those with problems seeing lighter colours. * Improved functionality of the various pop-up dialogs and context menus in the UI; they can now be navigated more fully by the keyboard and mouse. * Updated internal ROM properties database to ROM-Hunter version 9 (thanks go to RomHunter for his tireless research in this area). Related to this, updated the snapshot collection. * Updated included PNG and ZLIB libraries to latest stable version. 3.8 to 3.8.1: (March 3, 2013) * Added support for TIA RSYNC writes, thanks to Omegamatrix of AtariAge. This allows the recently released "Extra Terrestrials" ROM to run, as well as improving emulation of "Fatal Run" and several other test ROMs. * Fixed typo in TIA HMOVE writes, thanks to Thomas Jentzsch. This fixes the constant collision issues in "Kool-Aid Man", and several other homebrew ROMs. * Fixed sound issues on OSX PPC machines (all sound was in little-endian format, but PPC is big-endian). * The OSX DMG archive now contains proper modification dates. 3.7.5 to 3.8: (February 21, 2013) * Huge changes to the sound system: - The sound code now uses 16-bit signed samples instead of 8-bit unsigned samples, making it more compatible with a wider variety of systems. - Improved sound output for several ROMs, including "Space Rocks" (the 'heartbeat' sound can now be clearly heard). - The 'volume clipping' option has been removed, since in 16-bit mode it's no longer needed. - The 'Tia freq' option has been removed. - Selecting more common sample rates (other than 31400) now works much better, but there are still a few ROMS (like Quadrun) where 31400Hz still works best. * Many changes to handling ZIP archives: - Files in multiple levels are now recognized. This fixes issues in Windows where such files couldn't be loaded at all, and in all systems where ROMs with the same name (but in different directories) weren't being recognized. - ZIP contents are now handled more intelligently. Archives containing only one ROM are automatically loaded, whereas those with multiple files are treated as directories. - Opening an archive from the commandline now works as in the UI, where opening a multi-ROM archive will pop up the UI and show the archive contents (as a directory). - The ZIP code behind the scenes is now much faster by making use of caching (the old code was actually from 1998!). - This new 'archive' infrastructure may eventually lead to 7-Zip support, as well as 'virtual' formats (such as showing the list of files for 2in1/4in1/8in1/etc within the UI). * Improved bankswitch autodetection for FA2 ROMs; 29K and 32K versions (meant for Harmony cart) are now recognized. * Improved bankswitch autodetection for X07 ROMs (although there's only two known ROMs in existence, so the detection probably isn't robust). * Tweaked bankswitch autodetection for the 0840, F8 and FE schemes; several homebrews that didn't run before now work correctly. * Fixed regression in RIOT INTIM reads; at least one known ROM (Mr. Roboto Berzerk hack) wasn't working properly. * Fixed bug in the debugger with RIOT INTIM/TIMINT display; reads were being done multiple times, changing the state of the registers and resulting in incorrect emulation. * Worked around bug in debugger disassembly of zero-page RAM; for now, the resolving of address vs. data sections is turned off in such a case. This fixes lockups in 'Meltdown' ROM. * Added support for different directories for saving/loading PNG files. These are set with the 'snapsavedir' and 'snaploaddir' commandline arguments (which replace the old 'snapdir'), and are also available within the UI. * Changed 'eepromdir' commandline argument to 'nvramdir', and changed the default location to BASEDIR/nvram (where BASEDIR depends on your OS). This means all your EEPROM and Flash files will have to be manually moved to this new directory. This affects developers, and those people playing ROMs with AtariVox/SaveKey support as well as the newer 'Star Castle' FA2 ROMs. * Updated included PNG and ZLIB libraries to latest stable version. 3.7.4 to 3.7.5: (December 22, 2012) * Improved regressions in PAL format autodetection, introduced in the past several releases. * Fixed crash when loading invalid PNG files in ROM browser. * Snapshots generated by Stella now include more informative info, such as the build number, platform architecture, TV effects in use, etc. 3.7.3 to 3.7.4: (October 31, 2012) * Fixed screen blanking regression in 'Video Chess', and improved behaviour of ROMs that don't use VSYNC. 3.7.2 to 3.7.3: (October 26, 2012) * Note: because of TIA/RIOT changes, the state file format has changed again, and old state files will not work with this release. * Improved handling of 'illegal' VSYNC signals, which sometimes created 'short' frames that caused massive flickering. Also improved related behaviour when VSYNC isn't used at all. * Improved sound generation with ROMs that have irregular scanline counts. This fixes many demo ROMs as well as Quadrun, where previously there would be 'gaps' in the sound output. * Improved emulation of RIOT chip, in particular the behaviour of reading from TIMINT. Also, D6 of the Interrupt Flag register is now properly set on active transition of the PA7 pin. * Fixed bug in DPC+ bankswitch scheme; the music in several ROMS wasn't playing correctly. * The ROM properties database now uses 'Auto' instead of 'Auto-select' everywhere. This makes for less typing when running from the commandline. * Updated included PNG library to latest stable version. 3.7.1 to 3.7.2: (June 10, 2012) * Fixed bug in handling filenames with the '~' character, as is used extensively by RomHunter rom-sets. 3.7 to 3.7.1: (June 8, 2012) * Note: because of TIA changes, the state file format has changed again, and old state files will not work with this release. * Improved TIA emulation with ROMs that have too few or too many scanlines; the output is now more accurate compared to a real TV. Special thanks to Omegamatrix of AtariAge for test ROMs in this area. * Modified hotkey for "Change console palette" (Control-f) to also change the display properties of the TIA. This allows you to switch between NTSC/PAL/SECAM (and variant) modes dynamically. Related to this, added Shift-Control-f key to step backwards through the available modes. * Added '64in1' and '128in1' multicart bankswitching schemes, which work the same as the 2in1/4in1/etc ones (Control-r switches to each consecutive game in the ROM). * Fixed several bugs in DPC+ bankswitching scheme, including ability to load and save state files. As well, ROMs now work correctly after console format autodetection. * Fixed bugs in handling relative filenames on the commandline, introduced in the last release. The new functionality should be much more robust. 3.6.1 to 3.7: (June 1, 2012) * Added Blargg TV effects, with presets for Composite, S-video, RGB, and badly adjusted TV, and well as a custom mode with full configurability of contrast, brightness, gamma, etc. Many keyboard shortcuts and commandline arguments were added to support this; see the documentation for a detailed explanation. These effects are OpenGL-only. Special thanks to Ian Bogost and the Georgia Tech Atari Team for the preliminary implementation. * Updated the CompuMate keyboard handler to recognize more keys on an actual keyboard, instead of having to remember the weird combinations used on the original CompuMate keyboard (although those original keys will continue to work). Related to this, fixed bug whereby 'ghost keys' would be detected by the CompuMate, particularly after pressing 'Enter' to start a game from the ROM launcher. * Added emulation for MindLink controller using the mouse; the 'Bionic Breakthrough' and 'Telepathy' ROMs now work. * Updated FA2 bankswitch scheme (Star Castle) to emulate load/save high score functionality to the Harmony cart flash RAM. * Added ability for ROM launcher to 'descend' into ZIP files when it contains more than one ROM file. This means you no longer have to unzip a multi-file archive before using each ROM. Thanks go to Roland Schabenberger (webOS maintainer) for this idea and sample code. * Several improvements to the debugger/disassembler: - The 'resolvedata', 'showaddr' and 'gfxformat' commandline arguments are renamed to start with 'dis', indicating that they're used with the built-in disassembler. - Zero-page code addresses no longer have their high-byte truncated, and system equates (TIA and I/O registers) are now properly marked as such. - The Distella '-r' option (Relocate calls out of address range) is no longer the default, resulting in output more consistent with normal usage of Distella. Related to this, added the '-dis.relocate' commandline argument (and associated UI item) to toggle this dynamically. * Fixed bug in EFSC bankswitch scheme state saving; the Superchip RAM wasn't actually being loaded and saved to state files. * Improved speed of loading and saving state files, as well as slightly reducing their size. Because of this, old state files will not work with this release. * Replaced commandline argument 'uselauncher' with 'exitlauncher'. The new option specifies the behaviour of the ROM launcher when exiting a ROM (always exit to launcher, or only when the launcher was actually used). This setting can now be changed in the GUI. * Several updates to the internal properties database: - 'Juno First' ROMs now use an AtariVox/SaveKey when possible - 'Astroblast' ROMs now use the paddles by default - 'Star Castle 2600' ROMs added * Changed key-combo for enabling TIA objects and collisions to be toggled on and off with the Alt-period and Shift-Alt-period respectively (instead of having two separate keys to turn them on and off). * When working on the commandline, relative filenames are now correctly handled (current working directory is used). * The Windows 98/ME/2000 builds have been discontinued, due to code and features that are only available on Windows XP/SP3 and later. * Updated included PNG library to latest stable version. 3.6 to 3.6.1: (March 30, 2012) * Extended FA2 bankswitch scheme to handle 28K ROMs (in addition to the previously supported 24K ROMs). 3.5.5 to 3.6: (March 16, 2012) * Added support for 2600-daptor II device, including native support for 7800 controllers, BoosterGrip and Keypad controllers. Special thanks go to Tom Hafner for a complimentary test sample of this device, and also for donating a BoosterGrip controller. * Added ability to dynamically swap the port order of Stelladaptor/ 2600-daptor devices with the 'Control-1' key combo (useful if you have only one 2600-daptor and want to use it as a left port normally, but as a right port for Star Raiders, etc). * Added CompuMate bankswitching/controller support to the emulation core; the Spectravideo CompuMate ROMs (NTSC and PAL) now work. Frequently used keys on the CompuMate are directly mapped to your keyboard (ie, Func-Space for backspace is mapped to Backspace, etc). Loading/saving from the cassette player is not yet supported, and will come in a future release. * Fixed bug in BoosterGrip controller emulation; the functionality of the booster and trigger buttons was reversed. Related to this, renamed these actions in the Event Mapping dialog to be more clear. * Reverted to SDL 1.2.14 for the Windows 98/2k release, since SDL 1.2.15 isn't supported in that environment. * Updated included PNG library to latest stable version. 3.5 to 3.5.5: (February 4, 2012) * Due to changes in the debugger, old state files will not work with this release. * Fixed bug in sound restructuring introduced in the last release; in some cases, there could be some sound 'crackling' when starting a ROM after at least one ROM had already been loaded. * Several significant improvements to the debugger I/O tab: - added controller input widgets for many of the built-in controllers, allowing to control joysticks, paddles, etc from within the debugger. - added ability to modify the SWCHB/SWBCNT port B registers. - added ability to view TIA INPTx and VBLANK latch/dump bits. * Reworked 'mcontrol' argument, and added ability to map the mouse axes separately for paddles 0-3 or driving controllers 0-1. In such modes, the left mouse button is tied to the x-axis, and the right button is tied to the y-axis. * Mouse 'specific-axis' mode is now saved per-ROM, meaning that each ROM can have separate settings. For example, this allows one ROM to use paddles 0 and 1, while another can use paddles 0 and 2, etc. * The key-combo for switching the mouse between controller modes is now 'Control-0' (Control-1,2,3 have been removed). This switches between all possible modes for the current virtual controllers. * Fixed bug in 'Fixed Debug Colors' mode; under certain circumstances, playfield graphics could be coloured as being player graphics. * Fixed bug in PAL color-loss setting in Video Settings; changing the settings wouldn't take effect until the ROM was reloaded. * Fixed bugs with cheatcode handling; loading a ROM with a cheat disabled would sometimes trash the emulation. More work is required in this area, including the ability to create more advanced types of cheats. * Updated ROM properties database for all Sega Genesis controller compatible ROMs. Also, the mouse can now emulate a Genesis controller, with the left/right buttons mapped to buttons B and C, respectively. * Added 'FA2' bankswitch scheme, thanks to code from Chris D. Walton. This scheme will be used in an upcoming 'Star Castle' ROM. * Updated internal ROM properties database to ROM-Hunter version 7 (thanks go to RomHunter for his tireless research in this area). * Added several PERL tools to help in automation of analyzing RomHunter ROM set releases. * Fixed compile issues in Irix when using the default compiler instead of gcc. Thanks go to Rainer M. Canavan for this code. * Updated included PNG library to latest stable version. 3.4.1 to 3.5: (December 29, 2011) * Stella is now DonationWare! Please see the DonationWare link on the main webpage for more information. * Added several improvements to the joystick management code. Joystick event mapping is now saved per device, meaning that if you map events to a certain joystick device, remove the device and then later insert it again, Stella will remember the original mapping. * The total number of joysticks present and their associated properties (number of axes, buttons and hats) is now dynamic. That is, there's no longer a hard-coded limit on the number of joysticks that Stella can use, or the number of buttons, etc that it contains. This fixes a serious bug with PS3 controllers with 27 buttons, whereby adding a mapping for joystick 0 would inadvertantly change settings for joystick 1, and could potentially lead to a program crash. * Added 'mcontrol' commandline argument, which can specify to use each mouse axis as a separate paddle. The old (and default) behaviour can be activated by setting this argument to 'auto'. Related to this, removed redundant 'usemouse' argument. * Huge restructuring of the OpenGL code, making it compatible with OpenGL 2.x+ features (such as vertex buffer objects), while at the same time keeping compatibility with OpenGL 1.5 / OpenGL ES. Because of the required changes, TV effects were removed (they will be added again for the next release). * Improvements to audio handling, particularly for certain cases of Windows, ATI video cards, and OpenGL mode. The sound device is now opened only once when Stella starts, and is paused between loading different ROMs. This fixes a problem whereby sound could possibly not be functional after loading the first ROM. Related to this, removed the 'audiofirst' commandline argument as it's now redundant. * Fixed bug with displaying the ROM launcher in Windows XP; the initial load was sometimes taking up to 30 seconds to complete. * Added logging facility, whereby the output of the application is available within Stella itself. This can still be printed to the console, or also saved to a file. Add the 'loglevel' and 'logtoconsole' commandline arguments which control these settings, and removed the 'showinfo' argument as it's now redundant. * Updated DPC+ bankswitching scheme to latest code provided by SpiceWare. * Added MAMCR handling to the Thumb ARM emulation code. Note that MAMCR isn't actually emulated, it is just ignored for now. This fixes a bug whereby accessing MAMCR would crash the ARM emulation. * Added 'thumb.trapfatal' commandline argument, which causes the Thumb ARM emulation to either trap on a fatal error (throw an exception to the debugger and exit emulation) or simply log the error and continue. This should normally always be enabled, but can be disabled by developers for testing reasons. * Updated default snapshot directory to be much saner and easier to find. For most systems, it now defaults to the users 'Desktop'. Note that the commandline argument has changed to 'snapdir'. * The debugger 'print' command now indicates "special" addresses if they are read-only (R), write-only (W) or read-write (R/W). * Fixed a bug where scrolling the mouse-wheel in certain debugger UI items would cause the program to crash; scrolling now works as expected. * Fixed minor display issue in the debugger RAM area; some addresses were being displayed as '...'. * Fixed compile issues in the latest versions of Ubuntu and Debian, and fixed UNIX desktop file so that Stella will launch with a ROM when selected from its icon. Thanks go to Stephen Kitt for this code. * Updated included PNG library to latest stable version. * Updated the credits list in the documentation, listing people that have donated hardware to the Stella team. 3.4 to 3.4.1: (June 11, 2011) * Re-enabled 'grabmouse' commandline argument and associated functionality with the following changes: - it is changed in the "Input Settings' UI, not in 'Video Settings' - it only has meaning while in emulation mode - it is enabled by default * Fixed bug with emulation of paddles using the mouse most evident in Warlords; movement was being filtered out if the mouse was moved too fast. There's still more work required in this area, however. * Fixed bug with analog axes on gamepad devices, whereby jittering in these axes would override input from digital axis, hat or keyboard input. * Fixed bug when switching to the debugger and back again would sometimes cause an extra mouse motion event (which would cause the emulation to think the mouse was moved and move the player accordingly). * Tweaked bankswitch autodetection code for 4A50 bankswitching; several more test ROMs are automatically detected. * The 'saverom' debugger command now saves ROMs in your home directory by default if you don't specify a valid path. This fixes a bug whereby ROMs were saved in strange locations and couldn't later be found. * Fixed bug in automatically executing the debugger 'autoexec.stella' file; any commands it contained weren't actually being executed. * Zero-byte ROMs are no longer loaded and mis-detected as Supercharger images. 3.3 to 3.4: (May. 29, 2011) * Many improvements to input handling, particularly with the mouse and paddles: - The mouse can now be used to emulate a joystick, booster-grip or driving controller. - The mouse now controls only one device at a time (1 of 4 paddles, 1 of 2 joysticks, etc), instead of devices from both virtual ports. - The sensitivity for digital and mouse input (for paddles) can now be set separately with the 'dsense' and 'msense' commandline arguments, and from within the Input Settings UI. * Added support for the 2600-daptor device (2600-daptor.com), which is similar to a Stelladaptor but improves handling of paddles. Thanks go to Tom Hafner for a complimentary test sample of this device. * Added new controller types 'Paddles_IAxis', 'Paddles_IDir', and 'Paddles_IAxDr', which invert the paddle axis, direction, and axis+direction, respectively. These are used for certain ROMs that have the axis or direction inverted from normal (for example, using the paddles causes on onscreen object to move up and down vs. left and right). All applicable ROMs in the internal database have been updated. * Added preliminary support for emulating ARM code to the DPC+ bankswitching scheme (thanks to Batari). Related to this, fatal errors in the DPC+ ARM code are now caught and shown in the debugger. * Updated internal ROM properties database to ROM-Hunter version 6 (thanks go to RomHunter for his tireless research in this area). * The ROM audit dialog now automatically selects the current directory in the ROM launcher, and reloads the directory after the audit is complete. * Removed the 'grabmouse' functionality; the mouse is now always grabbed while playing a game, and released otherwise. * Updated built-in version of the PNG library to the latest version. 3.2.2 to 3.3: (November 12, 2010) * Added the following Distella 'directives', which are used to override and specifically tell the debugger how to treat address space (CODE, GFX, PGFX, DATA, ROW). See the debugger documentation for more information. * Disassembly from the debugger is now tracked by the emulation core, and accented by the built-in Distella code. Basically, the emulation core knows when an address is referenced as code, making for very accurate disassembled output. Related to this, the emulation core now tracks accesses to GRPx and PFx registers, automatically marking the addresses as GFX or PGFX sections. This will be improved in future releases, as there are many ways to store data in the graphics registers. * Improved output of graphics output in the disassembler, by marking such addresses with a bitmap of the data they represent. This allows player graphics (GFX directive) and playfield graphics (PGFX directive) to really stand out in the disassembly. Related to this, added ability to edit such graphics in either binary or hexidecimal. * Added preliminary support for Distella configuration files. Much more work is required in this area, since Stella now contains directives that don't yet exist in the standalone Distella program. Configuration files are automatically loaded, and debugger commands now exist to load and save configuration directives directly from the debugger. * Added the following commands to the debugger prompt: - clearconfig, listconfig, loadconfig, saveconfig (used for Distella configuration files) - code, data, gfx, pgfx, row (directives used to override automatic disassembly types) - jump (jumps to a specific address in the disassembly) - type (gives detailed info for disassembly type of an address) * The debugger prompt commands 'trap', 'trapread' and 'trapwrite' now accept a range of addresses as well as a single address. * Added 'data source' address output for the CPU SP/A/X/Y registers. This is useful for quickly seeing what an operand address resolves into with various load commands. * Many commands in the debugger prompt are now case-insensitive; further improvements will be made in future releases. * Many improvements to the built-in Distella disassembler. When passing a relative branch or jump, data is now disassembled as code only if the emulation core hasn't detected it as data. Such 'preliminary' code is marked with a '*' in the disassembler, indicating that it is tentative code, and hasn't actually been executed yet. This allows to quickly see possible code paths, and at the same time eliminate disassembly of addresses that are never used as code sections. * Program counter/instruction addresses can now be toggled in the disassembly. * Disassembled instructions involving relative branches now show only one byte for the operand, not two bytes. * Fixed bug in several text input fields, whereby binary data couldn't be input (a '\' was required, but the character was blocked). * Fixed issues with PAL ROMs on screenmodes smaller than a PAL ROM would require. In this case, the image is centered and clipped to the screen resolution. This prevents the message "PAL ROM not supported" from appearing. * Fixed bug in fullscreen OpenGL mode when using ATI video cards; the desktop background was 'bleeding through', resulting in a very annoying flickering. * Fixed crashes when opening windows larger than the desktop resolution in fullscreen mode; this is now allowed only in windowed mode. * Application window centering now also works when switching between video modes, not just when starting the application. * Added support for building a Windows version compatible with Windows 98 and 2000 (compiled with Visual Studio 2005). Testing is very limited, since I no longer have access to these systems. * Fixed build issues for Innosetup in Windows XP. * Fixed bug in OSX version where the name of the application wasn't being shown in Activity Monitor. * State files from older versions will no longer work in this release, because of the extensive changes to the debugger and disassembler. 3.2.1 to 3.2.2: (September 17, 2010) * Fixed bug with window centering; if enabled and the the window was larger than the desktop, the window would be moved offscreen. 3.2 to 3.2.1: (August 25, 2010) * Improved behaviour of joystick 'hat' movement. This should fix bugs most visible in Yars' Revenge. * Fixed bug in debugger rewind states; bankswitching wasn't being performed during the rewind. Related to this, fixed a similar issue with the debugger 'loadstate' and 'savestate' commands. * Added game properties info and snapshot for the newly released 'Halo 2600' ROM. 3.1.2 to 3.2: (August 20, 2010) * NOTE: because of the many event-related changes in this release, all event mapping should be reset to defaults after starting Stella for the first time. As well, because of other internal changes, older save-state files are no longer valid. * Many improvements to joystick handling code, particularly for analog axes. Navigating the UI should be much smoother now, and remapping events to analog axes should be less 'twitchy'. * Added ability to assign and remap 'combo' events in emulation mode. Combo events are basically a sequence of normal events (up to 8) that are generated from a single event (ie, one button on a joystick could generate up to 8 events). Updated Input Settings UI to access and modify these events. * Default mappings are now available in UI and emulation mode for the first 'hat' detected on a joystick/gamepad. Related to this, a hat now works exactly like an axis in UI mode (holding down a direction continues that direction until the hat is released/centered). * Several major improvements to the debugger: - the disassembler can now process multiple entry points, and caches entry points as they're encountered (ie, the disassembly isn't 'reset' each time a bank change occurs or you exit and re-enter the debugger) - preliminary support for disassembling from zero-page RAM - re-added ability to change banks with the 'bank' debugger prompt command and within the ROM disassembly UI - user labels in disassembly are now supported again - 'runto' command is now case-insensitive, and shows a progressbar while searching through the disassembly - the debugger window can be resized between ROM loads (previously, the app had to be restarted) - fixed bug in Distella disassembler output, where it sometimes generated addresses above $FFFF - a vertical line separates the disassembly from the raw bytes * Fixed behaviour of SWCHB and SWBCNT; pins set to output now remember the values previously written. Some ROMs use this functionality for extra storage. Special thanks to Omegamatrix of AtariAge for advice and test ROMs in this area. * Fixed bug when reading from illegal TIA addresses; a Space Invaders hack was showing pink enemies instead of white ones. Again, special thanks to to Omegamatrix of AtariAge for advice and test ROMs in this area. * Fixed bug in handling INPT4/INPT5 latches from VBLANK; a least one ROM was working in Stella when it didn't on real hardware. * Added 'ramrandom' commandline argument, which is used to randomize all RAM in the system; otherwise, the RAM is zeroed. * Added 'finishing touches' to some of the UI descriptions, giving a better explanation of the functions. Related to this, certain options now show a message box explaining the option in further detail (particularly the ROM Audit mode). As well, when starting Stella for the first time, a prompt appears to select a ROM directory. * Fixed bugs in the ROM launcher when viewing certain PNG images not created by Stella. Related to this, the official PNG library is now included in the Stella codebase (version 1.4.3). Also added composite snapshots for those ROMs which consist of several games. Thanks go to Buzbard of AtariAge for these images. * Added several fixes for crashes on 'small' systems (those systems where the maximum resolution is less than 640x480). * Tweaked bankswitch autodetection for 0840, DPC+, E7 and UA schemes. * Improved F8 bankswitch autodetection for Yars Revenge in 8in1 ROM. * Updated DPC+ bankswitch scheme to latest specifications. * Snapshots taken in continuous snapshot mode are now timestamped, so older files are never overwritten. * Fixed a TIA segfault that could occur with certain ROMs. * The 'center' application window functionality can now be changed without having to restart the application. Related to this, mouse positioning bugs when using the Linux version in OpenGL mode with SDL 1.2.14 have been fixed. * Reworked the manual, dividing it into 'Getting Started' and 'Advanced Configuration' sections. It still contains the same info as before, but hopefully in a better organized way. * Updated Help dialog; it was showing incorrect info for some OSX shortcuts. * Updated OSX build script to not crash when a previous build is detected, and to properly handle filenames with spaces. * Updated included ZLib to latest release version (1.2.5). 3.1.1 to 3.1.2: (May 3, 2010) * Modified 'showinfo' command to accept levels of output, where increasingly larger numbers provide more debug output. Related to this, added UI item to modify 'showinfo'. * Updated DPC+ bankswitch scheme to latest specifications, including support for 32K ROMs with ARM code (the ARM code is ignored for now). * Fixed bug in saving patched ROMs using DPC and DPC+ bankswitch schemes; the saved image didn't actually include any changes made by the user. * Removed 'uselauncher' from the UI, since disabling it will remove the ROM launcher on all future runs, and not allow one to enable it again. It's still available from the commandline, for those that have a need for it. 3.1 to 3.1.1: (April 26, 2010) * Fixed program crash when using RIOT addresses and labels in the debugger console prompt. * Updated DPC+ bankswitch scheme to latest specifications. 3.0 to 3.1: (April 22, 2010) * Fixed a major bug with text drawing in software rendering mode. Switching between windowed and fullscreen mode while text was being shown could result in garbled text or even a program crash. * Fixed issues when using 'sleep' timing, whereby a lockup could occur when changing video modes, and/or Stella would consume more CPU time than was necessary. * Integrated Distella disassembler, completely replacing the previous disassembler. The entire infrastructure has not been completely ported yet. As a result, labels defined by the user or from a DASM symbol file aren't actually used in the disassembly, and almost all distella config options are disabled. These will be addressed in a future release. * Completely reworked the debugger cartridge interface, so that the disassembly is dynamic (ie, the debugger tracks when cart address space has changed, and automatically performs a re-disassembly). * All carts with extended RAM that differentiate between read and write ports now behave correctly when a read from the write port occurs. * Added more complete support for the more esoteric bankswitch schemes in the debugger. These schemes now support accurate disassembly and ROM patch functionality. Related to this, fixed a bug in disassembler view when a failure to patch a ROM still showed the (incorrect) patched results. * Added ability to disable TIA object collisions, independent of enabling/disabling the objects. Previously, one had to completely disable an object to avoid collisions, but now an object can be enabled (and seen) but still have its collisions disabled. These actions are tied to the same keys as the enable ones, except the 'Shift' key is also used. * Added preliminary support for 'DPC+' bankswitching scheme, thanks to Darrell Spice Jr and Fred Quimby. * Added '16in1' bankswitching scheme, which works with various ROMs labeled '128-in-1 ...' (the database has been updated for these). Related to this, switching between multicart ROMs for 2in1, 4in1, 8in1, 16in1 and 32in1 now shows a UI message indicating which ROM is active. * Reverted some of the TIA improvements with respect to 'starfield effect' as seen in "Cosmic Ark" and "Stay Frosty". The emulation is now more accurate as compared to the majority of consoles in use. * Added debugger pseudo-register '_rwport', which traps on a read from the write port. This differentiates from reads that are normally part of a write cycle (ie, it traps only on inadvertent reads). * Added 'resolvedata' commandline argument and associated UI item, used to set the "resolve data sections" config option in Distella (vs. treating all address space as code). * Added 'runtopc' debugger command, used to step until encountering the given program counter. This is also available in the ROM disassembly UI from the right-click context menu. * Added 'listfunctions' and 'delfunction' debugger commands to access/remove user-defined functions. Related to this, fixed a bug in 'function' command that could cause a program crash. * Added 'cls' debugger command, used to erase the text and history from the debugger prompt. * Removed the 'listwatches' and 'poke' debugger commands, as they were redundant. * Removed the 'loadlst' debugger command and the ability to use a DASM .lst file. This code was incomplete, and no longer fits with the recent disassembler improvements. Support for this may return in a future release. * Modified 'disasm' debugger command to accept a second argument indicating the number of lines to disassemble. * Improved tab-completion in the debugger prompt; it now completes on functions and pseudo-registers. * Added emulation of the "Sega Genesis" controller, with two buttons that are directly supported on a real system. * The ZLib library is now included in the core code, so Windows developers no longer have to track down the ZLIBWAPI archive. * Many changes to the MacOS X port, bringing it more in line with other systems: The application is now known as 'Stella' (instead of StellaOSX). Two versions are available: the first is a 32-bit Universal Binary for OSX 10.4 - 10.6, and the second is 32/64-bit Intel-only for OSX 10.6 (aka Snow Leopard). The Intel version is compiled with the very latest compiler (LLVM/Clang), resulting in better performance. The keyboard handling is changed to match other systems in terms of where the keys actually are on the keyboard (ie, the OSX Command key corresponds to Alt, and the OSX Control key corresponds to Control). The application menu has been cleaned up and simplified, and it now shows the correct shortcuts for menu items. The settings file is now (according to Apple standards) '~/Library/Preferences/net.sourceforge.Stella.plist'. The base directory (where all other Stella stuff is located) is now '~/Library/Application Support/Stella'. Because of these changes, all your settings will have to be entered again. * Added 'ctrlcombo' commandline argument, which toggles the use of the control key as a modifier key. This is useful if you want to press 'Control' and 'R' in a two player game, and not have the combination treated as 'Control-R' (which will issue a ROM reload). * Added 'usemouse' commandline argument and associated UI item. This toggles the use of the mouse as a controller of any type. * Added 'uimessages' commandline argument and associated UI item. This toggles showing of UI messages overlaid on the screen. Critical messages are still shown, though. * Added ability to take multiple snapshots in a given interval every x seconds. This is currently tied to the 'Alt-s' key and is not remappable (for now). The interval can be set with the 'ssinterval' commandline argument and within the UI, and defaults to 2. * Many changes to the FrameBuffer and UI code for 'smaller' systems. Stella will now scale correctly to small screens, down to 320x240 (which is the absolute lower limit supported). Related to this, added 'maxres' commandline argument, which is useful for developers testing on such systems. * The About dialog now shows the version of SDL in use, and the type of CPU the application is running on (i386, x86_64, etc). * Improved 'listrominfo' commandline argument to list all information from Stella's internal ROM database, including a heading. This output can be imported into a spreadsheet or database program. * Renamed 'tiafloat' commandline argument to 'tiadriven'. The emulation of the behaviour of floating TIA pins is also much more accurate. * Reworked state files so that they're associated with the cartridge type used, not the MD5sum of the ROM. This is useful for developers, since the same state file can now be loaded from different ROMs, as long as the cart type stays the same. This also fixes a bug where loading from a non-existent state file could cause Stella to crash. Because of these changes, old state files will no longer work. * Fixed bug in certain editable text fields, where pressing Return/Enter would disable any further input. 2.8.4 to 3.0: (September 11, 2009) * Huge updates to the TIA emulation system. Illegal HMOVEs are now handled correctly, resulting in improvements to many ROMs (thanks to Wilbert Pol for many ideas and code for these improvements). All HMOVE emulation 'cheats' were removed; the emulation is now cycle-exact in this area. * Improved emulation of the Cosmic Ark 'starfield effect', also used in Stay Frosty; the emulation now looks very accurate. * Many improvements to the normal TIA rendering code, fixing problems when disabling certain graphical objects (certain objects were being misdrawn when others were enabled/disabled). * Improved TIA collision handling in the non-displayable area of the screen; this fixes problems in RAMRacer ROM. * Improved TIA redraw problems/graphical garbage when ROMs generate many more scanlines than a real TV would allow; this fixes problems in Q-Bert and the recent Playaround demo. * Added 'Fixed Debug Colors' option similar to the no$26k emulator. This allows each graphical object to be drawn in a fixed color, more clearly showing how the objects interact. HMOVE blanks are also shown in a different color. The TIA now emulates a 7-color register model, allowing even shared objects to show different colors. This is toggled with the 'Alt Comma' key. * Related to 'Fixed Debug Colors', HMOVE blanks can now toggled during TIA display with the 'Alt-m' key. * Added rewind functionality to the debugger, where states are saved after each step/trace/scanline/frame advance. Pressing 'Alt-r' or clicking the new rewind button will undo up to 100 previous operations. * Added 'electron beam indicator' to the debugger TIA output. Basically, this is a visual pointer indicating the position of the electron gun when scanning the display. * Added ability to completely disable fullscreen mode, which fixes problems for some people where fullscreen mode was being entered even if it wasn't enabled. * Added '-joyallow4' commandline argument and associated UI item to allow all 4 directions to be pressed simultaneously on a joystick. * Improvements made to the ROM launcher: the backspace key now goes to the parent directory (this key can be remapped), and previously selected directories are now automatically selected. * Added support for 2IN1 bankswitching scheme, where two ROMs are present in one binary. Currently supported are 2, 4, 8, and 16K ROMs. * Added bankswitch support for the 6K version of Starpath/Supercharger ROMS. This allows the 6K version of Cubis to run. * Updated bankswitching schemes FASC and MB; they are now known as FA and F0, respectively. This naming brings Stella in line with other emulators and programming utilities. * Fixed editing of cheats in the Cheat Dialog; the old cheat wasn't being removed. 2.8.3 to 2.8.4: (July 4, 2009) * Fixed bug where Stella could lock up after running for ~71 minutes. Special thanks to Robert Tuccitto for bugtesting and feedback on this issue. * Updated UA bankswitch autodetection for Gingerbread Man ROM. * The smallest ROM that Stella can support is 64 bytes; this lower limit is now tested when loading Sub2K ROMs. 2.8.2 to 2.8.3: (June 25, 2009) * Fixed OpenGL bug which caused an immediate program crash if the available OpenGL version was less than 2.0. 2.8.1 to 2.8.2: (June 23, 2009) * Fixed OpenGL detection bug which could disable OpenGL support entirely if TV effects are not available (version < 2.0), when in fact only the effects should have been disabled. * The '\' character can now be entered in UI text fields again. Related to this, strings containing '\' are now properly loaded and saved to various config files. 2.8 to 2.8.1: (June 19, 2009) * NOTE: Windows users will have to reset their options or manually move their config folder in this release, since the location of the config files has changed. * Fixed OpenGL issue for some Windows users whereby the OpenGL TV effects weren't available, even if the available version of OpenGL was sufficient. Related to this, the OpenGL version found by Stella is now reported in the TV effects dialog. * Added fallback to software rendering when OpenGL rendering has been requested, but for whatever reason fails to initialize. * Added native support for 4in1, 8in1 and 32in1 multicart bankswitching schemes. When using these schemes, the 'Reload ROM' action (by default, Control-r) will switch between each game in the ROM. * Added bankswitch support for ROMs smaller than 2K in size. These will be treated as 2K ROMs natively, without having to manually 'pad' them to 2048 bytes. * Added preliminary suppport for autodetection of X07 bankswitching. * Tweaked PAL autodetection; it was marking some PAL ROMs as NTSC. * Changed default location for Stella config files in Windows to the users' APPDATA folder (for XP and Vista, this is '~/Application Data/Stella'). The '~' symbol now represents the users PROFILE/home directory, matching its usage in Linux and OSX. The ability to override this with 'basedir.txt' is still available, but not advised. * Changed '-exitlauncher' commandline argument to '-uselauncher'. This works as before except the launcher is never used at all if the option is set to false. * Fixed crash when launching Stella from the commandline and giving a directory name instead of a rom filename. 2.7.7 to 2.8: (June 9, 2009) * Added CRT simulation effects as described in the AtariAge posting 'CRT emulation for Stella'. For now, this requires OpenGL 2.0 or greater with support for GLSL (GL Shading Language). This code will be expanded on and optimized in future releases. * Adding editing of extended RAM in the debugger RAM UI. The RAM 'spreadsheet' now shows the entire address space of RAM in the system, in 128 byte increments. The first bank shown is zero-page, with the others following in consecutive order. The UI takes care of read vs. write port differences, so you don't have to worry about the offsets. For now, all SuperChip based ROMs (EFSC, F4SC, F6SC, F8SC) as well as 3E, CV, E7 and FASC are supported. * All ROMs which include SC extended RAM will now have memory erased if you attempt to read from the write port. Related to this, entering/exiting the debugger will no longer erase the extended RAM. * Patching of ROM for bankswitch types 0840, SB, UA and X07 is now implemented, but hasn't been extensively tested. * Visual improvements to the CPU register UI in the debugger; the SP/A/X/Y registers now have separate decimal and binary views. * Tweaked paddle control so that all positions are reachable in game 4 of Activision Casino in both NTSC and PAL versions. * SuperCharger/AR ROMs now start with a random value in the CPU accumulator. This should fix issues with Dragonstomper always starting in exactly the same state. * Auto-detection for '3F' bankswitching improved; several ROMs previously detected as 'F8' now work correctly. * Updated internal ROM properties database to ROM-Hunter version 5 (thanks go to RomHunter for his tireless research in this area). * Added '-exitlauncher' commandline argument and associated UI item, to specify what happens when you exit a ROM. Normally, exiting a ROM brings up the ROM launcher, but this can be disabled for those using an external frontend (in which case exiting a ROM also exits from Stella). * Re-added '-fastscbios' commandline argument, and added an associated UI item. When enabled, the SuperCharger load bars are now completely removed (and not just sped up as in previous releases). * The '-listrominfo' commandline argument now shows all ROM information built in to the internal database, taking into account any information in 'personal' stella.pro files. 2.7.6 to 2.7.7: (May 1, 2009) * Corrected emulation of CPU opcodes involving 'decimal' mode (ADC/RRA and SBC/ISB). Special thanks to SeaGtGruff and others on the Stella mailing list for in-depth discussion and creation of test ROMs. * Fixed bug in F4SC bankswitching mode; writes to bankswitch addresses weren't triggering a bank switch. * Changed internal sound frequency of Pitfall 2 from 15.75KHz to 20KHz, as this sounds much more authentic when compared to a real cartridge. 2.7.5 to 2.7.6: (April 14, 2009) * Added support for 'EF' bankswitching (Paul Slocum Homestar Runner), as well as auto-detection of this format. * Added support for 'EFSC' bankswitching, as well as auto-detection of this format. This is similar to the 'EF' scheme, but also includes 128 bytes SuperChip RAM. * Added autodetection for '0840' and 'SB' bankswitching formats. * Improved autodetection for 'UA' bankswitching format. * Fixed bug in selecting video modes larger than the current screen; the resulting video mode will now be the largest one available (previously it selected the smallest one available). * The currently selected CPU register now displays its value in decimal and binary (in addition to hex) in the debugger. 2.7.3 to 2.7.5: (Mar. 27, 2009) * After about 2 years, finally fixed the infamous 'red screen' issue when using ATI video cards in OpenGL mode in Windows. In the end, it was determined to be a bug in the ATI drivers. Special thanks go to Ant (http://aqfl.net) for bugtesting and constant feedback wrt this bug. * Fixed bug in TIA SCORE mode emulation when the Priority bit is also set. This fixes a very noticable graphical glitch in 'Swordquest Waterworld', as well as minor glitches in several other ROMs such as 'Space Shuttle'. * Treat spaces as normal characters in the ROM launcher. This means that ROMs with spaces can be located with quick selection (ie, typing characters will automatically jump to a ROM with that name, and typing 'space' won't cause the launcher to jump back to the top of the list). * The debugger window can now have a minimum height of 620 lines (previously the minimum was 690), but you lose access to the TIA 'RAM' bytes when using this resolution. This should allow it to work better on devices with small displays. 2.7.2 to 2.7.3: (Feb. 9, 2009) * Fixed rendering issues in software mode when using 24-bit colour depth. This isn't as fast as 16 or 32-bit modes, so you're recommended to use one of those whenever possible. * For the Win32 port: re-added ability to change the default location for storing Stella config files. To use this, simply create a file named 'basedir.txt' in the application directory containing the full path where all Stella-related items should be stored. * Tweaked the TIA info statistics overlay to be smaller while still including all relevant information. 2.7.1 to 2.7.2: (Jan. 27, 2009) * Fixed major bug in ROM Audit functionality; renaming ROMs would create files without an extension. 2.7 to 2.7.1: (Jan. 26, 2009) * Partial workaround for sound not working in OpenGL video mode in Windows with ATI video hardware. Sound will now work for the first ROM selected, but not for subsequent ones (you will have to quit and restart Stella for sound to work again). Related to this, added '-audiofirst' commandline argument, which initializes audio before video when emulating a ROM. Further work is required to completely fix this bug. * Fixed bug where volume wasn't being saved in 'Audio Settings' when started from the ROM launcher. * Fixed crash which sometimes occurred when viewing snapshots in the ROM Info viewer. * Allow setting window sizes for the ROM launcher and debugger to be larger than your desktop resolution. Be careful with this feature, as switching to fullscreen mode may cause problems in such cases. * Made the ROM launcher filename filtering be case-insensitive. This fixes a bug whereby ROMs with uppercase extensions were marked as invalid. * Added a pattern matching textbox to the ROM launcher, used to further filter the files shown in the listing. For now, this filters files only (directories are not filtered, and are always shown). * The location of EEPROM files used for AtariVox/Savekey emulation can now be changed with the '-eepromdir' commandline argument as well as in the UI. * Added '-gl_aspectn' and '-gl_aspectp' commandline arguments (and associated UI items), which replace the previous '-gl_aspect' setting. The aspect modes can now be set separately for NTSC and PAL mode. Related to this, the range of values is now 80 - 120. * Fixed bug with hold-select/reset/button0 when overriding ROM properties; the checkboxes in the UI weren't actually doing anything. * The 'grabmouse' option is now configurable from the UI; previously it was only accessible from the commandline or its shortcut key. * Removed 'Emulation_HmoveBlanks' ROM property and associated UI item. You can no longer optionally turn off HMOVE blanking; it is always enabled when necessary. 2.6.1 to 2.7: (Jan. 19, 2009) * Totally reworked the built-in UI to be font-sensitive and use higher- resolution fonts. Stella now requires a minimum screen size of 640x480. If used in a resolution smaller than that, the fonts will be reduced accordingly. Related to this, switching between software and OpenGL rendering now requires an application restart. * Added three different sized fonts (small, medium, large) which can be used in the ROM launcher. * Added ability to temporarily override ROM properties from the UI. This is tied to a right mouse button context menu in the ROM launcher, and is very useful when you want to use a set of properties for all subsequent ROMs without having to manually change each one. * Added ability to filter the files shown in the ROM launcher. Currently, the choices are 'all files', 'all roms', or 'roms ending with a certain extension'. This functionality is tied to a right mouse button context menu in the ROM launcher. Extensions can also be set with the '-launcherexts' commandline argument. * Added ability to reload the listing in the ROM launcher, either from a right mouse button context menu or pressing the Control/Cmd-R key. * Made the ROM info viewer in the ROM launcher configurable to show snapshots in 1x or 2x mode. * Made the delay between consecutive keys being recognized as one word configurable in the ROM launcher. This is useful if you find that you have to press keys too quickly to jump to a specific ROM. This can be set in the UI or using the '-listdelay' commandline argument. * Updated internal ROM properties database to ROM-Hunter version 4 (thanks go to RomHunter for his tireless research in this area). * Expanded the statistics overlay for the TIA image to also show Display Format and Bankswitch type information. * Added '-ss1x' commandline argument and associated UI item, used to generate snapshots in 1x mode, independent of the filtering/scaling currently in use. * Various path textboxes in the UI now recognize './' (or '.\') to mean the current directory and '~/' (or '~\') to mean your home directory (for Windows, home directory will be your 'My Documents' folder). * Large speedup in loading directories with many files in the ROM launcher. * Fixed reset issue in 3E, 4A50, AR, CV, E7, F4SC, F6SC, F8SC, FASC and MC ROMs; the internal RAM wasn't being randomized after the initial reset. * M6532/RIOT RAM is now randomized at every reset, not just when the emulation starts. * Fixed bug in _diff pseudo-registers in the debugger; they were actually defined backwards. * Added fix for 'Challenge/Surfers Delight' ROM; the startup bank was incorrect. Combined with the new 'Override Properties' functionality, you can now play both games directly from the UI (no need to use the commandline). * Fixed paddle issue with Activision Casino ROM; the last card in game 4 can now be reached. * Added new pseudo-registers to the debugger, useful for conditional breakpoints (_fcount, _cclocks, _vsync, _vblank). * Added 'timing' commandline argument functionality to the UI, so you no longer need to use the commandline to set it. * Size restrictions on the TIA image are now strictly enforced. The maximum height of a 1x TIA image is now 256 lines. * Added a new setting to the 'fullres' option named 'auto'. Using 'auto' will let Stella decide the best videomode to use in fullscreen. * Changed 'gl_fsmax' option to mean 'scale TIA image in fullscreen'. It will have no effect on UI modes. * Changed 'gl_aspect' option to range 80-100 (previously, it was 50-100). * Removed 'ui_zoom' and 'tia_zoom' options, replacing them with 'tia_filter' (which can be zoom1x, zoom2x, etc). There is no equivalent for ui_zoom, since the UI can no longer be scaled. * Added experimental 64-bit version for Vista64 (may also work on WinXP64). This hasn't been extensively tested, and is probably quite a bit slower than the 32-bit version. * OSX port now requires at least 10.3 and XCode 3.0 to compile. Sorry, but I no longer have access to older systems to compile for 10.2. * Huge updates to the documentation, particularly concerning the debugger. Many features that have been in Stella for a while are now documented for the first time. 2.6 to 2.6.1: (May 22, 2008) * Introduced more accurate timing for NTSC vs. PAL modes, where the framerate is based on the number of scanlines per frame. This should eliminate 'clicking' sounds when emulating ROMs that don't follow the exact NTSC or PAL scanline specs. * Added ability to see the current number of scanlines and corresponding framerate to the TIA emulation. This can be set with the '-stats' commandline argument, or dynamically turned on and off with the 'Alt-l' key combo. * Modified '-framerate' commandline argument, where a non-zero value overrides the automatic framerate calculation (based on number of scanlines). Setting 'framerate' to zero re-enables auto-frame calculation. Also, re-enabled changing the framerate from within the UI. * Added '-timing' commandline argument, which sets the type of waiting between processing frames. Setting it to 'sleep' emulates the previous behaviour in Stella; setting it to 'busy' emulates z26, and can in some cases eliminate screen tearing (at the expense of using all available CPU time). * Fixed issue with debugger disassembly and mirrored $40 TIA write addresses. They were actually defined at $30, and generating incorrect labels. * Fixed issue in AtariVox and SaveKey controllers where accessing the EEPROM sometimes failed after the first write. * Changed AtariVox and SaveKey EEPROM emulation to default to $FF for a blank EEPROM. * Fixed regression in cart auto-detection logic; some F6 ROMs were being misdetected as E7. * Fixed issue with M6532/RIOT timer initialization; it was causing some ROMs to hang (most notably Summer Games). Related to this, reworked the built-in random number generator to generate 'more' random numbers. * Fixed bug in CommandMenu where console buttons (Select, Reset, etc) weren't doing anything. 2.5.1 to 2.6: (May 16, 2008) * Added AtariVox support using a real AtariVox device, where Stella sends data directly to the AtariVox. For now, this is supported in Linux/UNIX, OSX, and Win32 only. You'll obviously need a real AtariVox, and a serial<->USB adaptor to connect it to your system. Added '-avoxport' commandline argument used to set the serial port to which the AtariVox is connected. Special thanks to Al Yarusso and Richard H. for providing sample hardware. * Added AtariVox and SaveKey EEPROM emulation. This reads/writes data to a 32KB file, not to the actual hardware. Very useful for testing EEPROM support without actually wearing out the real device. Special thanks to J. Payson for providing the EEPROM emulation code, and A. Herbert for answering many driver-related questions. * Added support for CX-22, CX-80, and AmigaMouse trackball controllers. * Improved debugger symfile handling so that addresses accessed as read-only won't use write-only labels (and vice-versa). More work is still needed in this area. * Added M6532/RIOT tab to the debugger. This will be expanded on in a future release. * Added TIA emulation fixes for graphical glitches in Escape from the Mindmaster, Mission Survive, Solaris, and SWOOPS! * Fixed bug where fullscreen OpenGL scaling wasn't working on 4:3 monitors. * Further improvements to the M6532/RIOT emulation, which unfortunately have broken old state files (again). * Added deadzone setting, for adjusting the deadzone amount for analog joysticks. This can be set using the commandline argument '-joydeadzone' or dynamically within the UI. * Make ROM disassembly in debugger take advantage of a wide window. * Fixed bug in 6507 BCD handling introduced in the last release. * For the Win32 port; Win9x should be fully supported again. 2.5 to 2.5.1: (April 9, 2008) * Fixed M6532 RIOT timer emulation. More testing is needed, but the changes so far have fixed several ROMs that didn't work before. * Fixed issue with weird characters in the debugger disassembly when loading .lst files. * Fixed bug where entering the debugger for 4A50 and E0 carts caused the ROM to be frozen afterwords. * Removed logic whereby starting a ROM from something other than the built-in launcher wouldn't allow the user to go back to the ROM launcher. * Fixed bug (hopefully) with the app icon not showing on the Stella window. Further testing is needed, since I can't duplicate the error myself. * Fixed default snapshot folder issues; the folder will now be automatically created in the same place as state folders, ini files, etc (whereever that may be for your platform). * Re-added 'lastrom' functionality, where Stella will remember and auto-select the last ROM that was successfully launched in the ROM launcher. * For Stella developers, fixed SpeakJet emulation so it compiles again. No improvements have been made to the emulation itself, though. 2.4.2 to 2.5: (March 28, 2008) * Added RomInfo widget to the ROM launcher, which shows properties information and a snapshot of the currently selected ROM. Updated the UI and added '-romviewer' commandline argument to activate this setting. Note that the ROM launcher will have to be sized at least 640x480 for this to be used. Also note that the snapshots must be in 1x mode with a maximum size of 320x260. This will be expanded on in a future release. * Added ROM audit functionality, whereby ROMs can be physically renamed according to their properties' name. * Added bankswitching support for 0840, SB, X07 and 4A50. A special thanks to Eckhard Stolberg for much help in this area. * Removed "non-browse" functionality from the ROM launcher; it now always uses browse/filesystem mode. The previous 'pretty' names can now be seen by renaming all your ROMs with the new ROM audit feature. * Huge overhaul of controller handling and Stelladaptor support, making it much easier to add new controller types in a future release. * Fixed paddle issues in Night Driver; paddle emulation speed should be much better. * Fixed several 6507 emulation bugs related to BCD handling. * Updated ROM properties based on info from RomHunter. * ROM properties can now be edited from the ROM launcher; you no longer have to start a ROM to do so. * Added support for configurable font to ROM launcher (currently only 'small' and 'large'). Updated the UI and added -launcherfont' commandline argument to change this setting. * Added SECAM, NTSC50, PAL60 and SECAM60 to the list of formats that can be used. Also, switching between these modes with 'Ctrl-f' now switches the palette only; the number of scanlines won't change. * Fixed crash when switching between software and OpenGL mode with a Stelladaptor plugged in. * Added '-tiafloat' commandline argument, which determines whether or not the TIA pins are in a 'floating' state. This is useful for testing on certain CMOS EPROM chips where the unused TIA pins on a read are not floating but pulled high. * Fixed issue in debugger where once a .sym file was loaded, it was used in all ROMs loaded after that. * Fixed issue in debugger where equate names weren't showing up in the RAM and CPU widgets. Note that this still isn't perfect, and needs support from DASM for proper functionality. * Updated state file format, creating smaller files (and in preparation for state rewinding in a future release). Old state saves will no longer work. * Added '-bs' commandline argument, which is an alias for '-type' (which is still present). * Removed -pXspeed' commandline arguments, and replaced them with a single '-pspeed'. * Removed '-paddle' commandline argument. The paddle currently emulated by the mouse can still be changed with Ctrl-0..3 or within the UI, but the setting is no longer saved. * Reworked UI for specifying that the console ports have been swapped, hopefully making it easier to understand. * Added 'Ctrl-c' & 'Ctrl-v' to EditTextWidgets, allowing to copy and paste the text widget contents. More work in this area is coming in a future release. * Added 'Ctrl-leftarrow' and 'Ctrl-rightarrow' to EditTextWidgets, to move to the first character of previous and next words (respectively). * For the Win32 port: fixed OpenGL crashes in Vista. Graphical updates are still slower in Vista compared to XP, though. * For the Win32 port: default folder for Stella config files is now 'My Documents\Stella'; this can be disabled if necessary. This should fix issues with losing settings when launching Stella from an IDE, and the creation of stella.ini and 'state' directories in many different places. * For the Win32 port: several fixes to the Visual Studio project files, allowing building in debug or release mode, for both i386 and x86_64. The project files have been upgraded to Visual Studio 2008, and Stella can now be built and distributed without the VS runtime libraries. * Updated configure script for cross-compiling Win32 version in Linux. 2.4.1 to 2.4.2: (September 17, 2007) * Made usage of 'GL_TEXTURE_RECTANGLE_ARB' extension configurable, and have it default to off. This should take care of the black/white screen many people were experiencing with ATI video hardware. This is accessible using the 'gl_texrect' commandline argument). Set it to 'true' or 'false' to enable/disable the extension. 2.4 to 2.4.1: (August 27, 2007) * Re-added OpenGL aspect ratio setting ('gl_aspect' commandline argument). * Re-added non-browser mode to the ROM launcher. * For the Linux/UNIX port; fixed OpenGL vsync issue with Nvidia video cards. 2.3.5 to 2.4: (August 20, 2007) * Added new video sub-system where fullscreen and windowed modes are treated differently. Windowed modes now use '-zoom_tia' and '-zoom_ui' arguments, while fullscreen modes can be specified by resolution using the new '-fullres' argument. * Widescreen video modes are now supported; Stella will simply center the image with surrounding black borders. * Many UI-related changes, including resizable ROM launcher and debugger windows, and a new UI palette (the previous 'classic' palette is still available). This is still a work in progress. * The locations of all major config files (statedir, palette file, cheat file, properties file, etc) are now configurable from the commandline and within the UI. * Updates to TIA palette support. Added SECAM support, and removed the built-in 'original' palette. Standard, z26, and user are still available. * Various bugfixes to some debugger commands. The 'run' command no longer causes a crash, and several others have better error-checking. * Added more complete cartridge auto-detection for Commavid (CV), 3E, 3F and Activision (FE) formats. * Removed XStart and Width ROM properties, since the forthcoming TIA rework won't be using them. * Reworked internal storage of ROM properties to be faster and take up less space. * Added several different ways of stretching the OpenGL image to the '-gl_fsmax' argument, for more flexibility. * Removed OpenGL aspect ratio setting favour of the previously mentioned video changes. We'll see how this goes. * Removed dirty-rect support from software rendering, since it was actually sub-optimal in Windows and OSX and defaulted to off in previous versions. * Added support for gzipped ROMs. * Re-added pause support. * Re-added support for Windows 98. * Removed support for 'STELLA_BASEDIR' environment variable, since each config file can be now configured separately. * Removed '-fastscbios' argument, since it must always be turned on. * Removed PSP support, since it hasn't been updated in over a year, and someone else is maintaining another port elsewhere. * For the Unix/Linux port; fixed 'make install' issues, and changed icon to PNG format. 2.3 to 2.3.5: (January 17, 2007) * Greatly improved cartridge bankswitch type auto-detection. Stella can now (mostly) autodetect cartridge types 'E0', 'E7', '3E', '3F' and Superchip carts. Obviously, this autodetection is not infallible, but relies on patterns in the ROM data, and how it was compiled. Because of the auto-detection types already supported, almost all bankswitch info was removed from internal ROM properties. Set the ROM property "Cartridge.Type" to "Auto-detect" for this to take effect. * Added auto-detection of display type (NTSC or PAL). Currently, PAL60 ROMs will be detected as NTSC. This is almost 100% accurate, and fails in very few cases (for those that are mislabeled, the ROM properties can be set specifically). Set the ROM property "Display.Format" to "Auto-detect" for this to take effect. * Improved emulation timing when exiting one ROM and starting another. Previously, this could result in the second ROM having its sound start later than it should have. * Removed pause functionality from the core, since it's been superceded by the other event states. You can now enter one of the menus for a similar effect (options, command, debugger, etc). * Added toggle for PAL color-loss emulation, which defaults to off. Previous versions of Stella always used color-loss emulation. Related to this, added 'colorloss' commandline argument. * Added rudimentary support for configuring the UI palette ('uipalette' commandline argument) and ability to change the size of the launcher window ('launchersize' commandline argument). This will be expanded on in future releases. * Reworked options menu so it's now accessible from the ROM launcher as well as while playing a ROM. * Re-added ability to change the width and height of a Console. Related to this, changing XStart/YStart/Width/Height dynamically no longer resets the ROM. * Removed 'tiadefaults' commandline argument, since Stella will now default to using accurate positioning, and not use 'tweaks'. * Joystick code now allows all 4 directions; 'Bumper Bash' now works correctly. * Improved Keypad emulation; 'Alpha Beam with Ernie', 'Oscars Trash Race' and 'Magicard' now work correctly. * Reworked GUI code, so that all dialog boxes are automatically centered. * Added 'rominfo' commandline argument, which prints some detailed info for a ROM. * For the OSX port; fixed crashes in OpenGL mode. * For the GP2X port; some improvements to the sound code. * For the GP2X port; added vertical centering of the TIA image (when possible). 2.2 to 2.3: (December 22, 2006) * NOTE: Because of the many changes in this release, all settings will be reset to defaults. If this doesn't happen for you, it will be necessary to manually delete your previous settings. * Potentially huge speedups in software rendering mode, both in emulation and UI modes. Deactivating 'dirty rects' uses these new modes, which can be 2-3 times faster for many configurations. * For UI navigation, changed from using 'joymouse' to the more familiar 'tabbing' functionality, where you move from object to object by use of some tab key. As a result, completely removed the 'joymouse' commandline argument and all associated functionality. * Added event remapping for UI events, separate from events while in emulation mode. * Added support for PAL60 ROMs, which use the PAL palette and resolution but run at NTSC timing (60Hz). Added ROM property for this, and updated the internal properties database for many PAL60 ROMs. * Added support for user-definable palettes. For now, only one extra palette is supported, but in the future we may have them specified per-ROM. * Fixed bug in PAL colour-loss emulation, which wasn't actually being done for the original Stella and z26 palettes. * Fixed several TIA-related emulation bugs as reported on AtariAge. More fixes will come with the TIA rewrite, due in the next release. * Added new scaler infrastructure, replacing the '-zoom' commandline argument with '-scale_ui' and '-scale_tia'. This means the UI and emulation can now be scaled independently. * Added '-gl_vsync' commandline argument and associated UI elements, which uses synchronization to vertical blank interrupt in OpenGL on supported systems. This eliminates tearing in OpenGL rendering. * Changed naming of snapshots and state files. These files are now named based on the names given in the properties database, and no longer use the 'md5sum' name. As a result, state files from previous versions will no longer work unless they're manually renamed. Related to this, removed the '-ssname' commandline argument. * Fixed bug where 'Snapshot saved' appeared when taking snapshots in succession. * Added a 'Previous directory' entry to the top of each listing while in ROM Browse mode, which is equivalent to the 'Go Up' button. This makes it easier to navigate the filesystem, since you never have to 'tab out' of the ROM listing. * Added all sound related commandline options to the UI, so you no longer have to use the commandline to set those options. * Added new property to ROM properties specifying whether to swap paddles plugged into a virtual port. This eliminates the need to manually set the paddle mode for those ROMs that don't use paddle zero by default. * Added a 'Defaults' button to the Game Properties dialog, which resets the ROM properties to the internal defaults, deleting that ROMs properties from the external properties file. * Fixed bug whereby modified ROM properties weren't being reloaded when restarting a ROM. * Made 'phosphor' and 'phosphor blend' a ROM property, meaning it can be set per-ROM. * Added support for relocating the base Stella directory, by setting the environment variable 'STELLA_BASEDIR'. This must be done each time before Stella starts. * Added '-fastscbios' commandline argument, which speeds up loading of vertical bars in Supercharger ROMs, and made it the default. * Added '-autoslot' commandline argument, which automatically switches to the next available slot after saving a state. This defaults to off, and must be set from the commandline. * Fixed bug in debugger command 'runto', which could enter an infinite loop under some conditions. * Updated configure/build toolchain so patching is no longer required for Debian packages. * Removed dependency on PNG library (PNG snapshots are still present, but the actual library is no longer required). * For the OSX port, improved OpenGL performance on Mac Mini using Intel GMA950 video hardware. * For the GP2X port, added support for PAL ROMs, and updated SDL to use hardware scaling. 2.1 to 2.2: (April 7, 2006) * Added new ROM browser option which works like a normal filesystem browser, allowing navigation throughout the filesystem. The old mode of browsing is still present, and can be toggled at runtime. Related to this, fixed bug whereby sorting in the ROM launcher sometimes didn't work. * Integrated stella.pro properties into the application, resulting in faster startup time. Now Stella can be redistributed as a single binary; no external files are needed, but they will still be used if present. * Reworked ROM properties files once again. The 'user.pro' file has been removed, and all user-defined properties are stored in 'stella.pro' instead. You should delete all properties files when upgrading to this version, to take advantage of the speed increases. * Reworked settings files once again. Removed all references to a global settings file. Each user now gets a user-specific settings file only. If that file doesn't exist, the built-in defaults are used. * Added 'conditional saving' of the cheatcode and settings files, so that these files are only written to disk when absolutely necessary. This doesn't really affect desktop systems, but is very useful for systems with flashram-based storage (GP2X, WinCE, etc). * Reworked Settings class, hopefully fixing a bug whereby settings weren't being saved in certain cases (most evident in the OSX port). * Added 'tiadefaults' commandline option, which can also be toggled from within the GUI. This option disables all TIA positioning 'tweaks' that typically make a game look better, and present the image exactly as it would appear on a real 2600. * Added jitter-detection code for the paddle emulation, which should eliminate an annoying 'jittering' effect when using paddles with a Stelladaptor. * Related to jitter-detection, added '-pthresh' commandline option and GUI entry, which sets a bound below which the emulation detects jitter. * Fixed crash when adding one-shot cheats. * Fixed bug in RAM comparative searches in the debugger. * Fixed bug with setting snapshot naming type from the GUI (it was always being set to 'romname'). * Re-added low compatibility CPU emulation mode, since it benefits some slower systems. This is activated with the commandline argument '-cpu low'. * For the OSX port, added Universal binary support. * For the OSX port, reworked the menu handling, so that certain menu options are only enabled when it makes sense to do so. * For the GP2X port, fixed joystick deadzone issues and scroll bug in ROM launcher. * For the GP2X port, fixed issue with PAL ROMs causing a crash because of screen size. A message is now shown indicating that PAL ROMs are not yet supported. 2.0.1 to 2.1: (January 29, 2006) * Added phosphor effect, similar to z26. Useful on ROMs which alternate sprites from one frame to another, resulting in an annoying flicker. When using phosphor mode, a pixels colour is mixed with its previous value, resulting in a blended image that doesn't flicker, emulating the phosphoresence effect on a real television. * Added 'pp' developer commandline argument to set the "Display.Phosphor" property, and 'ppblend' to set the amount to blend pixels in phosphor mode. Also added 'Alt p' key to enable/disable phosphor effect while ROM is emulated. By default, phosphor mode is only used when necessary, as specified in the stella.pro file. * Renamed 'cheetah' commandline argument to 'cheat'. * Added per-frame cheatcodes (4 characters long), which are evaluated each frame. * Added cheatcode GUI, where cheats can be named, edited, saved, etc. * Cheat codes are now saved to stella.cht file and are automatically reloaded when Stella starts. * Improved 'joymouse' functionality. While in GUI mode, any axis will simulate mouse movement, and any button will simulate a mouse click. So the GUI can be completely navigated without a mouse. * Improved CommandDialog and LauncherDialog wrt joymouse functionality. These dialogs are used more than any other on devices without a mouse, so joystick axis movement switches between GUI objects, rather than simulating the mouse. This leads to much faster selection of objects. * Added mapping of multiple SDL joystick axis to Event Mapping. * Added joystick hat support, and mapping of multiple hats to Event Mapping. * Added remapping of paddle emulation to the keyboard or joystick axis (the mouse is still used by default for paddles). Related to this, use more precise analog values when analog axis are mapped to analog-type events (such as paddles). * Treat joystick events as other types of controllers based on the virtual port entry in stella.pro. This means that mappings for a joystick will emulate other devices when necessary. * Added 'sp' developer commandline argument, which sets the "Console.SwapPorts" property and swaps the arrangement of the virtual ports. Useful for games like "Raiders of the Lost Ark", where the joysticks are normally swapped. * Added ability to set which Stelladaptor device emulates which virtual joystick port ('sa1' and 'sa2' commandline arguments, which accept 'left' or 'right'). * Fixed issues with jittering joysticks/mice causing weird events when starting Stella. * Added 'freq', 'tiafreq' and 'clipvol' commandline arguments, which affect the sound subsystem (see manual for further info). * Made state files completely cross-platform, both in terms of endianness as well as CPU size (32 vs. 64 bit). * Fixed crash with using 'cheat' and 'break' from the commandline. * Implemented dynamic loading of OpenGL library. 2.0 to 2.0.1: (October 24, 2005) * Added 'dirtyrects' support, which speeds up rendering for some Windows users. * Fixed bug where taking snapshots would fail if the snapshot directory wasn't specified. * Made ROM launcher case-insensitive, so upper and lowercase names are now mixed in the correct order. * Fixed ZIP ROM support to search the archive for ROMs ending with either .bin or .a26 (case insensitive). * ROMs which don't have an associated properties entry are no longer named 'Untitled' in the Stella window or when taking snapshots. The actual ROM name is now used. * Changed minimum height of debugger to be 27 lines in the prompt, or approx. 700 pixels high. This should make using the debugger easier for users with lower resolution monitors. Related to this, the RomWidget now uses all possible vertical space when changing the debugger height. * Fixed bug related to upgrading Stella and event mappings being incorrect. Stella now detects this, and uses the default mappings. So upgrading to version 2.0.1 means your event mappings will be reset. * Fixed bug in loading debugger symbol files generated on different operating systems. * For the Windows port; added exe installer based on InnoSetup. * For the Windows port; compiled icon into Stella, so it now looks like a real Win32 application. * For the OSX port, reverted window resize key combos back to 'Cmd =' and 'Cmd -' to match the 1.4.2 release. 1.4.2 to 2.0: (October 16, 2005) * Added integrated GUI. Stella is now a fully graphical application, and all settings can be changed dynamically while the application is running. That means the commandline is no longer required (but support is still there for those who want to use it). * Added ROM launcher. You can now exit a game and start playing another one from directly within Stella (you no longer have to quit Stella and restart it). * Because of the integrated GUI and ROM launcher, StellaX and KStella (the Windows and Linux frontends) have been discontinued. The OSX port now uses the launcher as well. * Added an integrated debugger for game developers. This is currently the first version of a debugger in Stella, but it's already quite usable. * Added new sound subsystem, which is much faster and more accurate. Related to this, added stereo sound output (used by some homebrew games). * Added ZIP support. Stella can now open ROM's compressed in zip format. * Added cartridge 'frying', thanks to Fred "batari" Quimby. This emulates the action of turning the power button on and off on a real Atari, often resulting in some strange effects. * Added ability to edit current ROM properties from directly within Stella, which can then be saved directly into the 'user.pro' file. So creating a properties entry for a new ROM can be done without any external tools. * Added initial support for using Stella in an 'arcade-box' environment without a keyboard. This consists of an in-game menu for choosing common actions in Stella, as well as using the joystick navigate the mouse pointer. * Reworked properties system to use both a system-wide 'stella.pro' and a per-user 'user.pro' properties files. Changes made by the user and stored in 'user.pro' are no longer erased when upgrading Stella. * Added support for cartridges with 3E bankswitching format. * Added preliminary Cheat support. * Added 'Alt/Shift-Cmd' z, x, c, v, b, n keys to enable/disable the P0, P1, M0, M1, BL, PL bits in the TIA, respectively. * Added 'Alt/Shift-Cmd .' key to disable all bits in the TIA. * Added 'Alt/Shift-Cmd /' key to enable all bits in the TIA. * Added 'Alt/Shift-Cmd g' key to switch dynamically switch between software and OpenGL modes while Stella is running. * Added 'Ctrl/Cmd r' key to reload the ROM currently being emulated. * Added 'Alt/Shift-Cmd s' key to merge the current game properties into the properties file. * Added 'help' commandline argument. Launching Stella from the commandline with no options now starts Stella in ROM launcher mode, instead of showing help (as in previous versions). * Added the following commandline arguments for developers: "pro, type, ld, rd, tv, lc, rc, bc, format, xstart, ystart, width height, cpu, hmove". Developers can consult the manual for further details. * Removed 'mergeprops' commandline argument, since there are now dedicated keys to either save or merge game properties. * Removed 'hidecursor' commandline argument. Stella will now automatically decide when to use this setting. * Fixed framerate when switching between NTSC and PAL modes. Stella now uses the correct framerate based on the format of the ROM, in terms of both video and audio. * Added 'configure' support to the build process for both Linux and Win32 (using MinGW). Developers can now use the familiar 'configure; make; make install' commands to compile Stella. * Further consolidation and integration of SDL. This should lead to faster operation and a more consistent look for all ports. * Fixed some 64-bit issues. Stella now compiles and runs correctly on AMD64 and PPC64 Linux systems. * Updated the Stella manual with pictures of the new integrated GUI. 1.4.2a to 1.4.2b: MacOSX version only (February 27, 2005) * Added fix to mute sound while user is loading a new cartridge, or using the Preferences window. 1.4.2 to 1.4.2a: MacOSX version only (February 21, 2005) * Fixed problem in timing loop which was causing crashes after 15-30 minutes. * Turned optimization on in compiler settings, which had somehow gotten turned off. 1.4.1 to 1.4.2: (February 19, 2005) * Updated the sound system. All popping and cracking sounds that previously occurred at program start/stop and when entering/exiting menu or pause mode have been eliminated. * Fixed the gl_fsmax argument to mean "switch to desktop resolution on fullscreen OpenGL", instead of to the maximum possible resolution (the two are not always the same). * Added Alt [ and Alt ] keys to dynamically adjust the sound volume during emulation. * Added Control 0, Control 1, Control 2, Control 3 keys to dynamically change which paddle the mouse should emulate. * Added video_driver argument. This accepts the different options that can be specified for SDL_VIDEODRIVER (see SDL homepage for more information). Basically, it eliminates the need to set the SDL_VIDEODRIVER environment variable. * Made sure screen is refreshed before taking a snapshot. This eliminates the problem with new snapshots containing the text "Snapshot saved". * For the Windows port; added windib and directx as options for 'video_driver' when using software rendering. The 'windib' option is now the default, and in many cases it's up to 10 times faster than using 'directx'. * For the OSX port; added 'Cmd-R' key to reload the currently loaded ROM. 1.4 to 1.4.1: (August 15, 2004) * Fixed PAL sound issues. PAL games now should sound correct (no distortion or missing sounds), but some games may still run too fast. This is still a work-in-progress, and will be fixed in Stella 1.5. * Cleaned up the SDL event gathering loop. This should hopefully fix the problems with "double-pumping events" reported by some Windows users. Event gathering and dispatching is now much faster as well. * Fixed a bug where the Control or Alt keys could be assigned to some event, but they could never be used. Control/Alt can now be used for any event. * Updated stella.pro file to work with the latest Good2600 ROMset release (Thanks go to Voch for helping to maintain the stella.pro file). * For the Windows port; removed requirement for ROM files to be named *.bin in the StellaX frontend. The ROM's can now have any name, but ZIP-files are not yet supported. * For the Windows port; fixed the problems with the included modified SDL library and Windows 98 users. Stella should now run in Windows 98. * For the OSX port; added preference to allow user to select the directory in which ROM images are stored. This sets the default directory to start the browsing for a ROM in, and doesn't preclude the user from selecting a file outside that directory. * For the OSX port; fixed preferences bug where Preferences changed before a game was opened were not being saved. * For the OSX port; fixed an issue which would prevent the program from working with OSX 10.1. 1.3 to 1.4: (July 17, 2004) * Codebase ported to SDL. The DOS and X11 ports have been discontinued. * Sound code ported to SDL. For the Linux versions, ALSA and OSS sound support has been discontinued. * The Linux, MacOSX and Windows ports are now based on the same codebase and are actively maintained. That means simultaneous (and hopefully more frequent) releases. * A new Windows port has been created, with the GUI based on StellaX. This is the first new release for Windows since Stella 1.2. (software mode is not yet optimized; OpenGL mode works much better) * A new Mac OSX port has been created by Mark Grebe. This is the first new release for Mac OSX since Stella 1.2. * Added OpenGL rendering support. * Added more refined in-game GUI. * Added event remapping. Emulation keys can now be remapped to the keyboard or up to 4 joysticks. * Added native Stelladaptor support. Joysticks, paddles, and driving controllers have been tested. * Digital sound support (used in games like Quadrun and Pitfall2) has been greatly improved. Sound generation is now more tightly synchronized with video updates. * Added support for switchable palettes. Currently you can switch between the current Stella palette, original Stella palette (pre-1.2 versions), and the z26 palette. * Added support for UA Limited style bankswitching (Funky Fish and Pleiades). * Switched to using high compatibility M6502 mode by default. This means old state saves from previous Stella versions will no longer work. * The meaning of the "-sound" command line option has been changed. This option now accepts either 'true' or 'false (1 or 0) to enable/disable sound. * Changed sound mixer functionality. The system volume/mixer settings will never be changed; volume changes in Stella will only affect the emulation itself. * Added "-video" command line option. This option accepts either 'soft' or 'gl', to use software/OpenGL rendering. * Added "-gl_filter" command line option. This option accepts either 'nearest' or 'linear', to use GL_NEAREST or GL_LINEAR filtering. * Added "-gl_aspect" command line option. This option accepts a decimal value specifying how much to scale the width of the emulation image (useful for giving an authentic 'square-looking' 4:3 mode). * Added "-gl_fsmax" command line option. This option accepts either 'true' or 'false, and specifies to use the maximum possible resolution when in fullscreen OpenGL mode (useful for Linux and for Windows on laptops). * Added "-fragsize" command line option. This option accepts the size to use for sound fragments. Linux/MacOSX works well with 512, Windows seems to need 2048. This value must be a power of two. * Modified "-volume" command line option. If you specify '-1', Stella will use the system volume. * Renamed the "-pro" command line option to "-altpro". * Renamed the "-fps" command line option to "-framerate". * Removed the "-center" command line option. Stella now automatically centers the window when possible. * Removed the "-paddle real" command line option, since it never really worked correctly (and Stelladaptor support adds that functionality anyway). * Removed all command line options relating to the X11 port (owncmap, display). 1.2 to 1.3: (February 17, 2003) * Improved TIA sound system so that games with digitized audio work * Added saving and loading of game state to the core; X11, SDL, and DOS versions current support saving and loading game state * Added support for F4 bankswitching method * Pitfall II DPC sound emulation completed * Fixed a bug which caused the difficulty switches to operate backwards * Changed DPC auto-detection to use file size so that Pitfall II mods work * Modified RIOT timer emulation so that startup values are random * Added 3F bankswitching auto-detection routine so that homebrews and demos work without a stella.pro entry * Updated the TIA message boxes so they look a little nicer * Latest stella.pro file included in distribution * Added some developer options to the core, and the ability to change game width, height, xstart, ystart, and others while the emulation is running. Added ability to switch between NTSC and PAL at runtime, and the ability to save the current properties to a file or to merge the changes into the stella.pro file; X11 and SDL versions supported for now (compile option) * External sound server for the X11 and SDL versions no longer required, as all sound code is now integrated into the core * Changed locations of the user's config files for the X11 and SDL versions; the user's stellarc file is now located in $HOME/.stella/stellarc, state files are located in $HOME/.stella/state/ and the stella.pro file is located in $HOME/.stella/stella.pro * Changed the way options are supplied on the commandline for the X11 and SDL versions. Now all commandline options take exactly the same arguments as in the INI file. * Added "-accurate" command line option to choose between accurate (CPU-intensive) timing or less accurate (CPU-friendly) timing to X11 and SDL versions. This is the final version of what was considered experimental timing code in Stella 1.2. * Added "-sound" command line option to choose which sound backend to use (alsa, oss, sdl) with the X11 and SDL versions. * Added the developer command line options to the X11 and SDL versions, which are only activated in developer builds: -Dformat, -Dwidth, -Dheight, -Dxstart, -Dystart, -Dmerge * Fixed window resize bug in the X11 port * Added "-nosound" command line option to the DOS port to disable audio * DOS port supports a "-vsync" option to synchronize emulation with the video blank of the video card * Changed VGA code in the DOS port to use a 60Hz 320x200 and a 60Hz 320x240 graphics mode * DOS port has been updated to run better under Windows NT, 2000, and XP. There are still issues with the sound, however, it is usable. * DOS port is using a new Sound Blaster driver created by Matt Conte which supports auto-detection of sound cards. * DOS port supports a STELLA_HOME environment variable that defines the location of config files. * In the DOS port the stella.pro file is searched for first in the current working director and then in the $STELLA_HOME directory * In the DOS port the ROM image is searched for first using the specified path, then in $STELLA_HOME/ROMS, and finally in $STELLA_HOME Cyberstella 1.2.1 (May 16, 2002) * Removed the built-in games until some legal stuff is sorted out Cyberstella 1.2 (May 10, 2002) * Initial release of a new WIN 32 port of Stella DOS 1.2 to DOS 1.2.1: (April 28, 2002) * Fixed a bug with control keys being confused with the pause key * Fixed a bug with the pause key causing the application to lockup 1.1 to 1.2: (April 21, 2002) * Improved illegal CPU instruction support. Thrust and Qb will now operate correctly. * Improved emulation of undefined TIA reads. The ball in Video Pinball finally bounces off of the paddles! * More accurate NTSC and PAL palettes. These palettes should be much more like the colors displayed on a real TV. * PAL color loss is now emulated. If a PAL game displays an odd number of scanlines then the next frame will be displayed in black & white. * TIA emulation improved to fix some problems with Pole Position, Fatal Run, Dolphin, Decathlon, Robot Tank, and Hole Hunter. * Support for Pitfall II has been added, however, the enhanced sound provided by the DPC chip found in the Pitfall II cartridge isn't currently emulated. * Support added for the Commavid (CV) bankswitching method. * Support added for the Megaboy cartridge. * Improved Supercharger emulation including a new BIOS that shows the vertical blue progress bars like the real thing. * Code for the emulation core has been updated to work with newer C++ compilers compliant with the C++ standard. * Basic message support added to the TIA emulation. This allows a short message to overlay the TIA frame. Currently, it's used when switching color modes and difficulty settings. * The internal data structure for the stella.pro file was changed from a resizable array to a binary search tree. This results in quicker startup times. * An SDL port of Stella is available (requires SDL 1.2.0 or greater) * Added option to not load in the whole stella.pro file when starting Stella. This option is enabled on the X11, SDL, and DOS versions. Win32 version is left alone since it's needed for loading multiple games from the UI. Saves on memory usage. * Added INI file option to the X11 and SDL versions. Options can be specified in this file instead of entering them on the commandline. Any options entered on the commandline override options in the INI file. File is called stellarc. For the X11 and SDL versions, it can be in either $HOME (as $HOME/.stellarc) or in /etc (as /etc/stellarc). The one in $HOME has higher priority than the one in /etc. * Added snapshot support to the X11 and SDL versions. Pressing F12 saves the current screen in PNG format. Requires PNG library. * Removed stella.pro file from the binary, resulting in large space savings. The stella.pro file is no longer optional. For the X11 and SDL versions, it can be in either $HOME (as $HOME/.stella.pro) or in /etc (as /etc/stella.pro). The one in $HOME has higher priority than the one in /etc. For DOS and Win32 versions, the stella.pro file must be in the same directory as the executable. * Added pause functionality to the core. Implemented in DOS, X11, and SDL versions for now. 1.0 to 1.1: (February 26, 1999) * DOS and Linux versions support real Atari 2600 paddles using a special PC game port adaptor * Linux version uses the new 1.2.x joystick driver API * Added support for the "-display" option to the X Window version * Added support for private colormaps to the X Window version * Fixed a few bugs in the Supercharger emulation - A major bug in the ROM loading routine was fixed - Multi-loading in "Escape from the Mindmaster" works correctly - All Supercharger games load and execute at this point * Added a small hack to the TIA code to fix a display problem in "Escape from the Mindmaster" * Improved TIA emulation to support the RESPx multi-sprite trick 1.0b1 to 1.0: (October 7, 1998) * DOS version supports 320x200 and 320x240 graphics modes * Several portability issues have been resolved * Preliminary support for Chris Wilkson's Megacart bank-switching scheme * BSDI target included in makefile * Improved Users Manual in several "popular" formats 0.7 to 1.0b1: (July 25, 1998) * Supports the following controllers: Joysticks, Paddles, Booster-Grip, Keyboard and Driving * Supports the following bank switching methods: 2K, 3F, 4K, AR, E0, E7, F4SC, F6, F8, F8SC, FASC, FE * Properties are associated with games using their MD5 checksum calculated on the entire ROM image * Uses the new 'stella.pro' file format for game properties * Includes Erik's latest stella.pro properties file * New frame rate throttle code for X windows GUI * Based on the new and improved M6502 CPU emulation * Improvements to TIA emulation - Support HMOVE blanks - Improved Cosmic Ark star field effect - Some support for the RESPx multiple sprite trick - Support NTSC and PAL palettes * Improvements to PIA emulation (timing) * Improved Supercharger emulation 0.6 to 0.7: (June 7, 1997) * Improved emulation speed of TIA and 6507 * Added Starpath Supercharger support * Added Tigervision bank-switching support (3F bank-switching) * Added pause game feature for Unix and DOS * VCS files combined into a single builtin property file * Added TIA HMOVE "feature" to support Cosmic Ark stars * Improved TIA VSYNC code so that it works more like the real thing (0.6 VSYNC code caused the graphics of some games to be off such as Alien and Battle Zone) * Added two 6507 emulators: one is designed to act more like the real thing, while the other is designed to be as fast as possible (required for Supercharger support) * Changed TIA peeking so lower nibble of byte read is the same as the TIA address being accessed (Warlords now works) 0.5 to 0.6: (January 18, 1997) * Fixed collision detection problem (Freeway works) * Changed PIA timing code to fix screen jitters * Added new bank-switching methods: F4SC (Fatal Run), E7 (Burgertime) * Fixed some code in the TIA emulation that caused SEGFAULTS * Improved frame rate throttling code to work better on fast machines * Improved TIA emulation (missle graphics are fully emulated now) * Included Bob Colbert's "Okie Dokie" game * Uses version 1.1 of the TIA Sound library by Ron Fries 0.4 to 0.5: (November 17, 1996) * Added sound support * Added new bank-switching methods: F8SC (Defender II), FASC (CBS RAM+) * Changed TIA so peeking $E and $F return $F not $0 for Haunted House * Changed PIA timing code to fix screen jitters in Frogger * Addressing scheme rewritten * Optimized 6507 memory accesses * Randomized memory in PIA upon startup * Removed auto-disabling of objects at the start of a frame so you can't walk through walls in Adventure * Changed the X windows terminal update method to make it faster and easier to understand 0.3 to 0.4 (August 28, 1996): * TIA code has been optimized some * Some games can be played with just a ROM image * New search method for ROM images (no more STELLA_PATH) * Delta screen update supported * Better error handling added to the "core" 0.2 to 0.3 (July 12, 1996): * Keyboard joystick support is much better (Daniel Marks) * Paddles are now supported via the mouse (Bradford Mott) * Many portability issues have been resolved (Keith Wilkins) * Fixed a problem with the 6507 ADC and SBC instructions that caused some games (Enduro) not to work correctly (Bradford Mott) * Power Macintosh port (Aaron Giles) * Windows 95 & NT port (Jeff Miller) stella-5.1.1/Copyright.txt000066400000000000000000000071741324334165500155320ustar00rootroot00000000000000=========================================================================== SSSS tt lll lll SS SS tt ll ll SS tttttt eeee ll ll aaaa SSSS tt ee ee ll ll aa SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" SS SS tt ee ll ll aa aa SSSS ttt eeeee llll llll aaaaa =========================================================================== License Information and Copyright Notice =========================================================================== Copyright (C) 1995-2018 by Bradford W. Mott, Stephen Anthony and the Stella Team This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. You should have received a copy of the GNU General Public License version 2 along with this program (License.txt); if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. /*************************************************************************** The Stella project uses certain portions of code under the following licensing; the specific files also contain this disclaimer: Copyright Aaron Giles All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name 'MAME' nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ stella-5.1.1/License.txt000066400000000000000000000431151324334165500151370ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. stella-5.1.1/Makefile000066400000000000000000000211301324334165500144450ustar00rootroot00000000000000##============================================================================ ## ## SSSS tt lll lll ## SS SS tt ll ll ## SS tttttt eeee ll ll aaaa ## SSSS tt ee ee ll ll aa ## SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" ## SS SS tt ee ll ll aa aa ## SSSS ttt eeeee llll llll aaaaa ## ## Copyright (c) 1995-2016 by Bradford W. Mott, Stephen Anthony ## and the Stella Team ## ## See the file "License.txt" for information on usage and redistribution of ## this file, and for a DISCLAIMER OF ALL WARRANTIES. ## ## $Id: Makefile,v 1.37 2009-01-11 21:31:21 stephena Exp $ ## ## Based on code from ScummVM - Scumm Interpreter ## Copyright (C) 2002-2004 The ScummVM project ##============================================================================ ####################################################################### # Default compilation parameters. Normally don't edit these # ####################################################################### srcdir ?= . DEFINES := -D_GLIBCXX_USE_CXX11_ABI=1 LDFLAGS := -pthread INCLUDES := LIBS := OBJS := PROF := MODULES := MODULE_DIRS := DISTNAME := stella-snapshot # Load the make rules generated by configure include config.mak # Uncomment this for stricter compile time code verification # CXXFLAGS+= -Werror ifdef CXXFLAGS CXXFLAGS:= $(CXXFLAGS) -x c++ else CXXFLAGS:= -O2 -x c++ endif CXXFLAGS+= -Wall -Wextra -Wno-unused-parameter -Wno-ignored-qualifiers ifdef HAVE_GCC CXXFLAGS+= -Wno-multichar -Wunused -fno-rtti -Woverloaded-virtual -Wnon-virtual-dtor -std=c++14 endif ifdef CLANG_WARNINGS CXXFLAGS+= -Weverything -Wno-c++17-extensions -Wno-c++98-compat -Wno-c++98-compat-pedantic \ -Wno-double-promotion -Wno-switch-enum -Wno-conversion -Wno-covered-switch-default \ -Wno-inconsistent-missing-destructor-override -Wno-float-equal \ -Wno-exit-time-destructors -Wno-global-constructors -Wno-weak-vtables \ -Wno-four-char-constants -Wno-padded endif ifdef PROFILE PROF:= -g -pg -fprofile-arcs -ftest-coverage CXXFLAGS+= $(PROF) else ifdef HAVE_GCC CXXFLAGS+= -fomit-frame-pointer endif endif ####################################################################### # Misc stuff - you should never have to edit this # ####################################################################### EXECUTABLE := stella$(EXEEXT) all: $(EXECUTABLE) ###################################################################### # Various minor settings ###################################################################### # The name for the directory used for dependency tracking DEPDIR := .deps ###################################################################### # Module settings ###################################################################### MODULES := $(MODULES) # After the game specific modules follow the shared modules MODULES += \ src/emucore \ src/emucore/tia \ src/emucore/tia/frame-manager \ src/gui \ src/common \ src/common/tv_filters ###################################################################### # The build rules follow - normally you should have no need to # touch whatever comes after here. ###################################################################### # Concat DEFINES and INCLUDES to form the CPPFLAGS CPPFLAGS:= $(DEFINES) $(INCLUDES) # Include the build instructions for all modules -include $(addprefix $(srcdir)/, $(addsuffix /module.mk,$(MODULES))) # Depdir information DEPDIRS = $(addsuffix /$(DEPDIR),$(MODULE_DIRS)) DEPFILES = # The build rule for the Stella executable $(EXECUTABLE): $(OBJS) $(LD) $(LDFLAGS) $(PRE_OBJS_FLAGS) $+ $(POST_OBJS_FLAGS) $(LIBS) $(PROF) -o $@ distclean: clean $(RM_REC) $(DEPDIRS) $(RM) build.rules config.h config.mak config.log clean: $(RM) $(OBJS) $(EXECUTABLE) .PHONY: all clean dist distclean .SUFFIXES: .cxx ifndef CXX_UPDATE_DEP_FLAG # If you use GCC, disable the above and enable this for intelligent # dependency tracking. CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d2" .cxx.o: $(MKDIR) $(*D)/$(DEPDIR) $(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o $(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d $(CAT) "$(*D)/$(DEPDIR)/$(*F).d2" >> "$(*D)/$(DEPDIR)/$(*F).d" $(RM) "$(*D)/$(DEPDIR)/$(*F).d2" .c.o: $(MKDIR) $(*D)/$(DEPDIR) $(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o $(ECHO) "$(*D)/" > $(*D)/$(DEPDIR)/$(*F).d $(CAT) "$(*D)/$(DEPDIR)/$(*F).d2" >> "$(*D)/$(DEPDIR)/$(*F).d" $(RM) "$(*D)/$(DEPDIR)/$(*F).d2" else # If you even have GCC 3.x, you can use this build rule, which is safer; the above # rule can get you into a bad state if you Ctrl-C at the wrong moment. # Also, with this GCC inserts additional dummy rules for the involved headers, # which ensures a smooth compilation even if said headers become obsolete. .cxx.o: $(MKDIR) $(*D)/$(DEPDIR) $(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o .c.o: $(MKDIR) $(*D)/$(DEPDIR) $(CXX) $(CXX_UPDATE_DEP_FLAG) $(CXXFLAGS) $(CPPFLAGS) -c $(<) -o $*.o endif # Include the dependency tracking files. We add /dev/null at the end # of the list to avoid a warning/error if no .d file exist -include $(wildcard $(addsuffix /*.d,$(DEPDIRS))) /dev/null # check if configure has been run or has been changed since last run config.mak: $(srcdir)/configure @echo "You need to run ./configure before you can run make" @echo "Either you haven't run it before or it has changed." @exit 1 install: all $(INSTALL) -d "$(DESTDIR)$(BINDIR)" $(INSTALL) -c -s -m 755 "$(srcdir)/stella$(EXEEXT)" "$(DESTDIR)$(BINDIR)/stella$(EXEEXT)" $(INSTALL) -d "$(DESTDIR)$(DOCDIR)" $(INSTALL) -c -m 644 "$(srcdir)/Announce.txt" "$(srcdir)/Changes.txt" "$(srcdir)/Copyright.txt" "$(srcdir)/License.txt" "$(srcdir)/README-SDL.txt" "$(srcdir)/Readme.txt" "$(srcdir)/Todo.txt" "$(srcdir)/docs/index.html" "$(srcdir)/docs/debugger.html" "$(DESTDIR)$(DOCDIR)/" $(INSTALL) -d "$(DESTDIR)$(DOCDIR)/graphics" $(INSTALL) -c -m 644 $(wildcard $(srcdir)/docs/graphics/*.png) "$(DESTDIR)$(DOCDIR)/graphics" $(INSTALL) -d "$(DESTDIR)$(DATADIR)/applications" $(INSTALL) -c -m 644 "$(srcdir)/src/unix/stella.desktop" "$(DESTDIR)$(DATADIR)/applications" $(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/16x16/apps" $(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/22x22/apps" $(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/24x24/apps" $(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/32x32/apps" $(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/48x48/apps" $(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/64x64/apps" $(INSTALL) -d "$(DESTDIR)$(DATADIR)/icons/hicolor/128x128/apps" $(INSTALL) -c -m 644 "$(srcdir)/src/common/stella-16x16.png" "$(DESTDIR)$(DATADIR)/icons/hicolor/16x16/apps/stella.png" $(INSTALL) -c -m 644 "$(srcdir)/src/common/stella-22x22.png" "$(DESTDIR)$(DATADIR)/icons/hicolor/22x22/apps/stella.png" $(INSTALL) -c -m 644 "$(srcdir)/src/common/stella-24x24.png" "$(DESTDIR)$(DATADIR)/icons/hicolor/24x24/apps/stella.png" $(INSTALL) -c -m 644 "$(srcdir)/src/common/stella-32x32.png" "$(DESTDIR)$(DATADIR)/icons/hicolor/32x32/apps/stella.png" $(INSTALL) -c -m 644 "$(srcdir)/src/common/stella-48x48.png" "$(DESTDIR)$(DATADIR)/icons/hicolor/48x48/apps/stella.png" $(INSTALL) -c -m 644 "$(srcdir)/src/common/stella-64x64.png" "$(DESTDIR)$(DATADIR)/icons/hicolor/64x64/apps/stella.png" $(INSTALL) -c -m 644 "$(srcdir)/src/common/stella-128x128.png" "$(DESTDIR)$(DATADIR)/icons/hicolor/128x128/apps/stella.png" install-strip: install $(STRIP) stella$(EXEEXT) uninstall: rm -f "$(DESTDIR)$(BINDIR)/stella$(EXEEXT)" rm -rf "$(DESTDIR)$(DOCDIR)/" rm -f "$(DESTDIR)$(DATADIR)/applications/stella.desktop" rm -f "$(DESTDIR)$(DATADIR)/icons/hicolor/16x16/apps/stella.png" rm -f "$(DESTDIR)$(DATADIR)/icons/hicolor/22x22/apps/stella.png" rm -f "$(DESTDIR)$(DATADIR)/icons/hicolor/24x24/apps/stella.png" rm -f "$(DESTDIR)$(DATADIR)/icons/hicolor/32x32/apps/stella.png" rm -f "$(DESTDIR)$(DATADIR)/icons/hicolor/48x48/apps/stella.png" rm -f "$(DESTDIR)$(DATADIR)/icons/hicolor/64x64/apps/stella.png" rm -f "$(DESTDIR)$(DATADIR)/icons/hicolor/128x128/apps/stella.png" # Special rule for M6502.ins, generated from m4 (there's probably a better way to do this ...) src/emucore/M6502.ins: src/emucore/M6502.m4 m4 src/emucore/M6502.m4 > src/emucore/M6502.ins # Special rule for windows icon stuff (there's probably a better way to do this ...) src/windows/stella_icon.o: src/windows/stella.ico src/windows/stella.rc windres --include-dir src/windows src/windows/stella.rc src/windows/stella_icon.o .PHONY: deb bundle test install uninstall stella-5.1.1/README-SDL.txt000066400000000000000000000006601324334165500151300ustar00rootroot00000000000000 Please distribute this file with the SDL runtime environment: The Simple DirectMedia Layer (SDL for short) is a cross-platform library designed to make it easy to write multi-media software, such as games and emulators. The Simple DirectMedia Layer library source code is available from: http://www.libsdl.org/ This library is distributed under the terms of the zlib license: http://www.zlib.net/zlib_license.html stella-5.1.1/README.md000066400000000000000000000015451324334165500142740ustar00rootroot00000000000000Stella is a multi-platform Atari 2600 VCS emulator which allows you to play all of your favourite Atari 2600 games on your PC. You'll find the Stella Users Manual in the docs subdirectory. If you'd like to verify that you have the latest release of Stella, visit the Stella Website at: [stella-emu.github.io](https://stella-emu.github.io) Enjoy, The Stella Team # Reporting issues Please check the list of known issues first (see below) before reporting new ones. If you encounter any issues, please open a new issue on the project [issue tracker](https://github.com/stella-emu/stella/issues) and / or in the corresponding [thread](http://atariage.com/forums/topic/259633-testing-the-new-stella-tia-core/) on AtariAge. # Known issues Please check out the [issue tracker](https://github.com/stella-emu/stella/issues) for a list of all currently known issues. stella-5.1.1/Readme.txt000066400000000000000000000005311324334165500147450ustar00rootroot00000000000000Stella is a multi-platform Atari 2600 VCS emulator which allows you to play all of your favourite Atari 2600 games on your PC. You'll find the Stella Users Manual in the docs subdirectory. If you'd like to verify that you have the latest release of Stella, visit the Stella Website at: https://stella-emu.github.io Enjoy, The Stella Team stella-5.1.1/Todo.txt000066400000000000000000000014771324334165500144670ustar00rootroot00000000000000=========================================================================== SSSS tt lll lll SS SS tt ll ll SS tttttt eeee ll ll aaaa SSSS tt ee ee ll ll aa SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" SS SS tt ee ll ll aa aa SSSS ttt eeeee llll llll aaaaa =========================================================================== To Do List =========================================================================== The main Todo list is now available directly from the main webpage: https://stella-emu.github.io/todo.html If you would like to contribute to Stella's development then feel free to contact me by email: Stephen Anthony (sa666666@gmail.com). stella-5.1.1/common.rules000066400000000000000000000021161324334165500153540ustar00rootroot00000000000000# Common build rules, used by the sub modules and their module.mk files # Copy the list of objects to a new variable. The name of the new variable # contains the module name, a trick we use so we can keep multiple different # module object lists, one for each module. MODULE_OBJS-$(MODULE) := $(MODULE_OBJS) MODULE_LIB-$(MODULE) := $(MODULE)/lib$(notdir $(MODULE)).a # If not building as a plugin, add the object files to the main OBJS list #OBJS += $(MODULE_LIB-$(MODULE)) OBJS += $(MODULE_OBJS) # Convenience library target #$(MODULE_LIB-$(MODULE)): $(MODULE_OBJS) # -$(RM) $@ # $(AR) $@ $+ # $(RANLIB) $@ # Pseudo target for comfort, allows for "make common", "make gui" etc. #$(MODULE): $(MODULE_LIB-$(MODULE)) # Clean target, removes all object files. This looks a bit hackish, as we have to # copy the content of MODULE_OBJS to another unique variable (the next module.mk # will overwrite it after all). The same for the libMODULE.a library file. clean: clean-$(MODULE) clean-$(MODULE): clean-% : -$(RM) $(MODULE_OBJS-$*) $(MODULE_LIB-$*) $(PLUGIN-$*) .PHONY: clean-$(MODULE) $(MODULE) stella-5.1.1/config.guess000077500000000000000000001255451324334165500153440ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2017 Free Software Foundation, Inc. timestamp='2017-12-17' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || \ echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "${UNAME_MACHINE_ARCH}" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} exit ;; *:MidnightBSD:*:*) echo ${UNAME_MACHINE}-unknown-midnightbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; *:Sortix:*:*) echo ${UNAME_MACHINE}-unknown-sortix exit ;; *:Redox:*:*) echo ${UNAME_MACHINE}-unknown-redox exit ;; mips:OSF1:*.*) echo mips-dec-osf1 exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; e2k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; k1om:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; mips64el:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-*:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-*:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; NSX-*:NONSTOP_KERNEL:*:*) echo nsx-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac echo "$0: unable to guess system type" >&2 case "${UNAME_MACHINE}:${UNAME_SYSTEM}" in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-functions 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: stella-5.1.1/config.sub000077500000000000000000001075241324334165500150040ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2017 Free Software Foundation, Inc. timestamp='2017-11-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pru \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | wasm32 \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pru-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | wasm32-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; asmjs) basic_machine=asmjs-unknown ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2*) basic_machine=m68k-bull os=-sysv3 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` os=$os"spe" ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; nsx-tandem) basic_machine=nsx-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; wasm32) basic_machine=wasm32-unknown ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; x64) basic_machine=x86_64-pc ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases that might get confused # with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -pikeos*) # Until real need of OS specific support for # particular features comes up, bare metal # configurations are quite functional. case $basic_machine in arm*) os=-eabi ;; *) os=-elf ;; esac ;; -nacl*) ;; -ios) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; pru-*) os=-elf ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-functions 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: stella-5.1.1/configure000077500000000000000000000442151324334165500147250ustar00rootroot00000000000000#!/bin/sh # # Some things this script could/should do when finished # # * detect whether it's a GNU compiler or not (for compiler settings) # * command line options to... # - override the host settings (for cross compiles # - whether to do a debug build (with -g) or an optimized build (-O3 etc.) # * detect whether the chosen backend is available (e.g. call sdl2-config) # * .... # use environment vars if set CXXFLAGS="$CXXFLAGS $CPPFLAGS" # default lib behaviour yes/no/auto _libpng=auto # default option behaviour yes/no _build_windowed=yes _build_sound=yes _build_debugger=yes _build_joystick=yes _build_cheats=yes _build_static=no _build_profile=no # more defaults _ranlib=ranlib _install=install _ar="ar cru" _strip=strip _mkdir="mkdir -p" _echo=printf _cat=cat _rm="rm -f" _rm_rec="$_rm -r" _zip="zip -q" _cp=cp _windowspath="" _sdlconfig=sdl2-config _sdlpath="$PATH" _prefix=/usr/local _srcdir=`dirname $0` # TODO: We should really use mktemp(1) to determine a random tmp file name. # However, that tool might not be available everywhere. TMPO=${_srcdir}/stella-conf TMPC=${TMPO}.cxx TMPLOG=${_srcdir}/config.log # For cross compiling _host="" _host_cpu="" _host_vendor="" _host_os="" _host_prefix="" cc_check() { echo >> "$TMPLOG" cat "$TMPC" >> "$TMPLOG" echo >> "$TMPLOG" echo "$CXX $TMPC $CXXFLAGS $LDFLAGS -o $TMPO$EXEEXT $@" >> "$TMPLOG" rm -f "$TMPO$EXEEXT" ( $CXX "$TMPC" $CXXFLAGS $LDFLAGS -o "$TMPO$EXEEXT" "$@" ) >> "$TMPLOG" 2>&1 TMP="$?" echo >> "$TMPLOG" return "$TMP" } cc_check_define() { cat > $TMPC << EOF int main(void) { #ifndef $1 syntax error #endif return 0; } EOF cc_check -c return $? } echocheck () { echo_n "Checking for $@... " } # # Check whether the given command is a working C++ compiler # test_compiler () { cat <tmp_cxx_compiler.cpp #include class Foo { int a; }; int main(int argc, char* argv[]) { std::shared_ptr a = std::make_shared(); return 0; } EOF if test -n "$_host"; then # In cross-compiling mode, we cannot run the result eval "$1 $CXXFLAGS $LDFLAGS -o tmp_cxx_compiler$EXEEXT tmp_cxx_compiler.cpp 2> /dev/null" && rm -f tmp_cxx_compiler$EXEEXT tmp_cxx_compiler.cpp else eval "$1 $CXXFLAGS $LDFLAGS -o tmp_cxx_compiler$EXEEXT tmp_cxx_compiler.cpp 2> /dev/null" && eval "./tmp_cxx_compiler 2> /dev/null" && rm -f tmp_cxx_compiler$EXEEXT tmp_cxx_compiler.cpp fi } # Add a line of data to config.mk. add_line_to_config_mk() { _config_mk_data="$_config_mk_data"' '"$1" } # # Determine sdl2-config # # TODO: small bit of code to test sdl useability find_sdlconfig() { echo_n "Looking for sdl2-config... " sdlconfigs="$_sdlconfig" _sdlconfig= IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="$SEPARATOR" done=0 for path_dir in $_sdlpath; do #reset separator to parse sdlconfigs IFS=":" for sdlconfig in $sdlconfigs; do if test -x "$path_dir/$sdlconfig" ; then _sdlconfig="$path_dir/$sdlconfig" done=1 break fi done if test $done -eq 1 ; then echo $_sdlconfig break fi done IFS="$ac_save_ifs" if test -z "$_sdlconfig"; then echo "none found!" exit 1 fi } # # Function to provide echo -n for bourne shells that don't have it # echo_n() { printf "$@" } # # Greet user # echo "Running Stella configure..." echo "Configure run on" `date` > $TMPLOG # # Check any parameters we received # for parm in "$@" ; do if test "$parm" = "--help" || test "$parm" = "-help" || test "$parm" = "-h" ; then cat << EOF Usage: $0 [OPTIONS]... Configuration: -h, --help display this help and exit Installation directories: --prefix=DIR use this prefix for installing stella [/usr/local] --bindir=DIR directory to install the stella binary [PREFIX/bin] --docdir=DIR directory to install documentation [PREFIX/share/doc/stella] --datadir=DIR directory to install icons/data files [PREFIX/share] Optional Features: --enable-sound enable/disable sound support [enabled] --disable-sound --enable-debugger enable/disable all debugger options [disabled] --disable-debugger --enable-joystick enable/disable joystick support [enabled] --disable-joystick --enable-cheats enable/disable cheatcode support [enabled] --disable-cheats --enable-windowed enable/disable windowed rendering modes [enabled] --disable-windowed --enable-shared build shared binary [enabled] --enable-static build static binary (if possible) [disabled] --disable-static --enable-profile build binary with profiling info [disabled] --disable-profile --force-builtin-libpng force use of built-in libpng library [auto] Optional Libraries: --with-sdl-prefix=DIR Prefix where the sdl2-config script is installed (optional) --with-libpng-prefix=DIR Prefix where libpng is installed (optional) --with-zlib-prefix=DIR Prefix where zlib is installed (optional) Some influential environment variables: LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags CPPFLAGS C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory EOF exit 0 fi done # for parm in ... for ac_option in $@; do case "$ac_option" in --enable-sound) _build_sound=yes ;; --disable-sound) _build_sound=no ;; --enable-debugger) _build_debugger=yes ;; --disable-debugger) _build_debugger=no ;; --enable-joystick) _build_joystick=yes ;; --disable-joystick) _build_joystick=no ;; --enable-cheats) _build_cheats=yes ;; --disable-cheats) _build_cheats=no ;; --enable-windowed) _build_windowed=yes ;; --disable-windowed) _build_windowed=no ;; --enable-shared) _build_static=no ;; --enable-static) _build_static=yes ;; --disable-static) _build_static=no ;; --enable-profile) _build_profile=yes ;; --disable-profile) _build_profile=no ;; --force-builtin-libpng) _libpng=no ;; --with-sdl-prefix=*) arg=`echo $ac_option | cut -d '=' -f 2` _sdlpath="$arg:$arg/bin" ;; --with-libpng-prefix=*) _prefix=`echo $ac_option | cut -d '=' -f 2` LIBPNG_CFLAGS="-I$_prefix/include" LIBPNG_LIBS="-L$_prefix/lib" ;; --with-zlib-prefix=*) _prefix=`echo $ac_option | cut -d '=' -f 2` ZLIB_CFLAGS="-I$_prefix/include" ZLIB_LIBS="-L$_prefix/lib" ;; --host=*) _host=`echo $ac_option | cut -d '=' -f 2` ;; --prefix=*) _prefix=`echo $ac_option | cut -d '=' -f 2` ;; --bindir=*) _bindir=`echo $ac_option | cut -d '=' -f 2` ;; --docdir=*) _docdir=`echo $ac_option | cut -d '=' -f 2` ;; --datadir=*) _datadir=`echo $ac_option | cut -d '=' -f 2` ;; *) echo "warning: unrecognised option: $ac_option" ;; esac; done; CXXFLAGS="$CXXFLAGS $DEBFLAGS" case $_host in #linupy) # _host_os=linux # _host_cpu=arm # ;; #arm-riscos-aof) # _host_os=riscos # _host_cpu=arm # ;; #ppc-amigaos) # _host_os=amigaos # _host_cpu=ppc # ;; gp2x) _host_os=gp2x _host_cpu=arm _host_prefix=arm-open2x-linux ;; mingw32-cross) _host_os=mingw32msvc _host_cpu=i386 _host_prefix=i386-mingw32msvc ;; *) guessed_host=`$_srcdir/config.guess` _host_cpu=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` _host_os=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` _host_vendor=`echo $guessed_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` ;; esac # # Determine extension used for executables # case $_host_os in mingw* | cygwin* |os2-emx*) EXEEXT=".exe" ;; arm-riscos-aof) EXEEXT=",ff8" ;; psp) EXEEXT=".elf" ;; gp2x) EXEEXT="" ;; *) EXEEXT="" ;; esac # # Determine separator used for $PATH # case $_host_os in os2-emx* ) SEPARATOR=";" ;; * ) SEPARATOR=":" ;; esac # # Determine the C++ compiler # echo_n "Looking for C++ compiler... " if test -n "$_host"; then compilers="$CXX $_host_prefix-g++ $_host_prefix-c++ $_host_cpu-$_host_os-g++ $_host_cpu-$_host_os-c++" else compilers="$CXX g++ c++" fi for compiler in $compilers; do if test_compiler "$compiler -std=c++14"; then CXX=$compiler echo $CXX break fi done if test -z $CXX; then echo "none found!" exit 1 fi # # Determine the compiler version echocheck "compiler version" have_clang=no cc_check_define __clang_version__ && have_clang=yes if test $have_clang = no; then cc_check_define __clang__ && have_clang=yes fi have_gcc=no cc_check_define __GNUC__ && have_gcc=yes if test "$have_clang" = yes; then clang_minor=$( $CXX -dM -E -x c /dev/null | grep __clang_minor__ | sed 's/.*\([0-9][0-9]*\).*/\1/' ) clang_patch=$( $CXX -dM -E -x c /dev/null | grep __clang_patchlevel__ | sed 's/.*\([0-9][0-9]*\).*/\1/' ) clang_major=$( $CXX -dM -E -x c /dev/null | grep __clang_major__ | sed 's/.*\([0-9][0-9]*\).*/\1/' ) cxx_version="$clang_major.$clang_minor.$clang_patch" is_xcode=$( $CXX -dM -E -x c /dev/null | grep __apple_build_version__ ) # Need at least version 8 if test -n "$is_xcode"; then cxx_name="XCode $cxx_version" if test $clang_major -ge 8; then cxx_version="$cxx_version, ok" cxx_verc_fail=no else cxx_version="$cxx_version, bad" cxx_verc_fail=yes fi else # Need at least version 3.5 if [ $clang_major -ge 4 ] || [ $clang_major -eq 3 -a $clang_minor -ge 5 ]; then cxx_version="$cxx_version, ok" cxx_verc_fail=no else cxx_version="$cxx_version, bad" cxx_verc_fail=yes fi # Only clang >= 5.0 supports extra warnings if [ $clang_major -ge 5 ]; then _make_def_CLANG_WARNINGS='CLANG_WARNINGS = 1' fi fi CXXFLAGS="$CXXFLAGS" _make_def_HAVE_GCC3='HAVE_GCC3 = 1' add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP' _make_def_HAVE_GCC='HAVE_GCC = 1' echo "$cxx_version" elif test "$have_gcc" = yes; then cxx_name=`( $cc -v ) 2>&1 | tail -n 1 | cut -d ' ' -f 1` cxx_version=`( $CXX -dumpversion ) 2>&1` if test "$?" -gt 0; then cxx_version="not found" fi case $cxx_version in 4.[7-9]|4.[7-9].[0-9]|4.[7-9].[0-9][-.]*|[5-9]|[5-9].[0-9]|[5-9].[0-9].[0-9]|[5-9].[0-9].[0-9][-.]*) _cxx_major=`echo $cxx_version | cut -d '.' -f 1` _cxx_minor=`echo $cxx_version | cut -d '.' -f 2` cxx_version="$cxx_version, ok" cxx_verc_fail=no ;; 'not found') cxx_verc_fail=yes ;; *) cxx_version="$cxx_version, bad" cxx_verc_fail=yes ;; esac CXXFLAGS="$CXXFLAGS" _make_def_HAVE_GCC3='HAVE_GCC3 = 1' add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MMD -MF "$(*D)/$(DEPDIR)/$(*F).d" -MQ "$@" -MP' _make_def_HAVE_GCC='HAVE_GCC = 1' echo "$cxx_version" else cxx_version=`( $CXX -version ) 2>&1` if test "$?" -eq 0; then cxx_version="`echo "${cxx_version}" | sed -ne 's/^.*[^0-9]\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*$/\1/gp'`" if test -z "${cxx_version}"; then cxx_version="not found" cxx_verc_fail=yes fi echo non-gcc compiler version ${cxx_version} else cxx_version="not found" cxx_verc_fail=yes echo found non-gcc compiler version ${cxx_version} fi CXXFLAGS="$CXXFLAGS" case $_host_os in irix*) case $cxx_version in 7.4.4*) # We just assume this is SGI MIPSpro _cxx_major=7 _cxx_minor=4 cxx_verc_fail=no add_line_to_config_mk 'CXX_UPDATE_DEP_FLAG = -MDupdate "$(*D)/$(DEPDIR)/$(*F).d"' add_line_to_config_mk '-include Makedepend' ;; *) cxx_version="$cxx_version, bad" cxx_verc_fail=yes ;; esac ;; *) cxx_version="$cxx_version, bad" cxx_verc_fail=yes ;; esac fi if test "$cxx_verc_fail" = yes ; then echo echo "The version of your compiler is not supported at this time" echo "Please ensure you are using GCC 5.0 / Clang 3.8 or above" exit 1 fi # # Do CXXFLAGS now we know the compiler version # if test -n "$_host"; then # Cross-compiling mode - add your target here if needed case "$_host" in mingw32-cross) echo "Cross-compiling for Windows using MinGW." DEFINES="$DEFINES -DWIN32" _host_os=win32 ;; *) echo "Cross-compiling to unknown target, please add your target to configure." exit 1 ;; esac else # # Determine build settings # # TODO - also add an command line option to override this?!? echo_n "Checking hosttype... " echo $_host_os case $_host_os in linux* | openbsd* | freebsd* | kfreebsd* | netbsd* | bsd* | gnu0.* | sunos* | hpux* | beos*) DEFINES="$DEFINES -DUNIX" _host_os=unix ;; darwin*) DEFINES="$DEFINES -DUNIX -DDARWIN" _host_os=darwin ;; irix*) DEFINES="$DEFINES -DUNIX" _ranlib=: _host_os=unix ;; mingw*) DEFINES="$DEFINES -DWIN32" _host_os=win32 ;; cygwin*) DEFINES="$DEFINES -mno-cygwin -DWIN32" LIBS="$LIBS -mno-cygwin -lmingw32 -lwinmm" _host_os=win32 ;; os2*) DEFINES="$DEFINES -DUNIX -DOS2" _host_os=unix ;; # given this is a shell script assume some type of unix *) echo "WARNING: could not establish system type, assuming unix like" DEFINES="$DEFINES -DUNIX" ;; esac fi # Cross-compilers use their own commands for the following functions if test -n "$_host_prefix"; then _strip="$_host_prefix-$_strip" fi # # Check for libpng # echocheck "libpng" if test "$_libpng" = auto ; then _libpng=no cat > $TMPC << EOF #include #include int main(void) { return printf("%s\n", PNG_HEADER_VERSION_STRING); } EOF cc_check $LDFLAGS $CXXFLAGS $LIBPNG_CFLAGS $LIBPNG_LIBS -lpng && _libpng=yes fi if test "$_libpng" = yes ; then _zlib=auto echo "$_libpng" else echo "none found, using built-in version" fi # # Check for ZLib # if test "$_zlib" = auto ; then echocheck "zlib" _zlib=no cat > $TMPC << EOF #include #include int main(void) { return strcmp(ZLIB_VERSION, zlibVersion()); } EOF cc_check $LDFLAGS $CXXFLAGS $ZLIB_CFLAGS $ZLIB_LIBS -lz && _zlib=yes if test "$_zlib" = yes ; then echo "$_zlib" else echo "zlib missing" exit 1 fi fi # # figure out installation directories # test -z "$_bindir" && _bindir="$_prefix/bin" test -z "$_docdir" && _docdir="$_prefix/share/doc/stella" test -z "$_datadir" && _datadir="$_prefix/share" echo echo_n "Summary:" echo if test "$_build_sound" = "yes" ; then echo_n " Sound support enabled" echo else echo_n " Sound support disabled" echo fi if test "$_build_debugger" = "yes" ; then echo_n " Debugger support enabled" echo else echo_n " Debugger support disabled" echo fi if test "$_build_joystick" = yes ; then echo_n " Joystick support enabled" echo else echo_n " Joystick support disabled" echo fi if test "$_build_cheats" = yes ; then echo_n " Cheatcode support enabled" echo else echo_n " Cheatcode support disabled" echo fi if test "$_build_windowed" = "yes" ; then echo_n " Windowed rendering modes enabled" echo else echo_n " Windowed rendering modes disabled" echo fi if test "$_build_static" = yes ; then echo_n " Static binary enabled" echo else echo_n " Static binary disabled" echo fi if test "$_build_profile" = yes ; then echo_n " Profiling enabled" echo else echo_n " Profiling disabled" echo fi # # Now, add the appropriate defines/libraries/headers # echo find_sdlconfig SRC="src" CORE="$SRC/emucore" COMMON="$SRC/common" TIA="$SRC/emucore/tia" TIA_FRAME_MANAGER="$SRC/emucore/tia/frame-manager" TV="$SRC/common/tv_filters" GUI="$SRC/gui" DBG="$SRC/debugger" DBGGUI="$SRC/debugger/gui" YACC="$SRC/yacc" CHEAT="$SRC/cheat" LIBPNG="$SRC/libpng" ZLIB="$SRC/zlib" INCLUDES="-I$CORE -I$COMMON -I$TV -I$GUI -I$TIA -I$TIA_FRAME_MANAGER" INCLUDES="$INCLUDES `$_sdlconfig --cflags`" if test "$_build_static" = yes ; then _sdl_conf_libs="--static-libs" LDFLAGS="-static $LDFLAGS" else _sdl_conf_libs="--libs" fi LIBS="$LIBS `$_sdlconfig $_sdl_conf_libs`" LD=$CXX case $_host_os in unix) DEFINES="$DEFINES -DBSPF_UNIX -DHAVE_GETTIMEOFDAY" MODULES="$MODULES $SRC/unix" INCLUDES="$INCLUDES -I$SRC/unix" ;; darwin) DEFINES="$DEFINES -DBSPF_UNIX -DHAVE_GETTIMEOFDAY -DOSX_KEYS" MODULES="$MODULES $SRC/unix" INCLUDES="$INCLUDES -I$SRC/unix" ;; win32) DEFINES="$DEFINES -DBSPF_WINDOWS -DHAVE_GETTIMEOFDAY" MODULES="$MODULES $SRC/windows" INCLUDES="$INCLUDES -I$SRC/windows" LIBS="$LIBS -lmingw32 -lwinmm" ;; *) echo "WARNING: host system not currently supported" exit ;; esac if test "$_libpng" = yes ; then LIBS="$LIBS -lpng" else MODULES="$MODULES $LIBPNG" INCLUDES="$INCLUDES -I$LIBPNG" fi if test "$_zlib" = yes ; then LIBS="$LIBS -lz" else MODULES="$MODULES $ZLIB" INCLUDES="$INCLUDES -I$ZLIB" fi if test "$_build_windowed" = yes ; then DEFINES="$DEFINES -DWINDOWED_SUPPORT" fi if test "$_build_sound" = yes ; then DEFINES="$DEFINES -DSOUND_SUPPORT" fi if test "$_build_debugger" = yes ; then DEFINES="$DEFINES -DDEBUGGER_SUPPORT" MODULES="$MODULES $DBG $DBGGUI $YACC" INCLUDES="$INCLUDES -I$DBG -I$DBGGUI -I$YACC" fi if test "$_build_joystick" = yes ; then DEFINES="$DEFINES -DJOYSTICK_SUPPORT" fi if test "$_build_cheats" = yes ; then DEFINES="$DEFINES -DCHEATCODE_SUPPORT" MODULES="$MODULES $CHEAT" INCLUDES="$INCLUDES -I$CHEAT" fi if test "$_build_profile" = no ; then _build_profile= fi echo "Creating config.mak" cat > config.mak << EOF # -------- Generated by configure ----------- CXX := $CXX CXXFLAGS := $CXXFLAGS LD := $LD LIBS += $LIBS RANLIB := $_ranlib INSTALL := $_install AR := $_ar MKDIR := $_mkdir ECHO := $_echo CAT := $_cat RM := $_rm RM_REC := $_rm_rec ZIP := $_zip CP := $_cp WINDOWSPATH=$_windowspath STRIP := $_strip MODULES += $MODULES MODULE_DIRS += $MODULE_DIRS EXEEXT := $EXEEXT PREFIX := $_prefix BINDIR := $_bindir DOCDIR := $_docdir DATADIR := $_datadir PROFILE := $_build_profile $_make_def_HAVE_GCC $_make_def_HAVE_GCC3 $_make_def_CLANG_WARNINGS INCLUDES += $INCLUDES OBJS += $OBJS DEFINES += $DEFINES LDFLAGS += $LDFLAGS $_config_mk_data EOF # This should be taken care of elsewhere, but I'm not sure where rm -f stella-conf* if test "$_host_os" = darwin; then cat < Wed, 21 Feb 2018 17:09:59 -0230 stella (5.1-1) stable; urgency=high * Version 5.1 release -- Stephen Anthony Sun, 4 Feb 2018 17:09:59 -0230 stella (5.0.2-1) stable; urgency=high * Version 5.0.2 release -- Stephen Anthony Sun, 20 Aug 2017 17:09:59 -0230 stella (5.0.1-1) stable; urgency=high * Version 5.0.1 release -- Stephen Anthony Sun, 23 Jul 2017 17:09:59 -0230 stella (5.0-1) stable; urgency=high * Version 5.0 release -- Stephen Anthony Sun, 16 Jul 2017 17:09:59 -0230 stella (4.7.3-1) stable; urgency=high * Version 4.7.3 release -- Stephen Anthony Mon, 21 Nov 2016 17:09:59 -0230 stella (4.7.2-1) stable; urgency=high * Version 4.7.2 release -- Stephen Anthony Fri, 25 Mar 2016 17:09:59 -0230 stella (4.7.1-1) stable; urgency=high * Version 4.7.1 release -- Stephen Anthony Sat, 13 Feb 2016 17:09:59 -0230 stella (4.7-1) stable; urgency=high * Version 4.7 release -- Stephen Anthony Mon, 25 Jan 2016 17:09:59 -0230 stella (4.6.7-1) stable; urgency=high * Version 4.6.7 release -- Stephen Anthony Wed, 28 Oct 2015 17:09:59 -0230 stella (4.6.6-1) stable; urgency=high * Version 4.6.6 release -- Stephen Anthony Sun, 11 Oct 2015 12:11:09 -0230 stella (4.6.5-1) stable; urgency=high * Version 4.6.5 release -- Stephen Anthony Fri, 25 Sep 2015 20:18:40 -0230 stella (4.6-1) stable; urgency=high * Version 4.6 release -- Stephen Anthony Fri, 20 Mar 2015 21:17:06 -0230 stella (4.5-1) stable; urgency=high * Version 4.5 release -- Stephen Anthony Thu, 01 Jan 2015 13:40:04 -0330 stella (4.2-1) stable; urgency=high * Version 4.2 release -- Stephen Anthony Tue, 28 Oct 2014 13:50:43 -0230 stella (4.1.1-1) stable; urgency=high * Version 4.1.1 release -- Stephen Anthony Sun, 14 Sep 2014 17:42:36 -0230 stella (4.1-1) stable; urgency=high * Version 4.1 release -- Stephen Anthony Mon, 01 Sep 2014 17:44:38 -0230 stella (4.0-1) stable; urgency=high * Version 4.0 release -- Stephen Anthony Tue, 01 Jul 2014 10:51:55 -0230 stella (3.9.3-1) stable; urgency=high * Version 3.9.3 release -- Stephen Anthony Sat, 18 Jan 2014 15:16:30 -0330 stella (3.9.2-1) stable; urgency=high * Version 3.9.2 release -- Stephen Anthony Sat, 31 Aug 2013 11:13:43 -0230 stella (3.9.1-1) stable; urgency=high * Version 3.9.1 release -- Stephen Anthony Wed, 21 Aug 2013 15:47:29 -0230 stella (3.9-1) stable; urgency=high * Version 3.9 release -- Stephen Anthony Thu, 27 Jun 2013 17:20:07 -0330 stella (3.8.1-1) stable; urgency=high * Version 3.8.1 release -- Stephen Anthony Sun, 03 Mar 2013 17:20:07 -0330 stella (3.8-1) stable; urgency=high * Version 3.8 release -- Stephen Anthony Thu, 21 Feb 2013 19:02:35 -0330 stella (3.7.5-1) stable; urgency=high * Version 3.7.5 release -- Stephen Anthony Sat, 22 Dec 2012 16:44:58 -0330 stella (3.7.4-1) stable; urgency=high * Version 3.7.4 release -- Stephen Anthony Wed, 31 Oct 2012 18:38:25 +0200 stella (3.7.3-1) stable; urgency=high * Version 3.7.3 release -- Stephen Anthony Fri, 26 Oct 2012 18:38:25 +0200 stella (3.7.2-1) stable; urgency=high * Version 3.7.2 release -- Stephen Anthony Sun, 10 Jun 2012 18:38:25 +0200 stella (3.7.1-1) stable; urgency=high * Version 3.7.1 release -- Stephen Anthony Fri, 8 Jun 2012 18:38:25 +0200 stella (3.7-1) stable; urgency=high * Version 3.7 release -- Stephen Anthony Fri, 1 Jun 2012 18:38:25 +0200 stella (3.6.1-1) stable; urgency=high * Version 3.6.1 release -- Stephen Anthony Fri, 30 Mar 2012 18:38:25 +0200 stella (3.6-1) stable; urgency=high * Version 3.6 release -- Stephen Anthony Fri, 16 Mar 2012 18:38:25 +0200 stella (3.5.5-1) stable; urgency=high * Version 3.5.5 release -- Stephen Anthony Sat, 4 Feb 2012 18:38:25 +0200 stella (3.5-1) stable; urgency=high * Version 3.5 release -- Stephen Anthony Thu, 29 Dec 2011 18:38:25 +0200 stella (3.4.1-1) stable; urgency=high * Version 3.4.1 release -- Stephen Anthony Sat, 11 June 2011 18:38:25 +0200 stella (3.4-1) stable; urgency=high * Version 3.4 release -- Stephen Anthony Sun, 29 May 2011 18:38:25 +0200 stella (3.3-1) stable; urgency=high * Version 3.3 release -- Stephen Anthony Fri, 12 Nov 2010 18:38:25 +0200 stella (3.2.1-1) stable; urgency=high * Version 3.2.1 release -- Stephen Anthony Wed, 25 Aug 2010 18:38:25 +0200 stella (3.2-1) stable; urgency=high * Version 3.2 release -- Stephen Anthony Fri 20 Aug 2010 18:38:25 +0200 stella (3.1.2-1) stable; urgency=high * Version 3.1.2 release -- Stephen Anthony Mon, 3 May 2010 18:38:25 +0200 stella (3.1.1-1) stable; urgency=high * Version 3.1.1 release -- Stephen Anthony Mon, 26 April 2010 18:38:25 +0200 stella (3.1-1) stable; urgency=high * Version 3.1 release -- Stephen Anthony Thu, 22 April 2010 18:38:25 +0200 stella (3.0-1) stable; urgency=high * Version 3.0 release -- Stephen Anthony Fri, 11 September 2009 18:38:25 +0200 stella (2.8.4-1) stable; urgency=high * Version 2.8.4 release -- Stephen Anthony Thu, 4 July 2009 18:38:25 +0200 stella (2.8.3-1) stable; urgency=low * Version 2.8.3 release -- Stephen Anthony Thu, 25 June 2009 18:38:25 +0200 stella (2.8.2-1) stable; urgency=low * Version 2.8.2 release -- Stephen Anthony Tue, 23 June 2009 18:38:25 +0200 stella (2.8.1-1) stable; urgency=low * Version 2.8.1 release -- Stephen Anthony Fri, 19 June 2009 18:38:25 +0200 stella (2.8-1) stable; urgency=low * Version 2.8 release -- Stephen Anthony Mon, 8 June 2009 18:38:25 +0200 stella (2.7.7-1) stable; urgency=low * Version 2.7.7 release -- Stephen Anthony Fri, 1 May 2009 18:38:25 +0200 stella (2.7.6-1) stable; urgency=low * Version 2.7.6 release -- Stephen Anthony Tue, 14 Apr 2009 18:38:25 +0200 stella (2.7.5-1) stable; urgency=low * Version 2.7.5 release -- Stephen Anthony Fri, 27 Mar 2009 18:38:25 +0200 stella (2.7.3-1) stable; urgency=low * Version 2.7.3 release -- Stephen Anthony Mon, 09 Feb 2009 18:38:25 +0200 stella (2.7.2-1) stable; urgency=low * Version 2.7.2 release -- Stephen Anthony Tue, 27 Jan 2009 18:38:25 +0200 stella (2.7.1-1) stable; urgency=low * Version 2.7.1 release -- Stephen Anthony Mon, 26 Jan 2009 18:38:25 +0200 stella (2.7-1) stable; urgency=low * Version 2.7 release -- Stephen Anthony Sat, 17 Jan 2009 18:38:25 +0200 stella (2.6.1-1) stable; urgency=low * Version 2.6.1 release -- Stephen Anthony Thu, 22 May 2008 18:38:25 +0200 stella (2.6-1) stable; urgency=low * Version 2.6 release -- Stephen Anthony Fri, 16 May 2008 18:38:25 +0200 stella (2.5.1-1) stable; urgency=low * Version 2.5.1 release -- Stephen Anthony Wed, 9 Apr 2008 18:38:25 +0200 stella (2.5-1) stable; urgency=low * Version 2.5 release -- Stephen Anthony Fri, 28 Mar 2008 18:38:25 +0200 stella (2.4.2-1) stable; urgency=low * Version 2.4.2 release -- Stephen Anthony Mon, 17 Sep 2007 18:38:25 +0200 stella (2.4.1-1) stable; urgency=low * Version 2.4.1 release -- Stephen Anthony Mon, 27 Aug 2007 18:38:25 +0200 stella-5.1.1/debian/compat000066400000000000000000000000021324334165500154300ustar00rootroot000000000000005 stella-5.1.1/debian/control000066400000000000000000000010671324334165500156410ustar00rootroot00000000000000Source: stella Section: games Priority: optional Maintainer: Stephen Anthony Standards-Version: 3.7.2 Build-Depends: debhelper (>= 5.0.0), libsdl2-dev Package: stella Architecture: any Depends: ${shlibs:Depends} Description: Atari 2600 Emulator for SDL2 The Atari 2600 Video Computer System (VCS), introduced in 1977, was the most popular home video game system of the early 1980's. This emulator will run most Atari ROM images, so that you can play your favorite old Atari 2600 games on your PC. . Homepage: https://stella-emu.github.io stella-5.1.1/debian/copyright000066400000000000000000000022211324334165500161620ustar00rootroot00000000000000This package was debianized first by Tom Lear on Thu, 7 Oct 1999 08:57:16 -0700. It was downloaded from Copyright Holder(s): Bradford W. Mott and the Stella Team License: Copyright (C) 1995-2010 Bradford W. Mott and the Stella Team This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL'. stella-5.1.1/debian/dirs000066400000000000000000000000101324334165500151050ustar00rootroot00000000000000usr/bin stella-5.1.1/debian/docs000066400000000000000000000001511324334165500151020ustar00rootroot00000000000000Announce.txt Changes.txt Copyright.txt README-SDL.txt Readme.txt docs/*.html doc/graphics/*.png Todo.txt stella-5.1.1/debian/rules000077500000000000000000000026321324334165500153150ustar00rootroot00000000000000#!/usr/bin/make -f # -*- makefile -*- # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 # These are used for cross-compiling and for saving the configure script # from having to guess our platform (since we know it already) DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) CFLAGS = -Wall ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CXXFLAGS += -O0 else CXXFLAGS += -O2 endif config.status: configure dh_testdir CXXFLAGS="$(CXXFLAGS)" ./configure --prefix=/usr --force-builtin-libpng build: build-stamp build-stamp: config.status dh_testdir $(MAKE) touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp -$(MAKE) distclean dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs $(MAKE) install DESTDIR=$(CURDIR)/debian/stella # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. binary-arch: build install dh_testdir dh_testroot dh_installchangelogs Changes.txt dh_installdocs dh_installmenu # dh_installman $(CURDIR)/debian/stella.6 dh_link dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install stella-5.1.1/debian/source/000077500000000000000000000000001324334165500155325ustar00rootroot00000000000000stella-5.1.1/debian/source/format000066400000000000000000000000151324334165500167410ustar00rootroot000000000000003.0 (native) stella-5.1.1/debian/watch000066400000000000000000000000701324334165500152600ustar00rootroot00000000000000version=3 http://sf.net/stella/stella-(.*)-src\.tar\.gz stella-5.1.1/docs/000077500000000000000000000000001324334165500137405ustar00rootroot00000000000000stella-5.1.1/docs/debugger.html000066400000000000000000002360341324334165500164220ustar00rootroot00000000000000 Stella Debugger
Stella

Release 5.1.1

Integrated Debugger

(a work in progress)


Contents


Features

The debugger in Stella may never be complete, as we're constantly adding new features requested by homebrew developers. However, even in its current form it's still quite powerful, and is able to boast at least one feature that no other 2600 debugger has; it's completely cross-platform.

Here's a (non-comprehensive) list of what the debugger can do so far:

  • Display registers and memory.
  • Dump state of TIA and RIOT, with things like joystick directions and NUSIZx decoded into English (more-or-less).
  • Change registers/memory, including toggles for flags in P register.
  • Single step/trace.
  • Breakpoints - break running program and enter debugger when the Program Counter hits a predefined address; you can set as many breakpoints as you want.
  • Conditional breakpoints - Break running program when some arbitrary condition is true (e.g. "breakif {a == $7f && c}" will break when the Accumulator value is $7f and the Carry flag is true, no matter where in the program this happens). Unlike the cond breaks in PCAE, Stella's are *fast*: the emulation will run at full speed unless you use lots of breakif's at the same time, or have a slow CPU.
  • Watches - View contents of a location/register before every debugger prompt.
  • Traps - Like breakpoints, but break on read/write/any access to *any* memory location. Traps can also be combined with conditions to become conditional traps.
  • Frame advance (automatic breakpoint at beginning of next frame) You can advance multiple frames with one command.
  • Rewind previous advance operations and undo rewinds.
  • Supports Distella 'configuration directives', which may be used to override automatic code/data determination in the disassembly. For now, the following directives are supported: CODE, GFX, PGFX, DATA, ROW. These directives can be entered at the debugger prompt, or (automatically) loaded and saved in configuration files.
  • Extensive disassembly support, both from the emulation core and with help from Distella. Where possible, the disassembly differentiates between code, player graphics and playfield graphics (ie, addresses stored in GRPx and PFx) and data (addresses used as an operand of a command). Code sections are also differentiated between actual code, and 'tentative' code (ie, areas that may represent code sections, but haven't actually been executed yet). Such tentative code is marked with a '*' symbol.
  • Supports visual representation of the bitmap data of graphics areas, as well as the ability to directly edit these areas in either hex or binary.
  • Support for DASM symbol files (created with DASM's -s option), including automatically loading symbol files if they're named romname.sym
  • Support for DASM list files (created with DASM's -l option), including automatically loading list files if they're named romname.lst
  • Built-in VCS.H symbols, if no symbol file is loaded.
  • Symbolic names in disassembly.
  • Symbolic names accepted as input.
  • Ability to generate DASM-compatible disassembly files (currently single-bank only) with all the features mentioned above.
  • Tab completion for commands, symbol names and functions.
  • Graphical editor for RIOT and extended RAM. Acts a lot like a spreadsheet. Input in hex, with displays for label/decimal/binary for currently-selected location.
  • GUI CPU state window.
  • Reset the 6502.
  • Start emulator in debugger (via command-line option "-debug").
  • Save CLI session to a text file.
  • Supports hex, decimal, and binary input and output almost everywhere. (disassembly is still hex).
  • Support for bank switching. You can see how many banks a cart has and the currently selected bank, and manually change banks.
  • Registers/memory that get changed by the CPU during debugging are highlighted when they're displayed.
  • Data sources for the CPU SP/A/X/Y registers, showing the resolved/source address of of load operands.
  • Scanline advance (like frame advance, break at beginning of next scanline).
  • TIA display is updated during step/trace, so we can see our scanlines being drawn as it happens. This isn't 100% perfect: unlike a real TIA, the one in Stella only updates when it's written to.
  • Graphical TIA tab, with register names and GUI buttons for various bits (e.g. click ENAM0 to turn it on).
  • GUI Disassembly window, scrollable, with checkboxes for breakpoints.
  • Script (batch) file support, including auto-running a script file named after the ROM image.
  • Saving the current debugger state to a script file (including breakpoints, traps, etc).
  • Built-in functions for use with "breakif", to support common conditions (such as breaking when the user presses Game Select...)
  • Patching ROM in-place.
  • Save patched ROM

Future planned features:

  • GUI for cheat codes (Cheetah and normal codes).
  • Perhaps 2 panes in the disassembly window (so you can see 2 parts of the code at once).
  • Add bookmark support to disassembly window.
  • More "special variables" for the expression parser.
  • Possibly a mini-assembler
  • Possibly support for recording and playing back input files, like MAME. This isn't a debugger feature per se, but it'll make it easier to reliably trigger a bug so you can debug it.
  • Various new GUI enhancements

How to use the Debugger

Pressing ` (aka backtick, backquote, grave accent) toggles the debugger on & off. When you exit the debugger, the emulation resumes at the current program counter, and continues until either a breakpoint/trap is hit, or the ` key is pressed again.

The main debugger window will look similar to the following (note that the letters here are for reference in the document below; they aren't actually present in the debugger):

For space reasons, the Prompt, TIA, I/O and Audio displays are split into 4 tabs, only one of which is visible at a time. You can use the mouse or keyboard to select which tab you want to view. Control/Cmd + Tab cycles between tabs from left-to-right, Shift + Control/Cmd + Tab cycles right-to-left. Pressing Tab (or Shift + Tab) cycles between widgets in the current tab (except for in the Prompt Tab, where 'tab' is used for something else).

You can also enter the debugger at emulator startup by use the 'debug' command on the command line, or alternatively within the ROM launcher in 'Power-on options':

  ; will enter the debugger before any instructions run
  stella -debug mygame.bin

  ; alternatively, you can use 'break' to accomplish the same thing
  ; $fffc is the 6502/6507 init vector. This command will break and enter the
  ; debugger before the first 6507 instruction runs, so you can debug the
  ; startup code:
  stella -break "*($fffc)" mygame.bin

Using the ` key will always enter the debugger at the end of the frame (for NTSC games usually scanline 262). This is because Stella only checks for keystrokes once per frame. Once in the debugger, you can control execution by stepping one instruction, scanline, or frame at a time (or more than one at a time, using commands in the prompt). You can also set breakpoints or traps, which will cause the emulator to enter the debugger when they are triggered, even if it happens in mid-frame.


Startup

At startup, the debugger automatically tries load a number of files which will provide additional information for the debugger and can make debugging more convenient.
  • "autoexec.script"
    Use this plain text file to define e.g. your own functions or settings. They will be loaded at startup for each ROM.

    The location of this file will depend on the OS as follows:

    Linux/Unix ~/.stella/autoexec.script
    Macintosh ~/Library/Application Support/Stella/autoexec.script
    Windows %APPDATA%\Stella\autoexec.script    or
    _BASEDIR_\autoexec.script (if a file named 'basedir.txt' exists in the application directory containing the full pathname for _BASEDIR_)

  • "<rom_filename>.script"
    In this ROM specific, plain text file you can store breaks, traps, watches etc. for future re-use. Use the "save" command to create this file using the current settings. You can also manually edit the file and add more commands.

  • "<rom_filename>.cfg"
    This file is described in Distella Configuration Files.

  • "<rom_filename>.lst"
  • "<rom_filename>.sym"
    If you provied the -l and -s parameters DASM will create these two files during assembly. Stella uses the file content to display the correct labels.

Note that all files are only accessed if you enter the debugger at least once during a program run. This means you can create these files, and not worry about slowing down emulation unless you're actively using the debugger.


Global Buttons

There are some buttons on the right top that always show up no matter which tab you are looking at. This is because these are the ones that are most frequently used.

The larger button at the left top (labeled '<') performs the rewind operation, which will undo the previous Step/Trace/Scan/Frame... advance, the smaller button at the left bottom (labeled '>') performs the unwind operation, which will undo the previous rewind operation. The rewind buffer is 100 levels deep by default, the size can be configured e.g. in the Developer Settings - Time Machine dialog.

The other operations are Step, Trace, Scan+1, Frame+1 and Exit (debugger).

You can also use the buttons from anywhere in the GUI via hotkeys.

Key Function
Control-s Step
Control-t Trace
Control-L Scan+1
Control-f Frame+1
Alt-Left arrow Rewind 1
Shift-Alt-Left arrow Rewind 10
Alt-Down arrow Rewind all
Alt-Right arrow Unwind 1
Shift-Alt-Right arrow Unwind 10
Alt-Up arrow Unwind all
Backquote (`) Exit

For MacOS use 'Cmd' instead of  'Alt' key.

To the left of the global buttons, you find the "Options..." button.

This opens the Options Menu which is described in detail in the User's Guide.


Change Tracking

The debugger tracks changes to the CPU, TIA and RIOT registers and RAM by displaying changed locations or registers with a red background after each step, trace, scanline, or frame advance. This sounds simple, and it is, but it's also amazingly useful.

One clarification about the change tracking: it only tracks when values have changed. If the ROM writes a value into a RAM location that already contained the same value, that's not considered a change (old value was $whatever, new value is the same, so nothing got tracked). This may change in a future version of Stella.


(A) Prompt Tab

This is a command-line interface, similar to the DOS DEBUG command or Supermon for the C=64.

Editing keys work about like you'd expect them to in Windows, but many Bash-style commands are also supported:

KeyFunction
HomeMove cursor to beginning of line
EndMove cursor to end of line
DeleteRemove character to right of cursor
BackspaceRemove character to left of cursor
Control-aSame function as 'Home'
Control-eSame function as 'End'
Control-dSame function as 'Delete'
Control-kRemove all characters from cursor to end of line
Control-uRemove all characters from cursor to beginning of line
Control-wRemove entire word to left of cursor
Shift-PgUpScroll up through previous commands one screen/page
Shift-PgDownScroll down through previous commands one screen/page
Shift-UpScroll up through previous commands one line
Shift-DownScroll down through previous commands one line
Shift-HomeScroll to beginning of commands
Shift-EndScroll to end of commands

You can also scroll with the mouse. Copy and paste is not yet supported.

To see the available commands, enter "help". For extended help, type "help cmd", where 'cmd' is the command you wish to know about. The available commands are listed in Prompt Commands at the end of this section. Bash-style tab completion is supported for commands, labels and functions (see below).

For now, there are some functions that only exist in the prompt. We intend to add GUI equivalents for all (or almost all?) of the prompt commands in future releases. People who like command prompts will be able to use the prompt, but people who hate them will have a fully functional debugger without typing (or without typing much, anyway).

Note: unlike the rest of the UI, whatever is shown in the prompt will not be updated during debugging and thus eventually become "stale". You can update it just by re-running the relevant commands in the prompt.


Tab Key Auto-Complete

While entering a command, label or function, you can type a partial name and press the Tab key to attempt to auto-complete it. If you've ever used "bash", this will be immediately familiar. If not, try it: load up a ROM, go to the debugger, type "g" (but don't press Enter), then hit Tab. The "g" will change to "gfx" (since this is the only built-in command starting with a "g"). If there are multiple possible completions (try with "tr" instead of "g"), you'll see a list of them, and your partial name will be completed as far as possible. After the first character, the autocompletion considers all characters in the right order as a match (e.g. "twf" will be completed to "trapwriteif").

Tab completion works on all labels: built-in, loaded from a symbol file, or set during debugging with the "define" command. It also works with built-in functions and those defined with the "function" command, but it doesn't (yet) work on filenames.


Expressions

Almost every command takes a value: the "a" command takes a byte to stuff into the accumulator, the "break" command takes an address to set/clear a breakpoint at. These values can be as a hex constant ($ff, $1234), or as complex as "the low byte of the 16-bit value located at the address pointed to by the binary number 1010010110100101" (which would be "@<\1010010110100101"). You can also use registers and labels in expressions.

You can use arithmetic and boolean operators in expressions. The syntax is very C-like. The operators supported are:

      + - * /  (add, subtract, multiply, divide: 2+2 is 4)
      %        (modulus/remainder: 3%2 is 1)
      & | ^ ~  (bitwise AND, OR, XOR, NOT: 2&3 is 2)
      && || !  (logical AND, OR, NOT: 2&&3 is 1, 2||0 is 0)
      ( )      (parentheses for grouping: (2+2)*3 is 12)
      * @      (byte and word pointer dereference: *$80 is the byte stored
                at location $80)
      [ ]      (array-style byte pointer dereference: $80[1] is the byte
                stored at location ($80+1) or $81)
      < >      (prefix versions: low and high byte. <$abcd is $cd)
      == < > <= >= !=
               (comparison: equality, less-than, greater-than, less-or-equals,
                greater-or-equals, not-equals)
      << >>    (bit shifts, left and right: 1<<1 is 2, 2>>1 is 1)

Division by zero is not an error: it results in zero instead.

None of the operators change the values of their operands. There are no variable-assignment or increment/decrement operators. This may change in the future, which is why we used "==" for equality instead of just "=".

The bitwise and logical boolean operators are different in that the bitwise operators operate on all the bits of the operand (just like AND, ORA, EOR in 6502 asm), while the logical operators treat their operands as 0 for false, non-zero for true, and return either 0 or 1. So $1234&$5678 results in $1230, whereas $1234&&$5678 results in 1. This is just like C or C++...

Prefixes

Like some programming languages, the debugger uses prefixed characters to change the meaning of an expression. The prefixes are:

  • Dereference prefixes:

    '*'
    Dereference a byte pointer. "*a" means "the byte at the address that the A register points to". If A is 255 (hex $ff), the result will be the value currently stored in memory location 255. This operator will be very familiar to you if you're a C or C++ developer. It's equivalent to the PEEK() function in most 8-bit BASICs. Also, the debugger supports array-like byte dereferences: *address can be written as address[0]. *(address+1) can be written as address[1], etc.

    '@'
    Dereference a pointer to a word. This is just like the "*" byte deref, except it refers to a 16-bit value, occupying 2 locations, in low-byte-first format (standard for the 6507).

    The following are equivalent:

             @address
             *address+$100**(address+1)
             address[0]+#256*address[1]
    		

    (TODO: add (indirect),y and (indirect,x) syntax)

  • Hi/Lo Byte Prefixes:

    '<'
    Take the low byte of a 16-bit value. This has no effect on an 8-bit value: "a" is equal to "<a". However, "<$1234" equals "$34".

    '>'
    Take the high byte of a 16-bit value. For 8-bit values such as the Accumulator, this will always result in zero. For 16-bit values, "<$1234" = "$12".

  • Number Base Prefixes:

    '#'
    Treat the input as a decimal number.

    '$'
    Treat the input as a hex number.

    '\'
    Treat the input as a binary number.

    These only have meaning when they come before a number, not a label or a register. "\1010" means 10 decimal. So do "$0a" and "#10". "a" by itself is always the Accumulator, no matter what the default base is set to.

    If you don't specify any number base prefix, the number is assumed to be in the default base. When you first start Stella, the default base is 16 (hexadecimal). You can change it with the "base" command. If you want to change the default base to decimal permanently, you can put a

          base #10
        
    command in your "autoexec.script" file (for details see Startup).

Remember, you can use arbitrarily complex expressions with any command that takes arguments.


Breakpoints, watches and traps, oh my!

Breakpoints

A breakpoint is a "hotspot" in your program that causes the emulator to stop emulating and jump into the debugger. You can set as many breakpoints as you like. The command is "break xx" where xx is any expression. If you've created a symbol file, you can use labels.

Example: you've got a label called "kernel". To break there, the command is "break kernel". After you've set the breakpoint, exit the debugger ("quit" or click the Exit button). The emulator will run until it gets to the breakpoint, then it will enter the debugger with the Program Counter pointing to the instruction at the breakpoint.

Breakpoints happen *before* an instruction is executed: the instruction at the breakpoint location will be the "next" instruction.

To remove a breakpoint, you just run the same command you used to set it. In the example, "break kernel" will remove the breakpoint. The "break" command can be thought of as a *toggle*: it turns the breakpoint on & off, like a light switch.

You could also use "clearbreaks" to remove all the breakpoints. Also, there is a "listbreaks" command that will list them all.

Conditional Breaks

A conditional breakpoint causes the emulator to enter the debugger when some arbitrary condition becomes true. "True" means "not zero" here: "2+2" is considered true because it's not zero. "2-2" is false, because it evaluates to zero. This is exactly how things work in C and lots of other languages, but it might take some getting used to if you've never used such a language.

Suppose you want to enter the debugger when the Game Reset switch is pressed. Looking at the Stella Programmers' Guide, we see that this switch is read at bit 0 of SWCHB. This bit will be 0 if the switch is pressed, or 1 otherwise.

To have an expression read the contents of an address, we use the dereference operator "*". Since we're looking at SWCHB, we need "*SWCHB".

We're only wanting to look at bit 0, so let's mask off all the other bits: "*SWCHB&1". The expression now evaluates to bit 0 of SWCHB. We're almost there: this will be 1 (true) if the switch is NOT pressed. We want to break if it IS pressed...

So we invert the sense of the test with a logical NOT operator (which is the "!" operator): !(*SWCHB&1). The parentheses are necessary as we want to apply the ! to the result of the &, not just the first term (the "*SWCHB").

"breakif !(*SWCHB&1)" will do the job for us. However, it's an ugly mess of letters, numbers, and punctuation. We can do a little better:

"breakif { !(*SWCHB & 1 ) }" is a lot more readable, isn't it? If you're going to use readable expressions with spaces in them, enclose the entire expression in curly braces.

Remember that Stella only checks for input once per frame, so a break condition that depends on input (like SWCHB) will always happen at the end of a frame. This is different from how a real 2600 works, but most ROMs only check for input once per frame anyway.

Conditional breaks appear in "listbreaks", numbered starting from zero. You can remove a cond-break with "delbreakif number", where the number comes from "listbreaks" or by entering the same conditional break again.

Any time the debugger is entered due to a trap, breakpoint, or conditional break, the reason will be displayed in the Breakpoint/Trap Status area.

Functions

There is one annoyance about complex expressions: once we remove the conditional break with "delbreakif" or "clearbreaks", we'd have to retype it (or search backwards with the up-arrow key) if we wanted to use it again.

We can avoid this by defining the expression as a function, then using "breakif function_name":

	function gameReset { !(*SWCHB & 1 ) }
	breakif gameReset

Now we have a meaningful name for the condition, so we can use it again. Not only that: we can use the function as part of a bigger expression. Suppose we've also defined a gameSelect function that evaluates to true if the Game Select switch is pressed. We want to break when the user presses both Select and Reset:

	breakif { gameReset && gameSelect }

User-defined functions appear in "listfunctions", which shows the label and expression for each function. Functions can be removed with "delfunction label", where the labels come from "listfunctions".

Built-in Functions

Stella has some pre-defined functions for use with the "breakif" command. These allow you to break and enter the debugger on various conditions without having to define the conditions yourself.

Built-in functions and pseudo-registers always start with an _ (underscore) character. It is suggested that you don't start labels in your game's source with underscores, if you plan to use them with the Stella debugger.

FunctionDefinitionDescription
_joy0left !(*SWCHA & $40) Left joystick moved left
_joy0right !(*SWCHA & $80) Left joystick moved right
_joy0up !(*SWCHA & $10) Left joystick moved up
_joy0down !(*SWCHA & $20) Left joystick moved down
_joy0button !(*INPT4 & $80) Left joystick button pressed
_joy1left !(*SWCHA & $04) Right joystick moved left
_joy1right !(*SWCHA & $08) Right joystick moved right
_joy1up !(*SWCHA & $01) Right joystick moved up
_joy1down !(*SWCHA & $02) Right joystick moved down
_joy1button !(*INPT5 & $80) Right joystick button pressed
_select !(*SWCHB & $02) Game Select pressed
_reset !(*SWCHB & $01) Game Reset pressed
_color *SWCHB & $08 Color/BW set to Color
_bw !(*SWCHB & $08) Color/BW set to BW
_diff0b !(*SWCHB & $40) Left difficulty set to B (easy)
_diff0a *SWCHB & $40 Left difficulty set to A (hard)
_diff1b !(*SWCHB & $80) Right difficulty set to B (easy)
_diff1a *SWCHB & $80 Right difficulty set to A (hard)

Don't worry about memorizing them all: the Prompt "help" command will show you a list of them.

Pseudo-Registers

These "registers" are provided for you to use in your conditional breaks. They're not registers in the conventional sense, since they don't exist in a real system. For example, while the debugger keeps track of the number of scanlines in a frame, a real system would not (there is no register that holds 'number of scanlines' on an actual console).

FunctionDescription
_bank Currently selected bank
_cclocks Color clocks on a scanline
_cycleshi Higher 32 bits of number of cycles since emulation started
_cycleslo Lower 32 bits of number of cycles since emulation started
_fcount Number of frames since emulation started
_fcycles Number of cycles since frame started
_icycles Number of cycles of last instruction
_rwport Last address to attempt a read from the cart write port
_scan Current scanline count
_scycles Number of cycles in current scanline
_vblank Whether vertical blank is enabled (1 or 0)
_vsync Whether vertical sync is enabled (1 or 0)

_scan always contains the current scanline count. You can use this to break your program in the middle of your kernel. Example:

    breakif _scan==#64

This will cause Stella to enter the debugger when the TIA reaches the beginning of the 64th scanline.

_bank always contains the currently selected bank. For 2K or 4K (non-bankswitched) ROMs, it will always contain 0. One useful use is:

    breakif { pc==myLabel && _bank==1 }

This is similar to setting a regular breakpoint, but it will only trigger when bank 1 is selected.

Watches

A watch is an expression that gets evaluated and printed before every prompt. This is useful for e.g. tracking the contents of a memory location while stepping through code that modifies it.

You can set up to 10 watches (in future the number will be unlimited). Since the expression isn't evaluated until it's used, you can include registers: "watch *y" will show you the contents of the location pointed to by the Y register, even if the Y register changes.

The watches are numbered. The numbers are printed along with the watches, so you can tell which is which. To delete a watch use the "delwatch" command with the watch number (1 to whatever). You can also delete them all with the "clearwatches" command.

Note that there's no real point in watching a label or CPU register without dereferencing it: Labels are constants, and CPU registers are already visible in the CPU Registers widget

Traps

A trap is similar to a breakpoint, except that it catches accesses to a memory address, rather than specific location in the program. They're useful for finding code that modifies TIA registers or memory.

Traps can also combined with a condition ("trapif"). If an access to a memory address is caught, the condition is evaluated additionally. Only if the condition is true too, the emulations stops. For details about conditions see Conditional Breaks described above.

An example: you are debugging a game, and you want to stop the emulation and enter the debugger whenever RESP0 is strobed. You'd use the command "trap RESP0" to set the trap, then exit the debugger. The emulator will run until the next time RESP0 is accessed (either read or write). Once the trap is hit, you can examine the TIA state to see what the actual player 0 position is, in color clocks (or you can in the future when we implement that feature in the TIA dump!)

Unlike breakpoints, traps stop the emulation *after* the instruction that triggered the trap. The reason for this is simple: until the instruction is executed, the emulator can't know it's going to hit a trap. After the trap is hit, the instruction is done executing, and whatever effects it may have had on e.g. the TIA state have already happened... but we don't have a way to run the emulated VCS in reverse, so the best we can do is stop before the next instruction runs.

Traps come in two varieties: read access traps and write access traps. It is possible to set both types of trap on the same address (that's what the plain "trap" command does). To set a read or write only trap, use "trapread(if)" or "trapwrite(if)".

All traps appear in "listtraps", numbered starting from zero. You can remove a trap with "deltrap number", where the number comes from "listtraps" or by entering the identical trap again. You can get rid of all traps at once with the "cleartraps" command.


Save your work!

Stella offers several commands to save your work inside the debugger for later re-use.

  • save: If you've defined a lot of complex functions, you probably will want to re-use them in future runs of the debugger. You can save all your functions, breakpoints, conditional breaks, traps and watches with the "save" command. If you name your saved file the same as the ROM filename and place it in the ROM directory, it will be auto-loaded next time you load the same ROM in Stella. The saved file is just a plain text file called "<rom_filename>.script", so you can edit it and add new functions, etc.

    Note: While "save" is ROM specific, you can also create a file called "autoexec.script" which will be loaded when the debugger starts, no matter what ROM you have loaded.

    See Startup for details.

  • saveconfig: The "saveconfig" command creates a DiStella Configuration File which is based on Stella's dynamic and static analysis of the current ROM.

    This will be automatically loaded the next time your start the debugger. From there on, you can continue analyzing the ROM and then use "saveconfig" again to update the configuration. You can also use "loadconfig" to load it manually.

    Note that this is not tested for multi-banked ROMs.

  • savedis: While your are playing or debugging a game, Stella will gather dynamic information about the ROM. It can then use that information together with a static analysis of the ROM and therefore create a better disassembly than DiStella alone. "savedis" allows you to save that disassembly as the result of this combined analysis.

    Note that this currently only works for single banked ROMs. For larger ROMs, the created disassembly is incomplete.

  • saverom: If you have manipulated a ROM, you can save it with "saverom". The file is named "<rom_filename>.a26".

  • saveses: The "saveses" command dumps the whole prompt session into a file named "<YYYY-MM-DD_HH-mm-ss>.txt". So you can later lookup what you did exactly when you were debugging at that time.

  • savestate: This command works identical to the save state hotkey (F9) during emulation. Any previously saved state can be loaded with "loadstate" plus the slot number (0-9).


Prompt Commands

Type "help" to see this list in the debugger.
Type "help 'cmd'" to see extended information about the given command.

                a - Set Accumulator to <value>
             base - Set default number base to <base> (bin, dec, hex)
            break - Set/clear breakpoint at <address>
          breakif - Set/clear breakpoint on <condition>
                c - Carry Flag: set (0 or 1), or toggle (no arg)
            cheat - Use a cheat code (see manual for cheat types)
      clearbreaks - Clear all breakpoints
      clearconfig - Clear Distella config directives [bank xx]
clearsavestateifs - Clear all savestate points
       cleartraps - Clear all traps
     clearwatches - Clear all watches
              cls - Clear prompt area of text
             code - Mark 'CODE' range in disassembly
        colortest - Show value xx as TIA color
                d - Decimal Mode Flag: set (0 or 1), or toggle (no arg)
             data - Mark 'DATA' range in disassembly
      debugcolors - Show Fixed Debug Colors information
           define - Define label xx for address yy
       delbreakif - Delete conditional breakif <xx>
      delfunction - Delete function with label xx
   delsavestateif - Delete conditional savestate point <xx>
          deltrap - Delete trap <xx>
         delwatch - Delete watch <xx>
           disasm - Disassemble address xx [yy lines] (default=PC)
             dump - Dump data at address <xx> [to yy] [1: memory; 2: CPU state; 4: input regs]
             exec - Execute script file <xx> [prefix]
          exitrom - Exit emulator, return to ROM launcher
            frame - Advance emulation by <xx> frames (default=1)
         function - Define function name xx for expression yy
              gfx - Mark 'GFX' range in disassembly
             help - help <command>
           joy0up - Set joystick 0 up direction to value <x> (0 or 1), or toggle (no arg)
         joy0down - Set joystick 0 down direction to value <x> (0 or 1), or toggle (no arg)
         joy0left - Set joystick 0 left direction to value <x> (0 or 1), or toggle (no arg)
        joy0right - Set joystick 0 right direction to value  (0 or 1), or toggle (no arg)
         joy0fire - Set joystick 0 fire button to value <x> (0 or 1), or toggle (no arg)
           joy1up - Set joystick 1 up direction to value <x> (0 or 1), or toggle (no arg)
         joy1down - Set joystick 1 down direction to value <x> (0 or 1), or toggle (no arg)
         joy1left - Set joystick 1 left direction to value <x> (0 or 1), or toggle (no arg)
        joy1right - Set joystick 1 right direction to value <x> (0 or 1), or toggle (no arg)
         joy1fire - Set joystick 1 fire button to value <x> (0 or 1), or toggle (no arg)
             jump - Scroll disassembly to address xx
       listbreaks - List breakpoints
       listconfig - List Distella config directives [bank xx]
    listfunctions - List user-defined functions
 listsavestateifs - List savestate points
        listtraps - List traps
       loadconfig - Load Distella config file
        loadstate - Load emulator state xx (0-9)
                n - Negative Flag: set (0 or 1), or toggle (no arg)
          palette - Show current TIA palette
               pc - Set Program Counter to address xx
             pgfx - Mark 'PGFX' range in disassembly
            print - Evaluate/print expression xx in hex/dec/binary
              ram - Show ZP RAM, or set address xx to yy1 [yy2 ...]
            reset - Reset system to power-on state
           rewind - Rewind state by one or [xx] steps/traces/scanlines/frames...
             riot - Show RIOT timer/input status
              rom - Set ROM address xx to yy1 [yy2 ...]
              row - Mark 'ROW' range in disassembly
              run - Exit debugger, return to emulator
            runto - Run until string xx in disassembly
          runtopc - Run until PC is set to value xx
                s - Set Stack Pointer to value xx
             save - Save breaks, watches, traps and functions to file xx
       saveconfig - Save Distella config file (with default name)
          savedis - Save Distella disassembly (with default name)
          saverom - Save (possibly patched) ROM (with default name)
          saveses - Save console session (with default name)
         savesnap - Save current TIA image to PNG file
        savestate - Save emulator state xx (valid args 0-9)
      savestateif - Create savestate on <condition>
         scanline - Advance emulation by <xx> scanlines (default=1)
             step - Single step CPU [with count xx]
        stepwhile - Single step CPU while <condition> is true
              tia - Show TIA state
            trace - Single step CPU over subroutines [with count xx]
             trap - Trap read/write access to address(es) xx [yy]
           trapif - On <condition> trap R/W access to address(es) xx [yy]
         trapread - Trap read access to address(es) xx [yy]
       trapreadif - On <condition> trap read access to address(es) xx [yy]
        trapwrite - Trap write access to address(es) xx [yy]
      trapwriteif - On <condition> trap write access to address(es) xx [yy]
             type - Show disassembly type for address xx [yy]
             uhex - Toggle upper/lowercase HEX display
            undef - Undefine label xx (if defined)
           unwind - Unwind state state by one or [xx] steps/traces/scanlines/frames...
                v - Overflow Flag: set (0 or 1), or toggle (no arg)
            watch - Print contents of address xx before every prompt
                x - Set X Register to value xx
                y - Set Y Register to value xx
                z - Zero Flag: set (0 or 1), or toggle (no arg)

(B) TIA Tab

When selected, this tab shows detailed status of all the TIA registers (except for audio; use the Audio tab for those).

Most of the values on the TIA tab will be self-explanatory to a 2600 developer.

Many of the variables inside the TIA can only be written to by the 6502. The debugger lets you get inside the TIA and see the contents of these variables. These include the color registers, player/missile graphics and positions, and the playfield.

You can control almost every aspect of the TIA from here, too: most of the displays are editable. You can even toggle individual bits in the GRP0/1 and playfield registers (remember to double-click).

The group of buttons labelled "Strobes" allows you to write to any of the strobe registers at any time.

The collision registers are displayed in decoded format, in a table. You can see exactly which objects have hit what. These are read-only displays; you can't toggle the bits in the current release of Stella. Of course, you can clear all the collisions with the CXCLR Strobe button.

To the right of each color register, you'll see a small rectangle drawn in the current color. Changing a color register will change the color of this rectangle.

Both player graphics registers (GRP0 and GRP1) come in two versions: a "new" and an "old" register. Writing GRP0 updates the value in the "new" version of GRP0 and, at the same time, copies the value in the "new" GRP1 register into its "old" counterpart. Writing to GRP1 behaves the same way, with the roles of GRP0 and GRP1 switched. The debugger shows both registers, the "old" register being located below the "new" one. If VDEL is off, the TIA displays the content of the "new" register, and the debugger tab reflects this by crossing out the old register. If VDEL is enabled, the TIA displays the "old" register, and the lines are removed in the tab.

The "enable ball" register (ENABL) also comes in a "new" and an "old" version. The content of "new" is copied into "old" on writes to GRP1, and VDELBL selects the register that is used to control the ball. This is visualized in the debugger in the same way as the two copies of GRP0 and GRP1

For many registers, writes don't take effect immediatelly as the TIA takes some color clocks to change state. In Stella's TIA core, this is implemented by queueing the writes, and the contents of this queue are visualized in the debugger in the "Queued Writes" area of the TIA tab.


(C) I/O Tab

When selected, this tab shows detailed status of the Input, Output, and Timer portion of the RIOT/M6532 chip (the RAM portion is accessed in another part of the debugger).

As with the TIA tab, most of the values here will be self-explanatory to a 2600 developer, and almost all can be modified. However, the SWCHx registers need further explanation:

SWCHx(W) can be modified; here, the (W) stands for write. Similarly, SWACNT/SWBCNT can be directly modified. However, the results of reading back from the SWCHx register are influenced by SWACNT/SWBCNT, and SWCHx(R) is a read-only display reflecting this result.


(D) Audio Tab

This tab lets you view the contents of the TIA audio registers and the effective volume resulting from the two channel volumes.

This tab will grow some features in a future release.


(E) TIA Display

In the upper left of the debugger, you'll see the current frame of video as generated by the TIA. If a complete frame hasn't been drawn, the partial contents of the current frame will be displayed up to the current scanline, with the contents of the old frame (in black & white) filling the rest of the display. Note that if 'phosphor mode' or TV effects are enabled, you won't see the effects here; this shows the raw TIA image only.

To e.g. watch the TIA draw the frame one scanline at a time, you can use the "Scan+1" button, the prompt "scan" command or the Control-L key.

You can also right-click anywhere in this window to show a context menu, as illustrated:

The options are as follows:

  • Fill to scanline: If you've already started a partial frame draw (ie, the frame is already partially 'greyed' out), selecting this option will draw all scanlines up to the vertical position where the mouse was clicked. Note that if you weren't in partial-frame mode, this option will have no effect.
  • Toggle breakpoint: Will toggle a conditional breakpoint at the scanline where the mouse was clicked. You can also use the Prompt Tab commands to list and turn off the breakpoint.
  • Set zoom position: Influences what is shown in the TIA zoom area (further described in TIA Zoom). The zoom area will contain the area centered at the position where the mouse was clicked.
  • Save snapshot: Saves the TIA image currently shown, including any current 'effects' (fixed debug colors, partial fill, etc).

(F) TIA Information

To the right of the TIA Display area, TIA information is displayed:

The indicators are as follows (note that all these are read-only):

  • Frame Count: The current frame number, since this ROM was loaded or reset.
  • Frame Cycle: The number of CPU cycles that have been executed this frame, since VSYNC was cleared at scanline 0.
  • Scanline: The scanline that's currently being drawn, and the count from the previous frame. Scanline 0 is the one on which VSYNC is cleared (after being set for 3 scanlines, as per the Stella Programmer's Guide)
  • Scan Cycle: The number of CPU cycles that have been executed since the beginning of the current scanline.
  • VSYNC & VBLANK: Self explanatory.
  • Pixel Pos: The current number of visible color clocks that have been displayed on the current scanline, starting from the beginning of the Horizontal Blank period. During HBLANK, this value will be negative (representing the number of clocks until the first visible one). Since there are 68 color clocks per HBLANK and 160 visible clocks per scanline, the Pixel Position will range from -68 to 159.
  • Color Clock: The current number of total color clocks since the beginning of this scanline's HBLANK. This counter starts at zero, but otherwise displays the same information as the Pixel Position (so Color Clock will always be 68 more than Pixel Position, and will range from 0 to 228).

(G) TIA Zoom

Below the TIA Information is the TIA Zoom area. This allows you to enlarge part of the TIA display, so you can see fine details. Like the TIA Display area, this one does generate frames as the real system would.

You can also right-click anywhere in this window to show a context menu, as illustrated:

These options allow you to zoom in on the image for even greater detail. If you click on the output window, you can scroll around using the cursor, PageUp/Dn and Home/End keys. You can also select the zoom position from a context menu in the TIA Display.


(H) Breakpoint/Trap Status

Below the TIA Zoom there is a status line that shows the reason and the address the debugger was entered (if a breakpoint or trap was hit), as shown:

The output here will generally be self-explanatory. Due to space concerns, the reason will be shown as follows:

  • "CBP:" for conditional breakpoints
  • "BP:" for normal breakpoints
  • "RTrap:" for read traps
  • "WTrap:" for write traps
  • "RTrapIf:" for conditional read traps
  • "WTrapIf:" for conditional write traps

See the Breakpoints, watches and traps... section for details.


(I) CPU Registers

This displays the current CPU state, as shown:

All the registers and flags are displayed, and can be changed by double-clicking on them (to the left). Flags are toggled on double-click. Selected registers here can also be changed by using the "Data Operations" buttons, further described in (J). All items are shown in hex. Any label defined for the current PC value is shown to the right. Decimal and binary equivalents are shown for SP/A/X/Y to the right (first decimal, then binary).

The column to the far right shows the 'source' of contents of the respective registers. For example, consider the command 'LDA ($80),Y'. The operand of the command resolves to some address, which isn't always easy to determine at first glance. The 'Src Addr' area shows the actual resulting operand/address being used with the given opcode.

There's not much else to say about the CPU Registers widget: if you know 6502 assembly, it's pretty self-explanatory. If you don't, well, you should learn :)


(J) Data Operations Buttons

These buttons can be used to change values in either CPU Registers, the M6532/RIOT RAM or Detailed Cartridge Extended RAM Information, depending on which of these widgets is currently in focus.

Each of these buttons also have a keyboard shortcut (indicated in square brackets). In fact, many of the inputboxes in various parts of the debugger respond to these same keyboard shortcuts. If in doubt, give them a try.

ButtonShortutDescription
0
'z'
Set the current location/register to zero.
Inv
'i' or '!'
Invert the current location/register (toggle all its bits)
Neg
'n'
Negate the current location/register (twos' complement negative)
++
'+' or '='
Increment the current location/register.
--
'-'
Decrement the current location/register.
<<
'<' or ','
Shift the current location/register left.
>>
'>' or '.'
Shift the current location/register right.

Any bits shifted out of the location/register with << or >> are lost (they will NOT end up in the Carry flag).


(K) M6532/RIOT RAM

This is a spreadsheet-like GUI for inspecting and changing the contents of the 2600's zero-page RAM.

You can navigate with either the mouse or the keyboard arrow keys. To change a RAM location, either double-click on it or press Enter while it's highlighted. Enter the new value (hex only for now, sorry), then press Enter to make the change. If you change your mind, press Escape and the original value will be restored. The currently selected RAM cell can also be changed by using the Data Operations Buttons or the associated shortcut keys.

The 'Undo' button in the upper right should be self-explanatory; it will undo the most previous operation to one cell only. The 'Revert' button is more comprehensive. It will undo all operations on all cells since you first made a change.

The UI objects at the bottom refer to the currently selected RAM cell. The 'Label' textbox shows the label attached to this RAM location (if any), and the other two textboxes show the decimal and binary equivalent value.

The remaining buttons to the right are further explained in the next section.

(L) M6532/RIOT RAM (search/compare mode)

The RAM widget also lets you search memory for values such as lives or remaining energy, but it's also very useful when debugging to determine which memory location holds which quantity.

To search the RAM, click 'Search...' and enter a byte value into the search editbox (0-255). All matching values will be highlighted in the RAM widget. If no value was entered, all RAM locations will be highlighted.

The 'Compare...' button is used to compare the given value using all addresses currently highlighted. This may be an absolute number (such as 2), or a comparative number (such as -1). Using a '+' or '-' operator means 'search addresses for values that have changed by that amount'.

The 'Reset' button resets the entire operation; it clears the highlighted addresses and allows another search.

The following is an example of inspecting all addresses that have decreased by 1:

  • Click 'Search...' and then 'OK' (no value entered). All address/values are highlighted
  • Exit debugger mode and lose a life, let your energy decrease, or do whatever it is you're trying to debug
  • Enter debugger mode again, click 'Compare...' and and enter a '-1' for input. This finds all values that have decreased by 1 (as compared to their current values)
  • Repeatedly following these steps may help to narrow number of addresses under consideration, and eventually you'll find the memory address you're looking for
  • Click 'Reset' when you're finished

(M) ROM Disassembly

This area contains a disassembly of the current bank of ROM. If a symbol file is loaded, the disassembly will have labels. Even without a symbol file, the standard TIA/RIOT labels will still be present.

The disassembly is often quite extensive, and whenever possible tries to automatically differentiate between code, graphics, data and unused bytes. There are actually two levels of disassembly in Stella. First, the emulation core tracks accesses as a game is running, making for very accurate results. This is known as a dynamic analysis. Second, the built-in Distella code does a static analysis, which tentatively fills in sections that the dynamic disassembler missed (usually because the addresses haven't been accessed at runtime yet).

As such, code can be marked in two ways (absolute, when done by the emulation core), and tentative (when done by Distella, and the emulation core hasn't accessed it yet). Such 'tentative' code is marked with the '*' symbol, indicating that it has the potential to be accessed as code sometime during the program run. This gives very useful information, since it can indicate areas toggled by an option in the game (ie, when a player dies, when difficulty level changes, etc). It can also indicate whether blocks of code after a relative jump are in fact code, or simply data.

The "Bank state" is self-explanatory, and shows a summary of the current bank information. For normal bankswitched ROMs, this will be the current bank number, however more advanced schemes will show other types of information here. More detailed information is available in Detailed Bankswitch Information.

Each line of disassembly has four fields:

  • Breakpoint: This is the area at the far left, to the left of the labels. Normally there will be nothing there: this indicates that there's no breakpoint set at that address. You can set and clear breakpoints by clicking in this area. When a breakpoint is set, there will be a red circle in this area. These are the same breakpoints as used by the break command, not the conditional "breakif" breakpoints (which makes sense: conditional breaks can break on any condition, the Program Counter isn't necessarily involved).
  • Labels: Any labels assigned to the given address, either generated automatically by Distella, read from a DASM symbol file or custom labels created by the user. If 'Show PC addresses' (see ROM Disassembly Settings) is enabled, the address will be shown in grey.
  • Disassembled bytes: This is either a standard 6502 mnemonic (possibly with operand), or information about graphics and/or data. For instructions, the cycle count will be included, separated by a semicolon. For graphics, a bitmap of the data, and the address of the data is included. For actual data, only the address is included.
  • Hex bytes: These are the raw machine bytes for the code/graphics/data. Note that only code, graphics or data will show bytes and can be edited.

At this point, we should explain the various 'types' that the disassembler can use. These are known as 'directives', and partly correspond to configuration options from the standalone Distella program. They are listed in order of decreasing hierarchy:

CODEAddresses which have appeared in the program counter, or which tentatively can appear in the program counter. These can be edited in hex.
GFXAddresses which contain data stored in the player graphics registers (GRP0/GRP1). These addresses are shown with a bitmap of the graphics, which can be edited in either hex or binary. The bitmap is shown as large blocks.
PGFXAddresses which contain data stored in the playfield graphics registers (PF0/PF1/PF2). These addresses are shown with a bitmap of the graphics, which can be edited in either hex or binary. The bitmap is shown as small dashes.
DATAAddresses used as an operand for some opcode. These can be edited in hex.
ROWAddresses not used as any of the above. These are shown up to 8 per line, and cannot be edited.

For code sections, the 6502 mnemonic will be UPPERCASE for all standard instructions, or lowercase for "illegal" 6502 instructions (like "dcp"). If automatic resolving of code sections has been disabled for any reason, you'll likely see a lot of illegal opcodes if you scroll to a data table in ROM. This can also occur if the disassembler hasn't yet encountered addresses in the PC. If you step/trace/scanline/frame advance into such an area, the disassembler will make note of it, and disassemble it correctly from that point on.

You can scroll through the disassembly with the mouse or keyboard. To center the display on the current PC, press the Space bar.

Any time the Program Counter changes (due to a Step, Trace, Frame or Scanline advance, or manually setting the PC), the disassembly will scroll to the current PC location.

Even though ROM is supposed to be Read Only Memory, this is an emulator: you can change ROM all you want within the debugger. The hex bytes in the ROM Widget are editable. Double-click on them to edit them. When you're done, press Enter to accept the changes (in which case the cart will be re-disasembled) or Escape to cancel them. Note that only instructions that have been fully disassembled can be edited. In particular, blank lines or 'ROW' directives cannot be edited. Also note that certain ROMs can have sections of address space swapped in and out dynamically. As such, changing the contents of a certain address will change the area pointed to at that time. In particular, modifying an address that points to internal RAM will change the RAM, not the underlying ROM. A future release may graphically differentiate between RAM and ROM areas.

ROM Disassembly Settings

The ROM Disassembly also contains a Settings dialog, accessible by right-clicking anywhere in the listing:

The following options are available:

  • Set PC @ current line: Set the Program Counter to the address of the disassembly line where the mouse was clicked (highlighted in green).
  • RunTo PC @ current line: Single-step through code until the Program Counter matches the address of the disassembly line where the mouse was clicked (highlighted in green)
  • Re-disassemble: Self-explanatory; force the current bank to be disassembled, regardless of whether anything has changed.
  • Show tentative code: Allow Distella to do a static analysis/disassembly.
  • Show PC addresses: Show Program Counter addresses as labels (where there isn't already a defined label).
  • Show GFX as binary: Switch between displaying/editing GFX and PGFX sections in either binary or hexidecimal.
  • Use address relocation: Corresponds to the Distella '-r' option (Relocate calls out of address range).

Limitations

  • The ROM Widget only works on ROM or zero-page RAM separately. If your game runs code from zero-page RAM, the disassembly will show addresses $80 to $FF (zero-page RAM address space) only. Once your RAM routine returns, the ROM Widget will switch back to ROM space ($1000 - $1FFF and mirrors). The same is true of the "disasm" command; it will show either ROM or RAM space, not both at the same time.
  • The standard VCS memory map has the cartridge port at locations $F000-$FFFF. However, not all the address lines exist on a 6507, so the cartridge port is "mirrored" at every other 4K chunk of address space ($1000, $3000, up to $D000). Some developers find it easier to think of the different banks of ROM as being at different addresses (such as: Bank 0 at $D000 and bank 1 at $F000). When such a ROM runs, the Program Counter can point to one of the mirrors instead of the main area at $F000. This is perfectly OK, and everything works just fine. However, breakpoints are set on actual addresses. If there were a breakpoint set at $F010, and the bank later switched to mirror $D000, the breakpoint will not be shown, and will not break on $D010, even though it's technically the same address.

These limitations will be addressed in a future release of Stella.


(N) Detailed Bankswitch Information

This area shows a detailed breakdown of the bankswitching scheme. Since the bankswitch schemes can greatly vary in operation, this tab will be different for each scheme, but its specific functionality should be self-explanatory. An example of both 4K (non-bankswitched) and DPC (Pitfall II) is as follows:

In many cases, quite a bit of the scheme functionality can be modified. Go ahead and try to change something!


(O) Detailed Cartridge Extended RAM Information

If applicable, this area shows a detailed breakdown of any extra RAM supported by the bankswitching scheme. Since the bankswitch schemes can greatly vary in operation, this tab will be different for each scheme, but its specific functionality should be self-explanatory. An example of both F8SC (8K Atari + ram) and DPC (Pitfall II) is as follows:

The RAM is shown in a grid similar to how zero-page RAM is shown in M6532/RIOT RAM (K) and (L). See those sections for a description of usage.

In the cases where RAM is always mapped into the same place in the cartridge address space (such as Sara-chip), the RAM addresses are labeled as such. In other cases, such as when the RAM is either quiescent (and mapped in at different places), or not viewable by the 6507 at all, the RAM addresses are labeled as the cart sees them. In the examples above, F8SC RAM is labeled starting at its read port, or $F080. However, the RAM in the DPC scheme is not viewable by the 6507, so its addresses start from $0.

Distella Configuration Files

As mentioned in ROM Disassembly, Stella supports the following directives: CODE/GFX/PGFX/DATA/ROW. While the debugger will try to automatically mark address space with the appropriate directive, there are times when it will fail. There are several options in this case:

  1. Manually set the directives: Directives can be set in the debugger prompt with the code/gfx/pgfx/data/row commands. These accept an address range for the given directive type. Setting a range with the same type a second time will remove that directive from the range.
  2. Use configuration files: Configuration files can be used to automatically load a list of directives when a ROM is loaded. These files can be generated with the 'saveconfig' command, and loaded with the 'loadconfig' command. There are also 'listconfig' and 'clearconfig' commands to show and erase (respectively) the current directive listing. Upon opening the debugger for the first time, Stella attempts to load a configuration file from several places. For this example, assume a ROM named "rr.a26", with properties entry "River Raid". Attempts will be made as follows:
    • ROM dir based on properties entry name: River Raid.cfg
    • ROM dir based on actual ROM name: rr.cfg
    • CFG dir based on properties entry name: configdir/River Raid.cfg

    The location of 'configdir' will depend on the OS as follows:

    Linux/Unix ~/.stella/cfg/
    Macintosh ~/Library/Application Support/Stella/cfg/
    Windows %APPDATA%\Stella\cfg\    OR
    _BASEDIR_\cfg\ (if a file named 'basedir.txt' exists in the application directory containing the full pathname for _BASEDIR_)


Tutorial: How to hack a ROM

Here is a step-by-step guide that shows you how to use the debugger to actually do something useful. No experience with debuggers is necessary, but it helps to know at least a little about 6502 programming.

  1. Get the Atari Battlezone ROM image. Make sure you've got the regular NTSC version. Load it up in Stella and press TAB to get to the main menu. From there, click on "Game Information". For "Name", it should say "Battlezone (1983) (Atari)" and for MD5Sum it should say "41f252a66c6301f1e8ab3612c19bc5d4". The rest of this tutorial assumes you're using this version of the ROM; it may or may not work with the PAL version, or with any of the various "hacked" versions floating around on the 'net.
  2. Start the game. You begin the game with 5 lives (count the tank symbols at the bottom of the screen).
  3. Enter the debugger by pressing the ` (backquote) key. Don't get killed before you do this, though. You should still have all 5 lives.
  4. In the RAM display, click the "Search" button and enter "5" for input. This searches RAM for your value and highlights all addresses that match the input. You should see two addresses highlighted: "00a5" and "00ba". These are the only two addresses that currently have the value 5, so they're the most likely candidates for "number of lives" counter. (However, some games might actually store one less than the real number of lives, or one more, so you might have to experiment a bit. Since this is a "rigged demo", I already know Battlezone stores the actual number of lives. Most games do, actually).
  5. Exit the debugger by pressing ` (backquote) again. The game will pick up where you left off.
  6. Get killed! Ram an enemy tank, or let him shoot you. Wait for the explosion to finish. You will now have 4 lives.
  7. Enter the debugger again. Click the "Compare" button in RAM widget and enter a value of 4. Now the RAM widget should only show one highlighted address: "00ba". What we did was search within our previous results (the ones that were 5 before) for the new value 4. Address $00ba used to have the value 5, but now it has 4. This means that Battlezone (almost certainly) stores the current number of lives at address $00ba.
  8. Test your theory. Go to the RAM display and change address $ba to some high number like $ff (you could use the Prompt instead: enter "ram $ba $ff"). Exit the debugger again (or advance the frame). You should now see lots of lives at the bottom of the screen (of course, there isn't room to display $ff (255) of them!)... play the game, get killed a few times, notice that you have lots of lives.
  9. Now it's time to decide what sort of "ROM hack" we want to accomplish. We've found the "lives" counter for the game, so we can either have the game start with lots of lives, or change the game code so we can't get killed (AKA immortality), or change the code so we always have the same number of lives (so we never run out, AKA infinite lives). Let's go for infinite lives: it's a little harder than just starting with lots of lives, but not as difficult as immortality (for that, we have to disable the collision checking code, which means we have to find and understand it first!)
  10. Set a Write Trap on the lives counter address: "trapwrite $ba" in the Prompt. Exit the debugger and play until you get killed. When you die, the trap will cause the emulator to enter the debugger with the Program Counter pointing to the instruction *after* the one that wrote to location $ba.
  11. Once in the debugger, look at the ROM display. The PC should be at address $f238, instruction "LDA $e1". You want to examine a few instructions before the PC, so scroll up using the mouse or arrow keys. Do you see the one that affects the lives counter? That's right, it's the "DEC $ba" at location $f236.
  12. Let's stop the DEC $ba from happening. We can't just delete the instruction (it would mess up the addressing of everything afterwards, if it were even possible), but we can replace it with some other instruction(s).

    Since we just want to get rid of the instruction, we can replace it with NOP (no operation). From looking at the disassembly, you can see that "DEC $ba" is a 2-byte long instruction, so we will need two one-byte NOP instructions to replace it. From reading the prompt help (the "help" command), you can see that the "rom" command is what we use to patch ROM.

    Unfortunately, Stella doesn't contain an assembler, so we can't just type NOP to put a NOP instruction in the code. We'll have to use the hex opcode instead.

    Now crack open your 6502 reference manual and look up the NOP instruction's opcode... OK, OK, I'll just tell you what it is: it's $EA (234 decimal). We need two of them, so the bytes to insert will look like:

        $ea $ea

    Select the line at address $f236 and enter 'ROM patch' mode. This is done by either double-clicking the line, or pressing enter. Then delete the bytes with backspace key and enter "ea ea". Another way to do this would have been to enter "rom $f236 $ea $ea" in the Prompt widget.

  13. Test your patch. First, set location $ba to some number of lives that can be displayed on the screen ("poke $ba 3" or enter directly into the RAM display). Now exit the debugger and play the game. You should see 3 lives on the screen.
  14. The crucial test: get killed again! After the explosion, you will *still* see 3 lives: Success! We've hacked Battlezone to give us infinite lives.
  15. Save your work. In the prompt: "saverom". You now have your very own infinite-lives version of Battlezone. The file will be saved in your HOME directory (NOT your ROM directory), so you might want to move it to your ROM directory if it isn't the current directory.
  16. Test the new ROM: exit Stella, and re-run it. Open your ROM (or give its name on the command line) and play the game. You can play forever! It worked.

Now, try the same techniques on some other ROM image (try Pac-Man). Some games store (lives+1) or (lives-1) instead of the actual number, so try searching for those if you can't seem to make it work.

If you successfully patch a ROM in the debugger, but the saved version won't work, or looks funny, you might need to add an entry to the stella.pro file, to tell Stella what bankswitch and/or TV type to use. That's outside the scope of this tutorial :)

Of course, the debugger is useful for a lot more than cheating and hacking ROMs. Remember, with great power comes great responsibility, so you have no excuse to avoid writing that game you've been thinking about for so long now :)

stella-5.1.1/docs/graphics/000077500000000000000000000000001324334165500155405ustar00rootroot00000000000000stella-5.1.1/docs/graphics/cheat.png000066400000000000000000000070671324334165500173440ustar00rootroot00000000000000PNG  IHDRn6lsRGBgAMA aPLTE@@@hhhb4ɯ|j pHYsodtEXtSoftwarepaint.net 4.0.19ֲd IDATx^흋z8F❫. a$0 #A9A] zh^x<x<bO1S JO *w=VpXE!Jy'[v!OfHxON*vz~bIO+:z7 V5iM5^jv:ÞiX2Ko={j[;eCFwɸ'$by1IHNW*2I{,,2yn̓jbQOj(+f@s8Rs/sZO8:ۮwo  nKYn=y') ­X$V9>YC@ɬ'j=Wxf4 <bO1<8W ߀AXM/@O -OS )߿x^\A8w'{tiƺw'{S b0 Vu*lleֽiSK6^/RR**- O$dE,z I>p)@'s*'=AgyCT\ AnΪܺ)2Rx`sֽ†ٗlڜ;O '#W[,"a Gb"Cy'oWyZm5PPéVAɃ=Yu]429>zr9p<z7yi"O$O0&&gx$]A=<<<@ɞ݅trŐQ&1 6Ȝ|ĿًBzC)#E:YA4yO"{)VVdO~ O\TOx6d" ga6zxcz+ɞN H~׼qu ^ xzRO ?tfQ{jLEidO^-i3M<k.Eq'꺲= '#vrNQߤ7=FSZEgQ?.g|WF$ 7yV{:΢6Q9E(&%|1}{53H5b7PUȂE6AuM2j^sNYOQ4y@GyŽTU% |KBR 4}Ժ7t\mj%ۘC&?q#zr"q(Oq'*ko5 MɍɍkJOLtOG{q1z2|s !ܬoFtM ܅}*X>z>K`OQ t?~q=/e7bO1S )x<bO1S )x<bO1S )x<bO1 {#|"XE#d;/{yܓO}!<4<(En,=a{SǷ Oה3>Ou=mN]SN>DxfV#|"bO1S )x<Ӟƪ=Ƭ'SXcyY/L}xbO1S )xqax<=x<b@!8]< O1&xz.iO1Њ&xz."X)'xWlKOUzJOS )x<bO1S )xZaO*t}9B~ xZзx<bQ^ܴYz*?a Txcr&`*О3C$|)D=Լ@*vVÞ7 Хe w; UADʋUE'""Q4CSm-E-ׂ6"tR9NY~zޔ@-oyKP$>C=d:0tlm/vBrEPodٲ`M&39wFo~^xg;?>K 4kk___[n6PǼo &5Fbז V6`k5?{OO?oOh|%{? A:#af RZ oh/a3*7G_0g7Gko6ܴ6Vm8twv24 8!.nET?Ap 0?s4?vޕٟ [.6hI$f]'^3 Wyi#E0ㅤVѷ7?F~AOwo;!`bj-4}iiZ nc&P*8@QNng`m64w,61]4f܃hkW7GKyHtjԱuho|o6a7nb4q5=Ì d`ߗڕ,ٟzst08Xߺ9b$hj?}C4ouN+GWƃտWX [O' ?~k)sMf^޶k$ͷRx?9g_9p@آ%%jaC& #͂ԃ"V1L6{c 9Y`4ޯBoogiw>䓏zD!6׿`@ {O2GG/ ح'$ B͛#onNMZA>}L>oԸ~d*$]_-0w Hͤ{z2}bmM8Amo{[7 Y9t!qm#jB|ْfc?  C(ԲG[l`}u3F~9zs#ѽopp.XŦZ/!_PFE~;*ZD R$Z%u7Czg>zs m/&=\W~(4|p+MozSKOh4TORhiyHO-En^9X1C)/8:0XF{|,(DOV *}4r`5)WT$&V3`B֤VO|Hzrfd$r6ʍ %"$&DaWCWnI@0UzM@"T՚LHMsu[&=HcHьϼ$,=Li7sG cx?.1Kk>'I/b_׾/Qޕ/9~o?R!z0`vQf5 {o!b6  : :`ϻ0j=!%cCox=˧z"=UH!i{tT}B0h2Sp7Sѳ!5,8Btl\P-`52z衇Bm&E rWBܯ~]t%힆 7`{u֖e y8Jf?U#F]A R옝:2.X՞K z 5la0uD1a6`C[n>l"vo `Շ>!FcW_9|s&w6]_IWqԩh_!ZiMk,- +!xsAnXK/ e^R0GVi G|A =yj G 86u_BnӀU! JpLc÷pajбG}4h}_dG@ q_~eůAL9A @T;u]>>k: Cn{C~khAA`Yoh>olλX)2ک?*`'`+(j`탖g=xĶ4SIcSۢPz<0Ϋ0y2˲Ѹ'۟hi|~5;,H cP:˛d+f"c?:"d+#}{%n62}}kvO=2Нl|3`aV^顏ݶ' ĈAADju Ll .DDqG"1cM/5+qr4=I@mWeOR"@0aBhw2s4a _e0P;EaY{b0&՚tw#l0$zOrp (O>$$굀fr;=Z5ˁxu{]}k_{Mj oLn}ت?[FOhqvCCLh@"lm1Sn.#.nb: ?R1Ŗ:uE$m k18I9~z.Ηzьsă6T(uwB5焎`dφ٭[( w&B7bi0f(!BZ:FHkHͫxpi߈$nq_~<䩎*МoƇ1HբC^zji#]ڣ.w8l7*`vCW,LmR̐mvCNIDn3nWdqhZmeHR4w#)A74*c_h`#k/);ZUW-%Ӌc,fx5 ^DY59]8Xo ;q R~+WM4*5q/AZ6Um.DYٮ0 ĎTX.|I6D)h#{m ֱH'!!Nc ʬH4g[+xQBP9>xUold6L*F曈yCdm,oVkImW8uHTMIX,!en$ MǍ!+2VB;UO<ѳV0n䒨ho{5o hRH/B-!&48`r"1&oB՛TyfF?!{#W!' GyIhNۢZ_F<04vGMu|_Co9)׃XF"[3yڿِcG]=,gڟ@l\{otC= =TP,"Tb 6G} p|d,0՟6 *PQfvjYm"'ɷVB-{mP_&'t '{}[}r>" )W3ΆgD[ fvƯ^I+FZv׻3đ\#ȑh2Zw#ųF$-SX+Q e%5.\>Wi,8BVGBD0+<:fpƳ_a\ Ѽ''Bw[SFQhѺ+:1y/e!r*\4ͭS4y~|~mSgfhgtl/`I<]^X5K>K5ߐ+>`S%$vyܐSč2!Fg1fĬvl7~?}'?&:gy%"VHT֒Z%XQChC B!bEe4v@FT6N=:&S!~v\Gx3 өO?LQd'4 -G'K8=v%Ӳ4x1 6j2wg`-8& Sd(*;߀-zAǰ(g :daޱFFU ,X  ZFEǧXh /bAK ZZ~ DbTko~'Q=bFT` cU (5yV{=Wihf¹n ` <`Ёa7CF3i!; m!0S{w33+*sh:e_X4%T(0h(PE^ws@EB _U]Ŧ/XDzE6X ~ᅭXVemwϊo9aKtu2-Ś{WNhACO?tɒ `jO!UmMPnێWc+4VpZ2Ϟ `m,r\# k`$4\틤-r`%iNGgA嘏_euc!Mj9|$a):оp7Ў02 D4Dd*E%O}Sf Z-1goDHɪ`dzE]%R %VY+K`k^H<> 䩛]e–*X'OO-h 5X1\i`5}W; TYRNygzgۯ H!q+DL TY7-gOO%`UTߞ]-ym0&κ8aXY&6šn.wpUf 8i)-J{=ޟ:„|՛C.!mXO>$EC7Gwc~ⷾ 6;4f^zSSCZ( ދ݊*/ok*bR=_Yte[E|q^9N_"Š _UtKƦMXUZU_=T8UQ{oj uNP0m'jst؟ ђR.k2nFA]:ۖ-32X,l)Se>ܼVpe(n,gшg)*oL?pWAiW&G.v#IjpZVI^ YC@6iwRm6X-P{߮%w `Ki?=tsJru裏"!9uBm~/B]# gOqA+i}5rQqSQ<V팕N~fX {Sn)u70dQDߧ~gKZ =gC5m;r00j&OB8@APe^,ۿS)| H8V2' ?ʗJ9)ԯbiڃ-V@Gц#$S̓~uzHg^} |&-#<"@SO=eE0f7䡇"w}5.bM6 yA[8 u;d#H)6M yB(m*,eͷ=qIڤNz?ފ¢-qB6A!AXVPb*\I_LWh /$3s&A upzJ7ށd]*sir d]R8ZTϭL$\įظl%nm>@K7WH T ömqYEmoaD+b0Z 1HH *gq8];*z`#vsK)A,Ǥ*$WC-٭V??o |ߨ.?H^:@x(ٗuʫۆzYFKPb*!:d(yf@͡SCr5Zjbڑ 9/8 % MoRNh|@%V(Jfs^Ij@KkMlAc;77ܒQ޹\~5a0峕Jkt%Qя>b$жVzn~fyUv:XA`<f|u>acz6c"qא<̹ΎmiZP [ D)X~#Str>e d!DYeO(HۑLU#R SCo1qN}ڢN; }`xճ!>ED8z,F}Uؒ\M>ncVD˲jE<_G Ã%uO3ִi(l#0U?9;67*qA_&nfPV]I9H Ut1U[>XlH7O|n٧y1+pzЖR0C7&Vp1Tc%h4 Cf52"|DVK?$hLmH`S:b0+&IQHPh5F$bŒg|{wt:-]ǁb͖ u.}ءBtWy$y*Ͱv. K݉Qb斤,q/!aڹ|m<3`ɾOj}]8W"Bk0A"GT{}u07lbSSk%A,|M 8=kD~. anxRݭܵ&!2uOJ3$%^Wj%.-Pw'J /)6m7nmglK3$j{ɫc+`w2]%oCW[y6mXdb޻lyIJELzZò+\X>UFw]wT(#UcwtD65Q@,Ex@n?9KL-471Xŏfue:}:mѝ57_ )žY>O^%=r&|^8*cbhG&| 5I WeNt P+8+h~ Rjg=>M|C!  U֝Z0mH_AwW.y TE%׼浯}- Xzg}mՈxեd1QI'7WձŒ{Ĩ\wWG`>3?c.?t${ƫ>wv'==paS\:d= "NJ_(8nzkfj1@11̶FҰjGF^Bz ߵWŢ#@??G+!(03vemvd+[d:0K"R+-$L1@BfPZ^ RE/l0>0|%=H{dxϡ<{𒫤hݺ#mgؖȝ\iI7,;vr+}'ѫ? I[(&)R~ʼL;+Юu˪߲;k8s }#'6O: ?!"uA-, 3I$YcX+2|~b Qmy0Q͂?D.~@_44ޑȳL|gG]O elAa&)::'U k,{jdJgyE]5fMECQ,jJ>p ¨ƫ/(׽d|꾫p"1(!^ *ͽMjlFV%D^:[IpN|Q°5c XdiE]q%C 4-|UqL(A7,/WJ4sa/R/70_8L][JB+idwVkM?j,֕~Hg cg?;?=QUzqc"U,Muy&Z5#8φʴÞM|P JI\:*89W8.KvY=Ge<t5gheruI74i%U<<\O`:'y>+glx̰]O1R` Y~in&lY5"EE\Hy''_9=Y_N~}'fu$GO8&K =q,B6V`鸾rgEP$Yc6kXbKQ-E9,`OdX{UEd2C=t _;)`LK`ZVfz:|&ئN9!k W8b>5vπdx->(u\{!sFͲ -ܔ0GH,6pe@ْ-}j@Es[?wai@?:|ñtUMQ27b;3aAzL';5yj|w .;v'Mʨ-K`6΂YXv)c4:!,DhJ:" -:%f "'qr +` Yr&-vA8jݸ ع<{fuU|>29P2SGmj+ ҂"@pvE1B;%Ä.fltX\sFl2 4™4 Ḿ.+ܞ{X͞| :o*}bۚ YWuESjğGkc\F~-Rit D]&][eg };Cك1T@=kLVof7:we $% $Bz  60 ùBmfMDK&apgb(< ;+qʹ?sptv*xUg!X+`8-VZ?铧0Hm%`RciOH GƩMS'+;ښl3J,˛ʾ j 63xz,PNmRq>Q#,zGS ]/r}A-\c3}:ƠcE'KƈH KB7+|ާɇNkCXQ8;g9bTrMW~7yFvN[ᙟV>)JƎuH]̭: snvYsdB-YsLwCYc*}R@r' h ŪB&KLKZe—n+NT\Lx0XoFiHp>ݛ2A^A~KtN>IEh%}_#huF{m+hiD "e,Y~'[ܙAZbk:]_<),39Epi;[@g9Pd=+拴o_htXܤ$nҁTe,$ y=A>_Q0he=#RO U|u) ;;JҾ̢ʒ9fG'7 3?5*΂uwsx<*}vz]n}߷6,cx|p.X~κm}̓VO`sğMrn!BGTXkR3<+䪛3qr;׳|-͌YriFt[2sEcmS

ebiVf['N=Q@=Ldc;n\d-hP5tgNrc)*oRUzF9k\_BYk#bݳ.Y\]aŞVcvm`!OB ܓO>&<q FMX)#1DVcxE`.^d>z\pv*`3V]nr*}l 2hS R[9| n?’4j6Zw$Pbk -VzW:Tqir$E׺d:+wuN,dsr,tk _g̻D([Oߛ*{-FT{WWS{Ds:sF5S?3BA70Mo:X8 L:}4b¬NϨ f1 f Rv;nc ڢeVi/Ȣ0̙ҬX#^su9y&V<l@'VI=ٝG OO~cus?s]1/c fgcqs?Q7M~aYKosםUGƖ] We-lWUIhQgcOԧIR˷L.4p%@ϞkJ/g.׽u??OADiS$Q^zgy7u+rb0挐:i)\'=L7t)o@O/RO>kuVMBl[M@P逡drb Ɇ)`!jo>:Zz/81 YZck)==ze7.2cgf}M"xCm=Yh'[?"kg9CD.Q#]۳l< ܂~}C\]#bJV-oy&3j0{ϱx)="5jDm*=/:H˟ v$ Lkqу,Jh{>qs|sS&o_T~I]ѻ<_u! O=B"pf&N.&RkE CsXvC;*rR L}g@xz]s SY  +Mh[eYnJ՚v:h5aZ6e~[ W#znS#QWd`$]G? Yt3i?ESv8#/u^Wh&Zl_ k+_ ;'vŒJ׌Sn=վvJZ):bBkD{% )Q plH?䌢]U$s&kDRpXnf~MS7Ef Jԫ{UYpYCq|p"x|NjHv*Ћ{U@` ;(4 _"6ơH|O>FK-8Ԏ̸ R9/,o|KZIR"&{qن xgp0yX'D*}9HgDYΧ_׺aWQ/n8___]Dg>Ц^yS/õ`k+c>8YD#d4;f7?2vS8VotU9|]0mFS`ȒHa$̥lDk.CM;7μU KsBݯ4&/nCAeV٫/"].Ң_m;+L1N{i4w\@֮HŁ-ڬxHjsK,chpmZ UgY'H_"XUHq`N 4gy1smwyT )>-{6P?vޛO^0AҮH䬄;rzh@b`}ɹ@DzIN VMZ V2q\K"~ӅR vsOL꬜Cm@ݿ"B::i AՖ%_ْ=S!7ړn^qa3*jIյzAչ(j$g,YdBO[4J8IzoED]\i&ެߩ+oO͗˵p8m?僳U<XrAWOf^$FwqGcu 6-oyhp}wg: 6gU*!Jstkw>+BAhȀ_|hfB0}35eI*>W*Of\l_2W3zD[TXV#-Hokeik{UAj8O#2-+-ZilHZ wҫ/̏?OBK7GKUv'|v]㸸 .+Ͱj'(]7:6"a#+'Zv$yB7FN|+_^t cn0†#me % I_Vz$.qW`GZX6Dٜ,6ްn  J֎B֔Hj5u70XtPCFc}7i0"43R }s\RʲH[gqEV[|Tn ikS\DWKO `PQ$mM 'yvޖ IJUfcob/+W͖ Tv_ IٔA| kT*z{[ =8 9s& xjۯ-)ӭ* nMB5!k2QJ`I.zNl}D]5 b]s/q lmp6lDų(=V oiO׀xRMq,y{$F95NlW!yJ3'N:a"vA-,"`qWzB[VĨxŊr"sOk5ExXl4Jk<-3| Z ALLxiO P"74* pz-!\P s[ .عmD-^ٯ"dz-Q 98˔i_r>zbo~u[lĺRKjIQZILU6f# Y?fߝIay{$a*H^vҲF؄{ I+ЅMd SZ6]딥s>a V;#*)v$u`]h9~Cn,9E /M8 %Td}ܝ7}C}*uX/_B?nA(V "m8zh#<16{>"WsqU B0&>;hy&bT%jqS/io .H[\IA^74 R ~t'4`x$R rw`itղ)-v3U/e3Nw9\RMa^XʳbF(Q4jsyj¢[XbB0n B ‘cC-ACHl q(9}I#P^9h-2*Mq__qss#HK5NVwz8uR+}!]l5s=O/rjt9 '.[ARz^`rf fjaZ4{τj3ʮP_ RF`wNe 7ԶieY Łج۸Tt> #c0BFF |yZYnqvΰD5`$ꪮ+4^Eh+EעbXvV0r҄w6}L#.c&3yK$Էu' Ki>j ͍3 > Mt٣ cio5(\CLC͵ڧ3?./,AOHPyU~@OCЫ/VR e ,M w;O$@jOaeNfx `-dڈ /[BAĂOǜNyᇛM*(~H'kO-T`{Tƞf+3Doh<@P4˾^bwE(P)!k(rm#D*v8$EܟaC獸?-9W_r4I.o1/b~`x~ N3O:mGH4SFkj(ps&|F$aͪ\}:BS/^eUݧەtejU~uRƊC}QK!p+$8ZKv7mDAנ}Ń&MFN[D VG2g5ugH>ڤV ֐@,p0G}FVt) fݶQ:te WnZ mKc'hM^J4n.,$8`󁸚$,hq7%`s = !tpՌHObEļMf@եK,Akg8 :yöY[ގD^N-Qc {ğ) ݑ{ %TcLkWȄ¯GTBShvXDtdi풻K!KdL]W+ܫ%|VJkی1 V!3(o/u_ӰZ&v:0{ ngs3=|r\z7>6D׋"p.RB-Z Z-Σ]XW"?[ w}wA/{[>|ma~5Ł"_~:@`11G!$ 4$ώa2ܕEnSV.>/3fذ_y"'i j<1 l A6Uݣ /UʜKci A)>hCJ^ε }?I/V-+]_O[sX6ӋA01ys^ - x!NQO\pkjj݉ih:s-`$sޡ3$[:Hk77GSA 9QԇߔqU@XZeIDM75, Ěgi}Ev^H:u$H\lUJ.16Nd d Yh=ܓ$t 9MpSsWq0a:[ /n]Zų>ۆJOF1 u'ݯ0b^}3y'&|6h/ߛ|xy!]6DLr)BLꄡGj\t#6 E B#u뱉fmqLau4!xl byTjnOs%g\jYs]tC6_*S0$N>Ǣ3% +$OZV0UZ-*P.VX&Apѱ8U墷~{za"f!JWnnE65w.?|;-~և=-|Y;{nz-iO̒7$>|5D矐Lf @ff'kO1md'!BۅKl@ }mn#C||5Uz3OIو-\Wg2 hҚ:m(ҁeJJx/!HΎȲbw:4ћQiDz Du1Sm*Ite@+﶑3bJ$gIbjݚ<,D0mYyʜ縊σ[Xe6!yOZns'{HXChRS?"/mdvץ٭Z2O#@Ps>|#CIyX !iً+%: qohAC@hTGef[e< HY.\+Aن;(>]ᢨ!17]jL j{gB̐g8b') X}$r8 A Nxgp> W,B/ڔ|db w$THnر9Q+V+WYX;1,*`T=h퓝4&M`7Y97`TU",m_f٥'];I>_ۗ$ SƜ.&'\p$-"_6D>;Cֶ]iC$ ֪G\QViv:IںʛDPG na*iKFp[SGRa o⇻3!97 f ݖI5&NP D/ym'iHpm% k: Fx)T͗* O$¹hYJ+y fΦ'dPdu\UҟOS^QX / lr(+Z~_H,k[G¡6)(CnAՖ:iz؂=3j*m`X 1U__YޠbJZ/>C; K (WlaDu7fB[3|IlZ16Txs U!K6G`*>O*`] ÊuUBu=>R/ڪӛR_jzw}3j3 &If-Y NJDC^Hhl(*4ǧ6b2Hd%d"@v2V*$"Bsص es^{i601ԪF8$F)Gt^[uMO*XkLRYX~aȟEcJAٷk|ql>h;~pZ`۠ > uRǝ%߲sd8;i"/~|S0XA7%gImMmS3GBW0ߨB^"SɛC%e{\% d3Q#,UI#  5'q(-D6 10xӸT Pt~x0w!Ms ʭDj&F09ՑƬ`q_9@cWڔu)@SJ[clOQ<45aSDN`$v+WmP 4N5wo ^WsEUxby}ݪ%.* [wgk~\B \6شF[kJ|61߾( Fam$m8K`z9Ge[ܤ*F*x[6;[V7/;]wbz,|0ŋu ^pB"o~OHhl Z @uMz=\G<`q[VrG|3{3w@%ڝ0Pj/լVۘV*h!̖Z`_ML۲$ݏExlỤ2E)~׻&cK{ɷH5e*Vi,#A\WHgɽTތ-S]ZN,)"RD$tC('?Y'֖F!"M޵M)V{Ő˿U@< 'Du q lN9ZvE{?-*?88jsI- .ٰBt1:Id]s"~xεH8зE@(KG': uC̚C->Ikذ K_ ު'm#q!Qr^!խ}jkz)@3DPYL"Md\N/'vv. [eQMضޭG׿j xo+2;x<^w xap>uSkV: ͅ_eOԌ=\==]Wc,Y;$.ѦY#AM3Y\V*tODh*PҴovu >9N$uMK"P'TVfW ~t5}`&Q,BrL&sTi.)f$E ui鶆yC/!ЉI kUAh_U!VI$V.qo} p#;P*")|5+$i۟V {N@ZW/Qj0 'fQZ,(h.hx\C+lBԤ~/ W i䐘˄=D<2$uJFb~k|k_Jl pn)*y݆jlGd!D@s}X^5K3di4{wt C ]jOP`b(?6J ,$\uNm )X5HAk> 4@J,VUD癛èW٢{Cy}o# aEFj]X. ^pZ z7 TSW{{fqS)^4K VooE $RKRvU-QJ2c1\natM0$ Ez+LE׮q',TO`q 6 fpI8_xiE 6D7 vQel2'fV3JՉ?"'ॴL,O DɽFAb-4;kTR16R /° f3j%яi&kXoB5I(S>!AM<}wGsxa .'7ރvbRd$KjDI"}"d%7-( EVG\J\t)*tSVEkဨMZ>}2U%tsDE;u*p[6W;ZGBS^6R`+Nq*9JbKhm|v>ęXPME($LCeI݄5!sAVbcub&V%g8'lD 0gS݌*d[ @P-3p#"FԆh<>V8gTQ@*1$׾+z\ XNʎ^( a:SS{)_B|i$7ǣO͋W8*oNEZf۲_7 3-r7[ S^ Ns b2حKhx6>e+ql" r|cKΛh jY,#>Aj=Ӽ~th0ɑ4<a`)< ֲ2槟~Dӯ^b⻮Anu"kˎJKAIDvU%%4n7zZImd}2y;Ԥ3tM YW=s?hRq_H}H>yCY!C &wy(HHwZ v_7^9x/.]]Z87C*"W/ D|:))D}d 89Y2Ip􊀴 ˆ"#^Uų|xڿW[D`1'z\mOn|AV[~"!RE~IVOjEHيk{ak4CY J,"Hk8範T/KXA9+xBYCSpumڎnVIIE ~EfGAEC$pNK&H/Vם:*+Muer*|2JKL`Bedpp" 9yI4LB7Wq9f )wJ޷kMmm(]WE:t[$,QRu#pu*/]YGOWq~n FI-k?,¶my23q`L6~OqCVJӖz oPס*=&NrDaw XQe9PUTa/o3\yu ԡ|U >ڀMHu2eߔegQ Bg/ de$zWEe8cA665UGm)Voxo9x7ě[nf -/rH_U怙oV$ώWvTѨB=[؆ʠƘUAw"jwqɨ!_q&UѺ̩ T4 ʷzzt9X(N2!`@o VPHlW?a:ȇ׫Q§}N>j GxBЎ67#u5MZ* 6rU_K )%oj Il*o'jZZQ c|WZ01D2|ݪ %+`Ce0iiD`j[w Xozu̺GUa aU+sbK%sdⅶ!uo2`S Z/ђKV $i"/iI.Aɶz>*s!+L8s%ImW[w]>VQBR׺꘨:c'9u 6uAЮ:J75@>#̣[(k D(zTcvEq KTϱM52zJ:F8v[klJ;mpHl29YƀEqWk#@Ԛ\#KtfpH ]wݵǒ"E5nbj*"ĽHi]x"`r-{}=0@;6d ė2䦭  sЀyI4Ql'^~;ZonjĽZgWLs6MUAVүWQē1fn%9^0Q Gl}Y4kz UP_(FP pv%eaY||Bv9薪"XTSm14T5dbpcՋ(*, X{jc^#|10?2&Dk0P.m^O}?)؃2-+3,ÐFi[PYCnkWSL-y%)z?Khcoְnm}\jI@cD͜JFYV빶ZXlН x:0ng5֦ͷjj9Fڳ˿4)$bS LY%I$5k(1tMhGZYm5)]=.F۲zCwɔ~Ig<6D` Z=>XfĺRѯ +V뀛Pp_$ZoZhf~3 $l]C/֢뜸`=s/i] GbT;02WN}o`a_VH ylg$5HZӫ=$ e-ЍA$;آ;fM$Hrԥd#WΫY]iv͵gEoHgӠ&F)|\<_"t(DAyV6zuz5(0,P)Uk;XL2iJ*/$V)&T UDc^q UdԹJ^i d 3lI1Kc4aA@H XB00"C_0I$Eo*u`r`6CP *e8CJ@”@{&YJtLC2ĉghz6x eJVð1]#b8io} eAcbt֛ 3\sâ%=R5IHզ%1K, cݡϴ(Q99 `"/j;s0G(S jK*yUV#4^277+}:&ʗ1?~`!zΒ%,wku826>htqFh=17D#G ͑۠ċBRQ2|Bq- 1WZsk{d87{ײBtH|Fe_EkkK[ 7/!S,n=}_zP.Ww]G|w0f$EE0~MA. khxذ*pΞ:A#+$4@-]r5b|t Ocx0~jUEyE'f>^#_*Lc=ICK/ jJebpmzJf2@f'KdӕHlVDK1-0oa0+K^eR`}{s7k&qthYa#iFW/ l!R'*+ǖZtbcFǟpaIw=P+*>goyqbm&, )(Rz=0-b=2 S4abޑ gC8XY^:N\j>yvOPl;'Z/i3 ~HcHq&͜k'&?T:U>㥗^%X;BTv2ϝWYFw=f#6H4Ҹ8*_tM:.uJd"r DGv"Ḃzs`Ў P'$3fqT뱼n4*'$&S,սR/!꬘UtUez^0>AUNA1= ʮWEU.%wxym11EOkKm"FŘ'pǥܸKxu Z` &|NOIUiDa*ˉ-P-oy 鲉ԫ!|]M^]`l13 0Z j=hD0Gp pی ~'J=6vumCb$. xE 8G;M,EB)/ϴ~SCyۚ rh NU>?[e#h0PB@+JUoݢő\0x|j68ROzݶsBqt֜~&[:S(fD Z$>՞??|]tgIB}NgSiJ:!Ta5S!ܒI@ ZiYiVGg0F/f5|J[ў]EK3R2Xz-Rkk!O+ ܫڊMrN||'>%X z5Do59 5Y65$@ov?O>m ƀ:I\u][/\iSPaF@Z&$^ nGLcʫ6 ɝnIg(}M^^"h9 WI"N '^2; "i>m '1_Kv h=(?8[7Mx;ZӧS╃k[qܞXW:+)Ⲩ^;땂HmseLb4%'ʟ_-&[LWA*ƌ'"!t*~N"3M:hPv}CTc=s5 ‰dW3.$kx:*ҕy4^e"08IRQWRU[?w3+Zw/v(mV8x Pv[,6~$z"ۈĮ$nl8tWNDNiCz^*yI.9xn-cVgT&&pyAP$Ige&6UϪ?%B5%* Rκ;{] _Op3OEqRW W]\1ͨ3do\="9}6V|]<=齟QgԙPz3!Y $JxQKZ!3qf{[i` Nb7E;Nc֩[^<ԓfʞY"=S~;/SJQIW a};h).\  k qy\pw^61jD_7|5![nV\2_U'kA~9.a{7to(PxJ[6]<)ZYk(AP[`#x6rjj*(}ؒuC@{&#Zr ¼]Df ę,&pK $L @+N* OeF?#֣'^:UZ Ҝ&`1QnCXQN 8SdQ"A)|ScA$Iۺ쨟r#JgKaxH(h*ShƉE-0+EĬ<2W\W,"ts_,b1x)ʡMZ➎A qJ(6Rj$*/?DvC HaI0 >r}M['2Z@i9Ng]xΫ^~Zb жRҐ&(&x<_r.fL<4hɪg|z1KH_[ØYAtGG箃O?3(xQ֮Aڹ_e"ŋ85!Tw[5mo~ngrRlNx޺.Qo_0YNyj&yJaBL'1NZ^x!r&HnSn녚~CRYK3y ]Z QcWtY[|E1&Y%.EiqůE piڡX==#ڧb׿{w%/,M>'vBs\(go{7>ǡ/L^e;iilz8ixx᫰WbU,[ԦV D637Mz"wt{N )lqzcӶ(OKovl?,Dw$)?ݎuΒu|&djB??pq騔ӫFg~ GIXHw'jM s }B ̜)`xx|FY_EH,0[mOGHoLbG~ e8 [PU{L>iki|-2DVԠ1Ϙ5[2B<_p+Q #v=!`zyu!E^mQxUYp8T*,8U0SF\]W#/WW~WСi5:; L-W+wqxg4@U}:ī3VdY'Nݲ|6b_/±hj\a!̓'Cyz!t-oyKsD{}v2)[>g;:q'vHi'`NSE>4K{}{Эɀ8!˽Γ/M-Ogk91c3E*a=:L̻5{b 7) /D^G>vWүSO=%kР_Mϝh:ަ"4V}%oOvDjVf2]Y&4Ȑ~|TS>wHI5f$`"EXEi9VQ]PKzTMN{&{P,gΒNJ˩v -=cׯd"xF}1e+>ཽ2J Ԍ݂?ThN&,Bߢ pj3;uf] 04m![nL:?J!0BU,08Yr`IM䀓 H& ;8iP߿L+|Z^F]5=ZvXЗvڮI[ʋ4<3Dum3dqNjSlj'3xD 6Y{[&  >+R\q8NZ侫HؑSxuN#'Ny[u2C^Sk:_NƜ"+ fcaDLkNEnZD3jS.|blu\,}1_HmvpfRTpzy")Ww,nȿ849EX5".~p3k9OiބYr<\%-2iͫSZ>= d_71)D ڕ [&veEz[:8^]olu뾘+%m tNU피.n":lg fmɕ!x"FHY4OWѧGe'M;Ƕ ΝuQtsQT$E0^bRNب.i2(UZd8j|:I'_qS޹CJ =F~j ñ74f'+oiIp5;X@@uG/ ogGꆈxZsO3Ji-oH _MOӘ4Eq{ʫuŽ?)p[s!$3qc^=O:}7K]hьD>byVmYTEfE嚋bg<2t fIza@ 8;ws'.&uߧm;ξ g YhT[i>iY'jm?3/IǒFi.sBKN6{QFnLLwڟE)Ӥ%X l5-2biB ܻݜ7aOR<ָdC:l^xڷ)rR@W??QkY-nE98揦NלlҸ.6xEJEpB㩃͙nj3hX24\Lu'yu柹9i9$ @65 kֱ /d3 Z__.X;72=mazљsfb%< E{j 6S@$7O[]WvOe,v2~^~aPU|YK` ei=`M{q}/\O%΍ ^0s/'66q2d=dF+trĔ ,E-Fo> o7M&y|< ooeFpT-IENDB`stella-5.1.1/docs/graphics/circuit.png000066400000000000000000000144121324334165500177120ustar00rootroot00000000000000PNG  IHDRoy;РgAMA asRGBPLTEoooatRNS@fbKGDH pHYsaa?itIME -2.hOTIDATxo*ş-R p&."o&ю ~IwO PU?$p \68XE!Pu,a-poVp"CK PSH(Ҁ*.PAIG‘j@ 80/GD'D e "v$ ET@ Z"* }38'PnTV  _5b#y:"I&E/*W]ɗ';p*TS iBD%PqHt2PDzpHtM4EgtaΑR:yl*PS%p \.K.=38z?9'pwU p'J;S6S rpBeN\1,'pC\ &p9!+ Jauu"!!t$[|=.K Hm,+]azN#'T3.0u>Kn3.wڱ67BgJmnǦMk]p#+ ͘XuIq`4\<HPSqQNTJropNn3(e%\ xo՟vNVOy\KDs0h2o|WЯZ$ v~ഩt=r V\KT쩮F^[/KWV Lp -'|58?="Yɕ f%ҳnj^[>g+~LUm Z$+5qEuhElj^΍H(q&^9W{XVZ+"30Ҏ4A)#8u{. %xlspe Bwʡs j3c 6Ǖ|[5.ROgׁSDAEn?砱3U1*0o ]U aĮ#/v7dX 9r(tڼZN(dϲE.!]P I;g1'2KTO\E8(M\[~gj-<Ţt4g`k6[Ν!GNRe'ҟ[Hܿ?/{ύ8oPh0NTFuj" À .ܬyKpcpFñ?(8^38T]?Z͜.$eIK9 i?rCP twR}p%JS0\ݵ|kp/UӒ7,%pOq/Ӄ/ql`ܢWJAKUl6/7++E"x^Z@)`jdWe#m4\ iusy?kJEyywpOґ6]y58G6@KQ尺V]:/ri5W&8/^}-.o !;"8r*[eFtKn|->3֍Uv+=.5 '--11+eT8wFM`j3d+8(:@^EVQ9xRqfcqܲ.ת1$(IΓ*P`_Qʮ:C #p5Η Ï8'Ńw-~J鼽9 <؋_VXvӟ\V³{O* "+޳ zgd/TV+d׻~ސda%p \9WOvd&,/_vAQoI◝LMw4ӅM]%M\w \JCpgZ09wp7qa4c<wpbYiz.gqPK>VM.[(+ݴiE/ }/+ե.xm:em%n|iIpN_F,Nό: sk1Ep67~Spũx:n$pM.,ewQj%p :Y yu&d" \2i4K8o eL~&k̥͠pI*)׸%"``y8t*8jlib3X*5 ZTrZ5Kd׍8wmKdey\d%JD$t*w0%k֪Օ:rOV""8 QXlMp`S5 0D'lx8:Ϩ'+`0Tր *i@p(Ҡ#arHxp5eJHT)қt+Ek2Y`6DDCe "v$ ET@ Z׻~HHF8Fb tVS2U;UQiذ%݈3 V9"4DsWMY <r=R2SUS 0l8G$:faK KD{PrV Α 008uod%!tpsRcnrGX4*i8E){p\fUڋLT-6ZNL[x\!v&=>'Cpm#*<ބqpicm++K\o\x r^ӦΛse0=?< Dsm No>UۼYCp'Cp!8A'8pyVd &p+q%p_ 4Wݏ+a92.W!Xv>ґUǁ;Q=p"!w~}8rO,{=i-WTVew-we]n+:)YpJokSG_qjg' HrpnpFñ-'܁oTuLթe>86[খݽ JiA2b֪ ;;d~&pwҲM!&kwȊ`̪Kwg3iLUGw[*kBh"s*ܯ[d(4H{֫rar'pw"ڑBty%8" !8GDNEQ/rK6/\ \oNxp&ܨ]7TnWԑ_*z܆p}3p>R #wFM`xN\[nln#&֎O``t/WS7e1bUka˿%lCpV%pKDK 2px\S)+[x9-GpV`e%XLl²"8$cp(aNT +]u+Z (czJ)nJ'<ѭO>]>sխRGv*ڭn:jΌw J4g[Y>Yo%cp0̜7{LՑܬR.7Vj|AMj*PSѽ wQʥ%Uh% T2L23!_d|ck}p6ԅcb_jP8t]a:TVzVgy0m Y[F#q-Iko3YFI0PN7uJpz~wp#Mp/^Tw1j\rZ#mw#9v[XtR{9X]vܽǷ/W'zwVVz8<p{\_RU6G1v|op/Uז+K ؔ6HiT^9l7(Z=;2b*poV9LG\-nĽW ܠ-P ґzuT{E^áٿ C?܊nv(e."2U9\ ެr\!=md^,()ׁAȢtŢt-Ѳ̓=l 8w\ \y2TeUaEHqFoתˋNȪD\͘oۺ U?C {3WZWiLx6Fv5NkQ OtY5\Yco(Q^Vp%JSܠB 1 %n<* [D@ijI>r&5ڼrp%`٠j-8wwp~Sp- 7ϗy=%<~<)bTqs$hUnY\˯TIxpV nmY9[otó1ci~ lcpxԿKԑM+w7185k';[E`ĝn%sx˩}X{k%x4j]he!3TZ)W"ϷMUxpËm(m# 0"իVu+n!sTylvu4> yV[ߐU=p62Boĝ7p"?Kt+%pI^}S MSIENDB`stella-5.1.1/docs/graphics/commandmenu.png000066400000000000000000000064641324334165500205630ustar00rootroot00000000000000PNG  IHDR/~gAMA asRGBbKGD pHYs  tIME5&tEXtCommentCreated with GIMPW IDATx݋6FaRBM%t}Af6|K)O|p @FPt/ p): HKс\`%߄ Zs"7ArVe@&d #B2g! d"mj7΢t /B.9#xrBѱB.@FPt  #(:\dEǾ 2Vezh\JNͱj#gMJ֫f9m7~tF29#Q[hOQvQgHgdѯ'h+<){/Cd(Q͕x/eeTzvik[v.8U=Nmi]﬚Q}!%ut}#[-piiF3y_{d4 "WFFc&*EhYg2j[F3<2j!iQi82:XFbȸ$12x!MegY-ϖeO&1 5+3U[L`NZ֫by3gӵvܯevwCV.k6]E|n72CFrAFdDF;@F2GFPt  #.\@.@F~ ! "EFo`" L@Fdt-B. EnE^ȅ\sF< zc_Ʌ\@.@FPt+ }%r-eT~jd}޽B=?طf.JՏosjܨ_H>VF%;5z`ebYiY!vEՅCF:KFBRdo"#2ZQF=Gg˨f=hնkm>LFyǷd=vex{֫HnT/W"}Y(\G23J*0#{ WKr$职0hn;-0aĕtrh\/5V2ZU7kdT=g d5ٳh^Yyr6VXtdn2"D^M=2r#և^xMԦufӍMWsNE|ިm'#xr_DFPt  #(: Aс\@.@FdErmdtC. hE ZE #qBAF "L%z #tg,q; @F A#&$2ſŗ,}߫ϪiOf0d2 H[lD.Cb%>sFF #5L! 3ͨ{Fp2ݪ##b#Ȉeddd4IFe!###hCt#Rd޻sfӁ_d22"#2@F #Ȉ@F # {p  #@F2d2d #dK3ǎ?coذYIENDB`stella-5.1.1/docs/graphics/console.png000066400000000000000000001706171324334165500177240ustar00rootroot00000000000000PNG  IHDR]IgAMA asRGBbKGD pHYs  ~tIME 24T?IDATxۯ}?{l=gN܉hQE9J (E=,PA[A-⦱ص eɒlm!g晙gv}]{ )AWQ^Ϳοver5&@@`-@W\e2@m Y!| (DoU6[BFaGhq{tjp7]B[O?us]؝]5m$# s`.Φ-}P>X/wmZKMc]#Sh]"rZ5Mo2RH,h~axͣ"в-ZhE\R]R]>:I2UXԺ[$9hudUe127]}dy(P3*rX&Bm^cK5sޑ# )1D4AћvC^)M{p*/Ih}~3z}G|𽛛7'%em^}_oU(5cbETZ.ki7V:ۤX6m^JWZr0)6[^MUYMZs];T7ǭUnѼ a2ݢdC0Z`E:[c;m.(dp1**LM? *ZlѻcW%Uuɱ݈uADZ.15H;F34jMcl'wn>~?n=ZzxB\u7~߾:UAT6T0vkt\s35ݺ2RPkjLƦֱ'V6jnzDhSbZ I\ZvkCw(ס2j\xubK=jk2/ a5>IjeU#k3ڤyΨͼ=fJɱBh5Pc`.ҢhZLƢR9*3C !p)]M"Zc3N[L\ZdV X;瘥*֬ŃrSG[aJ#ګ*%5iT&vryWH8J<,YLEJ'!,O=֬53{h;m~7?_/On?Yt??RaFp9 <7FR>`$&6yV~dJ 4 359q]É]1z i u6vzSTDCpZBIbR4bȒE+8p#QK*ۨ S]. ֢R LIVkaтmr[YZbׂ\Krb.\VSTdU2.5\(rYTڍJ[xG dդrMS.-")Z# b+A4$݋r)lG%٤+#dl,l aw2Q)'bY ԴF* "v*%ɶ$ĨT:,nh)Xr("rCZE G4MIѤ5s-G}V^VR82(zhU[UEePZ#φJAҜcW ٲRaR0"ښՂLHAPb`)4LQ!U:* C MeSTD(ĕLBB!PPV $UG*! (RփQtY!+ɕn Y%PG%kQrYM*zKrz ֢I6 iX.^C~hWY\ \Ks~{jMzص_og휵5 u #Z 8P5PUɁi]iYH +jtT:0vP Uy3])M=)̼sYiPsĺS+˥lhM9fӒ,nɈe VZ%lbjQk#GQmmݯC׺އN+"r]R>֬=z"Xstc#{RYIVU۵VsHuT fGu BͳZ_ox[Z̹jʹiabceH۶oM]\{K#z{4"r7quyI:ZW7jbjG9y %$&&ҵT'em&.GV|m7RHXkAm/}PFf^!ەj@UE4.Ig KHh-rڥs6פuʱˋ6tPI)]d /pEm^GVF(,/i_u;$@}_ӗ/5ML9vR:we"ƨt a:-l9aYTvYUѨJH, .JrPR(jEH(DhPV8XѢJRaeTbnw?yM4MV쫬&(+EEVGS[Fiݻ\~p瞛?~wxqW<5`ӹ1I٢+?|)z (dӣA[ʲ69X…%K!6j"BK>-dRVVq؝ki+z4%b(I]rwUD#@UE%0ld;RjQ bi&)`7GrM]i*K`jqd%9lxjmh2ְ͕ "0+B 9XYDG.@Dh GsB.Lji5pyT!EYC&.A:rUߘ.ͮٗK"[ϽEӥ/S{{Rxξ5x#ׂ:R~VӍ~s[ޤa3%ViӥA^$c_t2-Q XB9fjvm1IHji99D3"$[˄K "ZU[dVZW"XR>sWvEW)!ը**凗ztٜ.w˰>ٟSw{wq8aưK۱M.*3䩵2^RrUi^VU /.:;F 6k&I.;vSsr7nnoM-BѺQ[iM$K+Zŭh7v墪Hs냑&P-ilڤu^,`[ ;D.iUp DYZdg&Y`6CPhfMT1rwb,aͱfaEYUԚsro֢}Zj9jA4>['=Dk%prT½Ž6=rsMMMݹkjh{ju(z4mϛiY evW[BV,*Tom &lb\.,WIv֥S63i5E5mz@zFU-V !,+X/vA\ $eG`[PF`1H( bQ?ӵ(\1UV8ãɄ}NGqr{Guu Kzuwv>Ton5[Rj{7_ϼ[x4.):ג*0 7[r@Bm*(Fs 9wӟz_ÿs/ݛ];齵hsܘ㫟p{O&?󮧻?wkOxߝg?7_;ǟyW7>3o+_7kzblb>mn<{C҂D5 ?s =ygyxkb9Ϝ_x>s7˯-U$ . %P(H*X״Y7~~!蝕ʮo|G(x$Ȓhp5("zg{l>} Br$:גbXsMFBJ5Ji#"\(|@ ILmݳu|lO[v;ߙ;?~l}6Fhƺ~{O䷿^tr|;7.xP9>OP s~.?֦I-ʦ.R׀MZ£PŤUQJ+"cF///6沃<1Ƿ&?^csSvy7d˪~Z IṤf~??]߫~Mη_g?2=o]{is~e޸Or7Ns{+/ħ7'Gmb\)A g2RAmMStxkewuŽejW~vڏZK4yA.-u9vszs^j#59<JZ\KR/NM;~?,љ:@U2=dus}GǶǿ{om& ۯ/_za{{1=Sۿ6/cϼq_5{zo}jf:z{cԎoNc:~:otko?yt|kËBӍ'gɻnc{/|zןy߽vwH`$drT Bl6!"-5,b77ֻvxJ7__/~.[\IS<oZ 5Gu|\u%[ׂMljL-$uz(&R9H`R%<՗>ڷF?wma$N˃ߕ\+5t_+/+R9J^}PxD<|r~.$պ;+_#ڲ\/.?7F%0eIj@q]ћ,GeI%6?[S3esu(uzW κEm{ M[m數ZTՕM׏*{t;Wf6bZ#Ӆ 6BAQAwAs,s rd !b]S'pq,b+08wBcr ʲT1bO.`  $ $ þHn=Ԛ Tyr"U|G#MlGt}Z%?|>pȅ2i2,K綩 /k5'(\K6ʅƘdUÙD8dȲӄ&!F'\ e l 2%1` 0Sc#A6e¶$lF2& Y!Dl(U5I@̠ʇcDL3î_/fޝ^?.h)FڮlZ;e|gnQMgr?֥.%wUkйȡʘw˨%"dPvUpy9Ƽ@+2@B6 |2slmqŔKjlH.[ƈc(q1 @Jl)c @!nD ʕt_v{nO>_}rXc?n+׶ 51\>q&g6ͼek_mA0tn=2UH{O]!!qm~J2:@@ ۅq:񡛛Ǫ *%.g~tnOŨ˅AL&[CԜoV)hmZ*vis:REVt,7JE+čI; pHed 6]:,@7{Z@`d $ aYA2؄+e(H2bj<#)nntִLI\%PF&*3GCy?{lQvMmŲO'?P["-.ɣ=qH*숩ʈFkdG&Z5gtmj\ U\O U VI-U&QP De6HFaLnzOFy}@e?Gx˥0?e6, K`a$6; 2$BI~fp7n>?ee%$!"rͽ7eTQS8ZJh}?b+/baSjC5$E%GKMȥrVp ;RHQȣ  i r) d[RK*[7on=Y._{?֍;#L뵽~vB89080$@RPI@' H6![('#h u>I6沕4\nf=+w/ &׿fFkb]YஈfRWL=Z$+SQiBi[%k@s- ֌(JU Y7!l#hqOnlExÿ>~#7؊QOޘ7/@F,+Bƈ!` +B9 A?|0mOrāl,.Cƨ&*]R᩷.Ԏj2](\s}+F-nDXj9Zpv7a=ư0U6Mns%<5PεԺz(W/tY]2 l06W] ۛ/|>~/d)GzK/Ͽols-cyzkUTlB(@1ȼF6d#! y0XP~e E޴FUte#,YTUVrR6꯾v4o6=cw7n/}w?-$bk}?ZwATQ zX̼[6sWG6̵ε7Zr}/D"Q-p!`AY8{.^yl~{_?"g?|c3ER1׬iM){q+lsPʃ}Ӭ?5b֢+A*#l ]26L"@a+m=,4&TZ1ܙ'k^i]{"ں :Y~O.^מ8yk#<=6Mϖ?8i]Qk/WWO;nVCU:0kiVNZ3ֱ>kάiFRy&é90Kovw7S~gMcKR [n?~_ *,ƭMܹe-K""cassE`1€yG 90mrH@4ʑA9l#,!yV"yhг7uY^|w9w/9##%ʣٽzhRY!Fiӂ۝kISk-} +XS(c[Ϊ (Ȁ́UHΗ_^jfeUR8ՃNcHX~'_8޼06I`@. #0ؒ@\`[[҆FYLsETj D "lRBf<t<ʹ_r1sSùnnQFDF}m !SzfUp$,+5 ɸ k$eZ gU69A[XF%x/sηȜ>*ۯR⊄}3g?zXg;0 Arͭ.6@B\1B  a(#l0+2WDeUpH92Z WU%#m3#glvgijj8w5*r&0@:LܢFXJWU  0H!(_}{o^?:=w[.( a%. Hy׻N47-eQe0vI*6e$H 20]*0 E򰣅!:Y-#\,ubr{j.g!k֦JRZ1wRc3fڴvQr%׀pZ2YO64E)XFH2 dā˒, ʄ"b0V!2HaaTi)D#q`X,$́8Bd4T(KaX*#=*MbA&a$ZhڨQR/wF?:r~#i?of5U̓[psUW/JFR@5BiԾ1f+$av֕e FMwfaF`Yc$@ B`́q 1lA@6K¶,UB[Ɔ\1clVL.! Hd 4j6"zTq;gGZ\\Ǐ_wZo}f["R^{sǏm6[Qs-mj)mjޏle[ 80qE!?[o]K!7^ˣA@ @@>Y]FȀ16 m HBs`Bā ˀY6FHn.]2F'F$}䉣m쫜[E M(pѰ2Br-HM#~x|+׾//|5MB:PZZsAu i,a9,cl@`!;l#@};=<{k\D_x/|awOa\ @@Ł~}<-UX`6 D!90Kd⊁h?!d5 l \t;bc)Y(1`Qux|湓|ޚo}rV5FԢǟO?E1_=;Ii"&CTc9׀s-% J5-ds_+Cs`"R ,d  a ￵+9ھeBTU=}3?/,. [Bu_OoW//ց1 As ! م06a!sEeelʮtUhjb.iGocGݘcf6>w~&cx֐QA֬ m}'R@Kk/PDvK"q؝k)tnĴZ EĀ*($ldbjڧ 2oNޝ}>!as|_;[Xr'}5@ %={/݈u{7.j?O a,cIPvXHǝ}Ʒ?\J l-@T!UUD`*RdV1E pdZc~?hٯ^~[OxjJj$8&O~AYb;5-ck홻b=Og"z4s-!F5m);:+G`# G@B@\i]|n~t/?vUPjQo7>=vs H$ގyʩo|uv<́AX\òK„$?'>;/K#QH@0!$.dPE'B\K OmU'b_+*ۨ)onfh]Y&HlMSIGo\rcݹ,:adHaS&H22NWaF9dzoO|uMa_m>9y׿OO4B ́Aֽx36W|[㦷eY@m1d,QH-fgƭy m.#&dc+ WReG֒|,JVvԥXG-wki>4c|jvqz?b-8hBMRi+k6\7*5`ѹ: Zi8!+BaH2`@`YГ'qo5CB (c @ 0FH2Hj_z]Sel)K…mT #Sl 0HTa#l yl2sȭ:Ǎ܂Ai o&#.PXS `t=羯f]r_t%7YͬDwg!"bjF%TM _A`$I~v<<<{=i߸F0Hrq W 0 lXr!s`$ 6?a-a-d ;lKADltr蒂܏hnfSstTt d;5ڭXZ)ˊi?"{hI`y\K\pDo8p Aacd-woK9X6! a`B`ll$0`PH!80!dX0X$cds`@2`\Z \UT(V۝C#pý(yVa!eGզu˺0tZ;R9R?kPV`ʙn2d[ , ۰OKYʼ $(#BeO!cc0 2x,%~B0 $0 ~m3&, [cm`# 6%-`8&A\3s8øz(Zkyxn×k H!b_צG0}r] #6ӏS1׀ε,v BUl#M 2!l$c$ `F"0ȘwF $ l2vdOZ?AP Bg|_|mq Bd2Lٱ.cTeFM$YVZmV"MG(BZ+7P3bHԔe}|\aVk@RZZHc46}ݪd,daCH%BX@\&p $!l0A\d WL+RdY2ԧ>w?Z.F\!SOOܽw)% \)$D( GkGM쳳 z:ڴ(sp8YWzcT1LW8uI" ̲ۭs ׁ\Kmj,P8۲Z&LPE&-HBKHH!X`u>Kj_X)sEv!%0s @\12  AB.LF*I!ف??;vgo]9cl$7mtiKJȶ`$ Ch*=^8>ym=yGxt,&Q7>Lż-UG`^6NP(3T2z-ZĶ޸l:RV`QwA4SaK6e Xف$nG51GO|&>u1$A\88)] #@R`}cG?zm 5ho._󣧟9~NT , e??۝{p#a\!dPQ˘Tf3e2}2mywͣ~~~sH!kN@n0UK,s঵u+:RVBvk+QVX݄D6cF⠰ G;GO?;~\-N<l-s 0X  @HBj?ۿW^Ko߾coSϟ ~ŕoEl@uSj-X`i&7-x;X=7]fr1N,*VlM+HPՓBfǽS&׀MZ0Xx[:K(GC JHR@a!dl 6޷ƃڿr/^{{\lBBS!-cc,6$!@ I?_t׾7W^]uTW;< 6?y]~z$HpgR(1(Y$*WvR$M&JVdJv^ĪD.˶TH h}uP9NUJea,L` d2ž{ ]VDƛ%KYsTls^ϦeqT.%oʚ^0M5ݮ1eS]\C >ܾ5bD&dA*$tv#>Ϯg,B$lř8C|y": $E>OoW{ẁK7o~_{ͭ'-awdY` hC%lR6| M7yN[xUmy]"B1Ӭ21zD+r-j!me ˓}< J#)}>K<\d'Bog62R_m( lK P(16Զ8Ło~o_}T㈠iO 62s&v˲16g`vWni (i:,:KO}xG +"&5¬I#eKe<"2}DC2jȶ9sȒFF qm{V0`70B^>?!8ll !YCMW~G3߉jn= Ő{/G?ݜY+ɜY͙ƙ16jжQ=٪Ў[ݯڥmk0GlwvS}]{TY3ә]]Ussd[w;l9yX g*ҠpÈƬ6Ɩ%c@`l q`6aP61?K? [g6)@-Ѳ%z}^oFx("57;7l l9 `lؼ͜1jd)gK3ҡZܑH+PpڋQ2ՋN[ͮ X>DQ{}0'ճ6{\ݖFb(0X [6~mK6x @`΄˭n̛^˷6 ` 6oc`0sǍ ncPd X6x@,w!)6nlwo{wGu$RPWԕX3-&Xa}22]0Fƴ#cr:8FhC@0x(m֔\U2x2  #X؈3c!,1 ڟ|K_<|W@3 awGF7W?_?v+"}71n6g€1l6y@`6d6j`ԦqݡdnZm2svxGFi޸dͽQXr88ua6/DݫHS6pyU4b,jFԪ̱_ױUuwR!!dvJmc*vL1 c>#dPCt,iFr@"o{[~4 %̙0g-A k/g^O|ⷞzm/mC1a6e[xAgL!c7MSed$2kp:[ʩSt@md<<.ǫi>}<9@Cww伱dU5t".Ft*%!d3CۃS3ɧ%Ԁen "`@r[!-d&O_ͽFA$g! , ~? یHB7^z~qm6gƀX`,΄ X0դvcv{CkH4=umU,C^RxYS^]䨰kN/kzSW{غke)/βC@",Y3a"R,,$"@3hcs&l, D |~ou%0 ! ٸ0L<9W7~7ntm{ڍę m͙6`#!y@B2g6dlllڍ\vO_mu8V̎&bA^%oS1p@G6vG>9j1p*:,5KkJsv}<N,r}_d2dΌ1gF d2Hx 2 PHCR(hI pUr nKHƍ#)5]Ӟ[&avO6.u:cĸVܴ%$Qq}L<=QqfYID t#)ai*"XV\t97@%w)לϮvUϽkvO6Gn66BB #0H $ 4#d,-C, $Bv{]X66a4vP27.Ebzqe\^*B9uVy=!kpDsto{-sz <GBdav)nϼWjrս\12X˒,rRX.P݄\=Tr9=}51`[` 6:k#$BلB! ,ZI@Ȁ]%Ʈ@X.Fm%c fZc` c%]9ecFw8Ё8[aVFz^_[t]Ba[nSeD}Rn**yˑ,yYH#B9"s,5%atQSè{DeK e,-@~[@c$gA؀"mKX $3 6 A!vcmȌv5RYnQ{ V3*ɛq͹Kmf#t1t5tF$8=e#}fn^Kp6C"EˊCD.tӝ"as 2Ȗez/3  (bE+CH "y&I6mV$€A@VF9GHœ6۠-ݍARH d)d]ea$xYFɖCuji+ֱO 2r\'BK̙pq :arf5u݊m/O(3 6c)O,o.>^ڍZ*ʽ:{Z{wXFw3rm3$ȰZƆ;FFm#Ȕ PH2ؙa FAX ’@D" cp $ {wݟ}ݭ}_M mC[[,DuuS۱,mzǭm]k^@Jdz眑X-ʹʔd :P"rwC "QIN8eK,ezYU]n"4{omL6H (9- FIpY`̿$lȔ%h)6tY  гٳKd42Ǡ&nITtxP\5$Vګ%TRkNH@u00 J!cIubU!nM#!qe5[p,U72h nmY(B]0fx~⇿~"nu~me88q˧lP0b0#ޯo'>Goq@(ݶQ2@ RP|!Fj/֌edIUeL!{r=X[uA1br}S轙{u޸BR7!"!<.tzo{oyIvH#w\!K)Yt[¶Dg eĴn[i7`KCmԐ`u>u/Ї{9,aܙhc"sc $[oO|_amMK,ljB!% ( #2cn͌qOj^9:)^K(cu˸Xܡ?￸}k޶`P:_o翾O;ͶwwܽOjhB݆R Y0$lh6##llVXo^/,EuǙ4W=Vu"bdOu]\, [mIFdqu1mclQo^{[Ը*@K<0F.ra[ˈ\hTzyrө2DžG>ŭnx\J6{U<zPH<}S={4TT$ҡ]]$2~)__>kNY\VojF}N2E5.O8,1si(qO?G#cn\xCrݨt캮jW_jo^{DwqhԑpQi6G:E%}j")=}MWͽvح٧.3ں\6 !oUN0;!ݶĚcRKm߻l͙Q` m 6c]_ʛv,%: A&Pho".$${* Ȇ5)kxH-D(RWB_("_" 0p3x(2o_ Ljam#m|8C1g t[-%nE`Zh *\TWLwP6nf`¶8$3  1 hӶDUac H d5m ;M!x@жlD B;C6YVkP!!;o X6m iیALkzpy1*)bA%YTU9B{6'F6x4I %e818B1vbsFU%30dnA!"5k!a-BqfY$7"0R%E .qxG_9{7ŶݻuuZhREK/n_u93eJd <͛e\ي6ZMkvSvmݶFlQ #㞙I`[0`BmB Ʋ, mku3J^i6r ]F`"mtXm tH9$qk#c #F|X أ7׌{y'?\P Xo<ԏiPzqwXyGko۷vӥmO?/ ڼͲqv\^~Tn 5]Fcm+C :} !CEӇ1Iy U"uﵗ{g, s&d,!e 1o8s>ޭ%Hq-S[ snjd[{R\o<2 #D@H;ǒqqyyyO~aPR֛ _>o*j޸g|r!$76-aC{o>;› )@s+e)$"dltK͈n>ݼM` 2PK`Y@u0v2 rJ6m1L ld 7C}{FBR[`$AHݻ ,c]/.qUHwe]c*:]ٯʛw$0 6˒"w B6X`D;B aFFPmJcd2n$@63]! ɘ3a 䥻LU7W#޸q7%Kes;' Q6D`[!%??7OhY0 ՜#pNiÑۏ|Wo^䑛C iSn]n<OܼyOvXQ!_xo\ݻ}։' '{z @<F⬑L  9EC Q;E.09GN|[>89F߹w}x[2nO<56czՏ=vӛ{2V` $]z]Cwǟޏ|Ͼ}U:Rܗ6ya|/_\P[@~h7Ty^u:gw3{ilV۬C.Uͭd,(Aj,Pec$ tUFЉ{Ʒ҇{xD1apw;y+?[o\-8"F{H7/n]\wߺwO>}w?yqX2.^\/>B=/c1ޏ3_ <~zC^%_)w-"6ה\%+Cݲtvpn[B !@)` !cٵ&ʛUYjEQQwm7bywfv)Bmz ݺyګwԏn1_w9kfRܸ[/]|}X=z⑛}uɭNR}u]zjm_-~>HvXbУYNM mMT=w.alHBؖd@Z m>d//Ko^yIyȸ>>O5sY7_zd 4Vhnmln nW׷nܺ}O7}= 眮?G/ZU?ģ^z"r C͞ղ"MٳNfzcd4ya嬴Jt[{ya^Z hC Fc!0FmP0qYpvǞ}dKFOo=~o]?:^˻[lO>捋+_f?+%TtJn#c `w7uVMww)!5V-y@؜ ۄ@1`#@<`oB p}o}j06y2H2m!mΞ}j<ȓWw'~3_~FZ-Ww߸s駟~ɋ>2(ږ,BF8PBBtcI

v䰎un?/ſxKك-myca5QJQ:.e)PU1RAW lId{n͙Ւm5mƆ]dsf0Hۀc "! D nRH6@L#H6jMHlŭzvoݿW~'w|/}avuzXG/abx\}-Tn@6vKqzE3#px{yowלUmWe9$a vCAt XŁ!ƘjXGw;Nfw e,ڬD6N)̈t-kDl>/?w|y?߻}´87 !+*.Pomj-$j6 ;PKlp0 tPW6E6!q D5g:23q0%"{9"SVVHcs.I J.),ZHU[055t[ZYۑttfR_/=x:C=8q79bJmn(2eѭS#.Wd[n)iAEn6RӆF,2ęlh3.)[ l(@m#}!dp֑X%EΨ҅ږZϱ,o|Sw+wP WlW7a -K-vLbq4}Fd"kΌKY1^ʡګQ( ];#ӱtjlѳ0X]XH chR!R*%/dFgHXBH]!h+a#&$(wN)۠? ͏/[nfO}tկ?}XxWYG'oڿxU);BZ1!nH!L ѲB=Bgf탖]#sNnx;,l #@A"#BaF)[! D2D4$-K)5:ri[ Z:uی!W%@"BѪuv7[ϾՃ1 }OpEt+Ph j^F\u8#F{QVFȚv.;}ߒ$f8٦mĈ؛1ZrmY gќ9#"BC*J=FcRɈF^D&drOڊ$Fr!"KxsYSTi Ū 8U;.ޏ' _ħwt涿g7^/<< _^sz:&$e5("iH22&"nkuTU!7t+nmA.GflHm\rw*6e h,dkgdwvGHPО*L5P3=e&"g1ʌwS\,vk: `ͱ˯/~co͛{ܼs??ZO<,{o[{o޹h5)!9ƍH{dD(̩ q:IAF=+Xϩ6di G橎QtǰGR+%dHRdHX gܓQK1Ӏ 6S.D-ψj[zn]Ɔ1;/~?_{??%ܝ_—Oڿҟ}}۷[1$tsmwҢ\Y=ݸÐ`aQ]sc]Ji"n,){ᄐqcVIudkU݉m±dAۼ_MA*VbHR#buknphX"uHaH#cQjE0pq8z"][KFC*މ UvEP+i26cXxP 9k<{>67x?OWwֿ7o׶/mdcΩD\+QӊV, ش2D9jH$2HFZ ܶilM#" Etu*R Qp&ہ,$\nU%Zp7 h;:YǻZ: \`Zn+AmiFKRճjYbWQ׿[CϻDHwuU Zmyg>/~7T,ZVmѭNQ|6m9BU[ػRyqO.qF.gH"`N,))D ,\!a-ђ!F@LamR(BC9ՕٝR6(B3Ze7DpiRm7ͦUhDܽ}ϲ,H-n&RwKt/o_XxWFwG9䊠l,%lOc/iJ+ f;GT+BbOvi'd 6ڒBߪ>y[GyʰMÊ4NL܀V2ArϐJ%[˲l7"E $ED*ʈ.#R89;QE.SZsS  :Kk5#0ilL=HqDݓH[ ̎vo֛kW_?̻"FDbm,c1q<%J{k_'>wz{h0*WKrSQiEjnF ڕ=jvfcmX)6VPq$ݲ2<]e "ն!@GFVYgێTʻV1%a$CD(gѹE4am9pU A`B(R}:RjَP Ycpv{DJD&Vd \Cu%Ҋ #lLZBʘ{W2$ۆd$;]刄PՔME~뛿O>9i#4[Nk?5|mГϽ/jfm@CDXav&.@ fڷ^pZ5M{pU,cM)өf; r w^YBKBA=,(#F՜{er1lEG*)4X 8A`\b;۬c1Zm5x'>Wx=x=x8ݸ}0\ΟW~o޻rVi.kޭY,v[) LS4$i{b)Xm/T-AjtuhCٖeqXzn,(5B{x `@ҁL(dviȽPr9!s*iRMϮ%uqVK^.{Q ;\>nc!_ݏ}G~g/o!;Ǟ6g1js؟x櫥ۣ]=2 Ҵ/fyBvc#$P3؋==-U N$% T0|osfbV 3KUaxk نlD )pڥ\PH-iIbdMjEr+Ew[" C*VWuc^}/|<wNt[mZy~{֌!BPM#k 4lX2tqh"L4>%&[YeI`U8@ݴHi%qjc #Br %@( `,ȐP#Ֆ&ʲ0TTْ }B"aaYxd ء}{NW?W_y<$9<c# x{w:nnNqXj/. X jNѲz]c-SH$ɴMH"2""Z KV]84vDsȒ]b2!, 6?lZK߼stWm[O|yiqed7~'ꙧo|t p2 1Ҙl,ތH F5єl "Hb!p8{NA.#rfHh"ICuqzNVcZ˄‡TCXvQrWlI[*F=6XEiJT;[Z43VG/_ߧn/bv6R~~In8€A?ߏ>oVfnIu3p RHاXF;`qȂ%a@ʠEX e3#TQ,gWLBD!)E3r+RaERkfɪP%PXU!U˖QJ "`.:M:w?䍛k#}+8[S`7.֟í܃w$lB)spѧ~gWz9jb^3pM*bFD 58hdv&lcUwX2RY#42l,#drtiD:-r[KXw̆@XͦVnɝ)[-hb8w/wl{8Ȱ͘aP"մ؍N9[~Ǟ~ݿm򩻫n0g|/Ku4   usf,uMeÍy?>n@$Zþv@t#܅2R*AVsY4R4#[EPy1@] !Ufv̪Jv, g[d0aNdKJ(n) ss2׈iWMGSV5{v B6ni 57/SykYg_Wy}5 m|}ݯ?gop=U_̳,*~.eι>馍-W_|v{Αy'N=kW>IE=ӛ1 dݑ*7;,)#"ջƎ.%lء O5K0y[kj\]U=КЀC8 ϕĺɕ191v`0$@Ǟ]]C\kZ>gwˊqP}CQ.hP[Z0`J9Z!BjE 'Yl^$lD  s 3I@D flC(n@7QM]Y̐ ,"E !9GWyL9< uo鬭vB3TEzro˿ɣɌ.0r_⪻7 xdaa5iܝ\9 ^8HK'._#>䱳wڽ/^;#Ņ+RW/K}8ع͕=xp͝R$4Ԓ2Vtg.h O.MWwOO^lNDZgvl (ok A3Yg9B< dW2hSkQYI iFIpD9Gf#\LRhHHIЄ)\NA(daA(3L*K@N.)1.O* mVd NnN鼠,@2K=Pnf~a7)μ:L"IF%O}ͨC!zIڔ^.@=zy2,S aVÏ}S;w쇫n/tGWWYՍΏܻ/mwq/\˚ag +#-F[h"$   @I $H@ %#IB H R #%$%@$@ \0R-@@p$-@e@uoIxqԡӝRArAhDBFO®}׻E|/?RʞrR'##=TEK63݉X,}xŢp_gY`v|w{>LC_ OʄxєAhT3AAr@ "(@ . HlH Dm! Hk (@B-$.H@-KH I  b& AfK "  $xe$tUox;M/:䜇^;U> H4R\`vw̋'?oocfn^o]X>'G8sg/nsFH0b*|U%V78#>+.HqtJsKIPRWe!a3mQNatˠEz#fz2oR @a<9᫪ܻw~`P{ p Mkic="R"  K"l`@h( BDAdef0  p@ʀ$@x H⫄Px ! QpT]shw_ 2+8oQFR!eYwî=O%oVjlD% k3[efF 08773=3W/kƓ/^|'x'_8~ܱZ6Ұ+j>ڳC_2eoc6c Aan6`i4esn-S^Ƕ(4#.]9$$Is8!ǟm ?zwolЌ!wE򅧟~cُ~HD$p e Ar@$ @@Y0A$@Ac !.Br " bBPSH"_!HAB@ %  @[TֻMm*{|ݭw,5C$D @Ì d@*a|QVx",x}ϝ^:;i6ڜ)wLWʼnNlVu 6pt>Aʞs0OmIݩ:,huɵWOH%#80=zn?Ow:VϧIKP\!K&D@ [HB2RDp a $ Q` .a$@ &8HD@ \ h t  $ (B ]@{aʽ;#c(ٹ]fr PwhAr@ ͪMho?˭Rv`$YEJṵfz(;6G ZϾxiӝPjuTI` sCWRn9{-|S"ά ch>_1ĺiIdN'T^b=GԻIacCO. 72wn_shm/ ւ !tEn]:>C\ie>qž,V]cQƜ,㦜/zNWqoqs;yą{?ŧ}#,(7c@9sgonʛnMqyK++ŕӋGO?-zngjT(~ڶ}J]LOOEF d!Xa, Ȫ6V ?O11 ]1x>gwR΂@ixHsk6vΗWquWsWme/M0ed+<^HYM'>{~M(+Wnq hg..f{"՚gR6+R߻(S,̓ PʈB09BP͔Eg~fUo_^>w=tlO,x]{W휟RB:Վr۶ۯ< s_^>{ҥ˗֖Wɨ,%``B9ӛ~%b-@QӉ]+BJq,߷s׎;^/w~?wI)+L3/:8X#Eŕ]}վW^.c9\TR!G {ݺ we03<"O9{Uqŕ2* B)U7ߩf};n9RUq晩Lғ9@pa;w<|ڧ>ē'/8|O=u7|W옭R*ծ,VUV󳽽.Mƫh啕Ѩl֣Iۜ={/c -IRn PtBwʍfBʂ+N)rIEF .ؒ(" ݳ;qf~wNU <Ԫn !X#t#Bx~ uzG9y B 0P eEk0ܴmĊnw6  F"DC/CpVPڶ^f49z~sO=.m,O:){wW\ȕv({ E6m'/;(̥2Cm3,,x2ZK}{zC-*\Wٵ{G(;ˊn* 3xeyNmbT+cf *IN L[G2V;Ï?֖]Mo嚫vuBS &v{}O-Njꪚv@czԢގn3g G0KejĘ ϟ?^̭0nA=^t0ן:Gc-ݑi]&$9h D{K z_,]8`|V9`V:O|7]U&͸ !PL=Lpdo8\ma.!&2!Z̊Bnp2'S_t8M`I#IVN{/#O>Sחƹ!rYu7_sWueY͙U8̩E %ʐ[U%*)gxh!Stҧ?s/NOƃԩfTe<7eʂO>-ouUѕYYb1-be۝5M N`(25^:){hŎ4Pa$C,,&Fx\שm2 (H!ԌSfxpasO=? ϟtvycHE˫~7\W߶wE95 SZ/'Lț4iڔs:{(E'~s_8|{M7^w+XiFu, ̽ڶM9k?{T,fiUUon_dqqeŽPy@Mg粷UUIR0]ަVugRg>S{~mytmou;NJn[cMM"^WH*_y$CcNڦ[S` ""ҸMMnꦹ2^m67m  " DRx [Ǘ{x7M^s{vC fod}4( Sۖhvu4JMt !a @U\O앓6&y;ku&g+{{v> eYhF3H#JM& 4ZU*z])qg˘ZYR$fnm8=5mecBJ޴FGi'I!0D3@#^B$@-̞777>w/o,VU{`[n;|Mᮝ;{CՙEx,>f2mq?xo_'>2\w]c?#β3U] $Aa zC=ԯeC?[nۛz[߳o;vɳmw ^% !{mo~}s ǖ>zǯ|[vv:IJkKO}JhaWURYAz2B1~権'ܓ9 H$3JtGD k+gO^>'aoM]s[ \yY?_u<v&hʂUG$,x$$3 5YEY8mNu=uj[%P-` %9"uOǏ;g:ri;;o|[~䆻wBIO=o~{?7e!닱xg._|]W4Mwr'.{zSXw~w>}~sg?{gN["Woڵ!B,LQٳ L@Cl4VA;$@ %@[I8$Ou:]eϓIRڜ WKϟ?'|ஃoxvnW?A|4x"VkM$2xA "e1Tp(#Cz^"pW77ևI=ɩf$̢#Af$BtG@g}=C?7~;]ךܿ{??8q|C׽fs^vāC7WO}6TZ[cz~[~pdǮ|n'N> >aoۛj_;v!ϒ)e.]~yu>JLœz,f* 1%qӎFæ)e4A3(/D Fe$x )?rMw ķ>K?;y-}pկ7"_NJ|nxHMo<'N<;w@=7\{>?ǿgѻ?}[zWE+xB3u۫hJu[ 3b%efJڄL3qn]A4KA4MaK .XDQĜS[Z/r{VFiu2zҋ{{fn/ 5K½Xcaln$P%$,,Ndm}8 v)FHh -AEYrҌ?s?sY(҉3/<U KS'_ʽ?;v+355t4®ozhNՎW~[{ť3?'^8Ó ZF>O~ O65Yڜ*,ƂVTb! f3&7m;kxj\KH @ZY"vˢTͮ228,3d%ox]?Kgff~sO\(O:24e,h &Zoڶn)I9;Pf$(Hn 9@H - L H\!Ռ&Uoz<_zo篺xؽ}'uxbQ̋+˗ލiozϡ{G>{_#y}?}׵nx'Ӑ@S[!ƵZX* 3 G6eH̚:ueʢћb&ga %!II(+iRAP=a3v 쾼܎6U F՝M.(%Mr$jVU'&x8mh-Fd$0 `!A .?|lp~'Mn&$^k'ͯO닗?{C5m$:v\#=׌?rkj箫o7Gz֞<>S8Y\UI3|NlSer@ AIA@l! OQ 3, MBۭ3$Yr%Hhe=S>uS_zrSS#-:?:v_No˿ ~?;=Won~ų<닫;,Z3÷Y:3Ww-om~[}҉|GO=}jxe}ɿ?Gy/xC~ˡ 殹W\u?|/<u+Ͻx`LOD 2!LN*-D -FdH"HŒ! mvj!Sn:!N&yss;Uٙ?A|l>9hB&zda$03 !@A @Jx0 p+d,o"Zxg7FC!Q IHrX[q1ߵcGaELŔADQqQ]M,$7SKϟ#ɮuW^}^w;;e1k䔾{ȇ?4;O׼ ^z{= \L.|=wwmvnt:3oO?T+e'GLe7# [m` [\"hh%$ f@@;' C 2%pl4 h4E{ t UѦ*|Wz|ǟn"rs ǍK@A"%$@HRpo}㵓*ٹ39ɓx[i:e DW 0-SnZF; zuz>?tjf _%~W/䏾]=/NF]{5[@r<…?pP|U(?̯oǟ "m3hF+KM9e@ dFF3 $(@heis\o֣ b i a  NXH "\Ē~4;E935+"\eս񶷿魏|$)9$"Le'^b@H,unՇpLԶT[nk2Ťm{EA$Q!խ_XTlX(M̰YnD!ːid>ySO+_\y/{/~BQKmGÍ[L{z,p~9?{ˏH\BnfʰiҰn!٘)#a`f.@AEQ]yMb\A"nS"!$&G[zQH|U7 w]=|(҄L0*C"!"@$/av_w_l4蚮i3֌ .PE??Ufu,MRaskdžݪ4$tXΨuv( XY~G_^_/^~㵰s{9urv?{orW_}-m$={~/?^0:;%H { `A$H%xYMZ[LO\l=IN $$3f@bw@a(iĨ,Z EUH_wÛN=pH$$HAF! ^pݎ޳;?ic z\'#;=layz2H $=Kp\Ʋ*:݄8O{xb/A@5n0Z֭U.1J~_Ͻo*;yEwlf?7 wq͓O]֩}>[?}(H^k ąѢhfRcʍ$`<7<\쎄/h . M:yyՂxGٟ>}/Q'&!HCxQI E(@h\_uŮ]"^]{zÛz`l9@@9I|Qw[nb;vPB` ?vLEg8_f[ _^ߔK.AF%˒6NI27mC[LOq{h&^bo^А=<rX@ &?;k?vpsϭ)+KF"'|?6;VzV[I.Pİ+MJNy3gϯ=BͶhSEg\Ԥyğ|e pOjR)#m^s,+zϝ|X=҃B\`3ݟxs8E i\")ߍ\w}"[ڶ4i~\v*׽qݭJn !YrLw`+\ro߿/OžxW>rxUWy3kP,"xV 4ufdN2r !ˌ4 MwYN4bjvnfv8,xQדhcc}ysgOxfiҋg.VkMmvdw$N%@ûӛ/* 8r=|ӗ[$4)/lvC^؝2XDȉL"0_~S`p߶ΣT> 9ѫNai۔2H HXI =Z3!DvB N>^+94mAٓ9Yfh8Ym?{=\Ņ7ut4Lg4&#$o~qG!xU:ȩA@WVE-e`1v$+յ&5! 7c24q&;}X/QȲW[LhȈQA@Q-WFݪ*Q7tǟ>qu':CѸ-&1ʹ0J(zi2pEEVmO=?rn߁WF;?~nz}zuq}2޻}avg,a_ q  A+` AK@e9n.[};wğBe՝)ʜz<V'pԴMzJm@nrAfnwa+Uɽgn/2jU/Un6m۴m4/Z;t[Eim`Һrpv1I 1dGݶȹi=[D3GQ'o{EͬjB~Yl*~벌Z-ͤ(BWO_HwM`(d-0{3f058Rk*GXy3 pWBֆh^v;Ua7f2 AFUŜ D2+zͮ Y!qm; ϽMނWfp؞M퟊97b}i^7]3;͇*:tmJIH@ b EPٙ 5>xw=x5^,z;gϹm&hR3ǓZ5;85=je?g⅔ M'N7=5=533ۛjIJ/.]GpqB,JIi`3Vj0ƓTV{=i&8A{pܴM*Dx2J#ʤe(`E;z?i$]Z7`eTFMok@9 9T7l'm֎$eF9ׇMMρ++aҢIVe#sѭur4P $ Ǔ's5vR XΏިO,nԓ۷>Y'XM B!,0u"IAEؚ_9g|WYHCEYfSrsjIE,; 3ßbDīd!r ?^W.3;!ebh 2ʪR&OY.HdXac&\'h33T.lds UQF"tyctayuN"VUU@SorOkˀ!IReEf5WN61ޖEfixQAf E`003h 3^ff9bp P;02،6!! 6Z2:;JXd,y8iRU6uhg&kpn%KVR\  @ (]-Yxw8-Ӛ˗'>ѓ_ mG|S,Dc2~?[\_b03pd1V> [̛e MSmc d YY tfܨS0?{4ce+a3ߩb1ӇHjK˩ eQ+1H`Uq77  D̂Py΄ypr*XlRV !`zA(ѠsBhV\2[9N&'yEY0>ZmCvO~3KV77,l7=d_]YOLA(Q"wEHOͭ!ש}'g?W " 6VV~o|7.Ǣ``tDR,$ ;zqJl6vU!7m. D@h0hҤ[= =msmw{mv &dTUa 3"bG._hPU hjl!2D) șC 1쭻@"n45Brd䎺uJENQYHBinmۥv:qQr{w_6ьfr?yɓ'ou@w義;ZZ3ɠ{*77;EZtGcZixct~mjvt7֛qAH$" !SQ(¸iFrs&f\Y_ ;EQZ_/ݪU,E( Af6rSnfB\ a!%4 /:jza$}}T_^;N;Uίm]Uw `cuqul Hq;\3SN6ԃFfә3gX]N\۵hE:%*!A7Gv(YS|m0NqŠ~Ԯ^ ۱V7EfdZY^p-ށW;F'iG"pTtqse}n5;3Hkmue#hUfD</ yWe(ìIF$=ĩk];6g/moR=?C%)M\Z\t*,f4Lu IYB;z蚫MtX)ktUr>ѴmfRGvVSJr1tWJ9b-JSɞ3VTI*NOg۹Rޝ y2SMԅfyes}Sg.n x|x^ ㊻?_Ou:"^kf8^I9N^'T&"Ea;]\ӭ=]SaF:5)gwAH 4NQ\{8x~ЌۦX5)}\7kN^72@{w@|C++C;RQ4q {w6\f!2QMaSV˪Lmrosv F rP,tQB;3XáS/[{fߏBk-5mxveOMujUL U{.,t1`c<5oꢟmGUO*~yuI::㖩j8<32;^(zrNVmޜ˛ͪt?e`&xg]ohFz=sj3:3:6ӟZJh4P?Wܽ0=әY-\rN7G)s3ffݢJ)ľٹvnVzNܶI cbOO 7{ib{S3'\.7A1O,X!Sk: ˂Uyn0IN/.fAY8qo\{W^}e9&+7)EYUfNw<?;jx6p%9a Ôw3;Zlg7anXUq_C`9 p}cnOu|wrw7r􋓶u*CB쒅{e0PޙzثbXTBMV@)4@p[qܶ!2X:}ĥK]5W(?~g>s A $:3b,$D@b, ND޷q?rGvbR;Mu dɓGO}ʫ·,Vw} {l:e+X{E3idt.ȭ/&YJ9'נLe'Ve(N( W!Tk:FMZ^i+E& \\$`SE<'KmjͰgdh^\^ILf鹙i[ŵU, @SWV0zatY_)j45\q`mZ\i&ܯzҤ<9o_/. Fw0,xn ^=2f||<șѰ ˳Ì4#@<2H$wIKPABJH}sGG=ZF`b$N' ZxɊ}UTJH.AI!ڱXnYZSVUڜsӤ61g  ``˙@Bhs9@׭b0AD,<ʿc?x߁W@F#&h2]s̴,b46}V.=uL߯N}W&c.'"&MDh*4i'AIx۶[f/iNe$9y"eNu{ $F5I$U7~O~ǻ{~_enE(< PU=?R=jO.\X[\dJ )0M.8I MmdWV.^ޔX ^wnd020) !{MOzb=ۧvsns;ݭxzAQrhf$@@Qd0E( t]8?zXON|p`欼6^۔'IEY6cI$61[D'䜴Pʭ+)թc eQHܒ2P BԮn 66ڪ!9+@m _'mۃWfiK+ePSOfO G#W3s{N (kxܮ6,2 ep!g]r ApW`MIE#̢d!deѰEc`1po{UBAЂQ&)@~O]Wi (nB<膲ShA=Y@\̞V9Am^v*FԦ$M}zΪ uxShKeap٬k\+yǶ ^7gg!ٟ~ܷ[_鞣Zr"M=eB4BremR5ѫ/<{p4Lڜܽ(`!AE|޶2P AsQp3R&M(t={FNBhHZ0cP`E u +Eh"@r [OUGn% X=OCAa1ŽnU:|c0Z ?8%H0.Rr3#a$n3‹KUUfL&u"Zi9i2iC;~-6ض}?U\f̑A A@[, e5 ȺNB8O6GScEx[owXX_]G24ۯ<Bqh2)h'U{\9άW"lٿqg.cd9!Xx@PH5m8ovzW Ixz)s&o禋NPŵe.b7Ve*ccc}yi:׾nǮ_}>//.L`B$ϞI f-fAppŲ)e,BC|2i~`ΛofE|,9k- $9r@wI,FϢw2D2g434Jh4cjSSSTE # JΞMc 8ie0c4^_og(7Ni<7ݝ*Ka~~yܥE&"$Jtrt95۟nX옛v6(TmnB4]th;e90! ǟ^C7ng{J`tONR,]n@rϒQN@Ҍ\OQ^xok!۠>ۙD (a  4 @d4] NrKZ,0ʀNXIʮO;~ ^^ctՙlybfSumn$owV)M6)(wgeJd0 ^FR`U^M{en]$bIPX1mE=peژjʲ2d+buN=^kԡ7-w_>>e!9Rs=A `4Pxڜ`徃wعow( AE`.0)@BN႙\Qd U!t @RΚ|~Lsk˫ XݲoSNo-)LsMېN+ڔHtNۦܤ1Yћ֕3 @ $HSƳW6ga!lN y2\^_j hnmG>pbcMnhܕrP`=8<|}?ϻN9 9V4,ɵYH$K4 \bAA&iQ_ (C QcY=ҌF3,u%R1<$8af .*wCį'A< ǁhҨ)9D%\(HM !=$ CErdrFW_iOG2vvw\Nzxs{޼#O3ͩʴsjyrIƻ}\ɓϮ,!hNu#¡@eѰ.Fk+Kgfv :S-3E+ؙs o> T0pxwBAmA7?uggqlleu}nniiic/=Ow6vv %%F ! u]2#-ooT̲ I1hf_jD@%@) IN "A'8AHrtk )ʕϓޞ1`zzsp1W-d,Ў*u[WR 3=Uu7os˳)1ETDwYh8Bh^+kbVNRX r b+[ @9f[̀39w0hf^#D4opw3O8253;[]]|ɝݭ޻?vwN CHw:S_+hY5D c/9/_~?wnc`K$H"$H@LH `?}淾<2iQBѕ5vvn~Ӭ*E `LysV c¥ŹNdvu91ATVe#4&L{ըi*\EQJ2 Z4g[QZuJDLץy*F?9̲ʙwή_+{7no}~Y Ti={~,8ehWNDj+_Y{]{{߿~A͚I„ CJ$B4DSu?o>—HÏ7e q0tv+v-t!)9C3QBI˭\(fA0$w7?v , 0tâV`*qq֤eRh: v{rM@w@PJftQwG,/_Y[{p姮\߹Ϯ_^^DylLMO?uz4<$=ݻwڵ>:>z {k_;wCHI$QAIqN 8A4LRJry;!x`X$!Yl hF2"U"M&^hdUrydFbI۸* Ѭ.jB$$H]>f6=ؙ?~}o bRWTg*_>M<<C\yP]ťٙg޸͛n>ׅ $(H!QR43'D)ӿ;ygAߥQ1ǂx$h¼whwn pE@p%Y03LI@(Luݕ JrSaAP(#Arc$it5~fh۸{x\u+gWNY={1x"x8{! Yzl!NW(֭k\{eJ@BB 0i;;^ybC"%%B.HN+Vu]gAê*H#@,Jy*GN"%L"  wv d$D tH M7sĠBgfaԙTAw j:3Y$-H)F8.Ǽ/cڭ,X9O_z36ƒDbB%9`4 F_7~+fMyBBFkna,x_:j^W&K# U]W(, 3+>{7?[#qf -_/~뻭".B4$nIH L$% HArAFwd ˣD HH$&$H $%DLtf=ԋ?/xz<[[{;[noV3w.FD D1saunw7oIHBןo˧l\ F 1!H *q "hو}W~ٜƑ /_rH'@@8BF$$@F/>&NǏfL=rn<lmnEQT2Sȧ>;sxQ>>,F`}p0,FaYUJ1o&3!;r女Cqz;;SYVH`T22yh4gYJY+ Tdyv|>k4⩾{jVuQf:4h <1U9%U=rg[+ot>꺙GIDP>}w݃qQe,…Kg/O,PŃ{^ =,TUbY]Vdg!ܓMP!!\ݙ[l:7~]:1*Q*,фCģN$%o!) IPNx4NxdNxdNxdNxdNxdNxr^ .z@5IENDB`stella-5.1.1/docs/graphics/debugger_audiotab.png000066400000000000000000000045321324334165500217060ustar00rootroot00000000000000PNG  IHDRFrsRGBgAMA aPLTE@@@hhhbɯ|) pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^횋r E6I>Yf5=# Ut"%; F$_y`44B68pE^h:_4؝R9R?X 8y=uB хBht!4].FB ǟTL?; N:$Tu=$L |UB#].' L~!?gqbB хBht]^=51s$4](5ҿ9PaE²s!wȦF> J뱇BU3FFR[SY-qdO Kڶ~S/ehD@X ˢFly6ڞe8׈ƄX(dӎ ,GEZ=s7/\ { х߁=w5хBhta[#+Of_#5dB хRtZĪ"4Ve4ʑ5dǶ*?B#`̌iх;kd|41ʓq(ʓ)4=-F3*6vʓ1f ӎ%c Hc1+OȚ'].k|hFob2(TAMRX@j@{n-S @h nlEH]n0W k 4L;5mbB(/\ftP,/u-4^Wsl $Sn<StvjHٸ}mZ>CfZ<1=j#FB х?K$IENDB`stella-5.1.1/docs/graphics/debugger_bankcomplex.png000066400000000000000000000245111324334165500224200ustar00rootroot00000000000000PNG  IHDRdnsRGBgAMA aPLTE@@@hhhɯ|ϥ pHYstKtEXtSoftwarepaint.net 4.0.19ֲd%IDATx^흇6D}˯s4j},&E45,6U,6U,6UL\cWɢlzU*W,2p}.N&|ő,%WY+\ii,<"YEE:*wY|8?cb0<L}Dg->ش+g"%;Y|Fcax^mVGV67γʺJ.Y찝Žg?:IeLd,ʝD8g;EJ!b$jlY,vg=L*s_5Nʉ̢߭(},"r>̞-ipwvLbYAʁIij!.K`3sY1:"̙̱1:}AыE3E:&he/z #*8E>&uap"$Čɱ>}à+*f~<P.`;l]H; ٱ $YkӨzN싫_ˢf2F8"AN)*J̳ AHf3t }5;6`sܓĂʢmORyW&HҼQ_B.OEQǏ%6BJ,,~r_Ft ߧvh/9Y| G,Oewq,dQzigQy̢]EywhiAgBgBgBgBgBgBgBgBg(t*t*H,>Z',6,e%_؜"BU&-ePRO /iá3p6B+M&Xx"KڛO'9E | dOH^<؍ڛ]Û-ss6Ŏa=7o}{l %!9dVbЄcNQ6.2 ]A/F8%4h%]ɸ,ǚCl},;Cd& tRpubF(x18[9γE̐5 paăq7[4e7014 +=2 Lx3 RɓVģpwO7Yٶ> !Q*0 #-`pUIdxU2!fcBAk4 !-D$WORt^d1|_o.}](^_\bS2Ydsc( b0Ŧ G7TTTaE#`䟇\foC/#Oϲ)ߊ|,"#Yy83C7HjylYC 45=ZFXq@ͩp]q"XtQqf :J"*"9$3;(yRef(,-Q4a,JsSs,n0'`@R#ƽQ0>K0Ʉk/gQ3fqGj"d5qp)=q/Yd`ѕ~IUxa=9Û.a{(EƤ 퉎'N8pt\SLY ~6WHpxf)̂d&DC&]XS(MVYSyCa4Y)쮚,ki5B-\{ST" !qfã9*h"O:8AQytN͌9&P=5BpЈo`"G&mZEQ0neSVfDY&V6ÇEP;FXa#xͦ`KGCD[05ZZnVQ{9E Q :#aKfQL, A-#4<[b3.P` .yPe=&=PK>Ϣ?xe5_яC~"PE^\D(܊bSbSbSbSbSbSY_3 h{Wh[MaiCrf0'm/#(ŕ)jv1qyD 4y =t1,p6PKGE).ŭLJۛəϤÀe͢ha;&+UYxvjf3DLJ0m,%ֳrcaK3I0 Or♖Tk|FO- m3DɤB )Q&K&E4z"uK8bgJHyF5{ʼn"y [4N XZ;G 4Xu%*Q9"fPi%Q yHiPc%6lF1Xu(_4S[}Qa,hNKTHBt>#h^ o6& > Zf eǸ]W~'Yl[YwjX YlYlYlYlYlYfyG?Lt*t*V+YlYlYlYlYlY+jzS_ŝ{[SpYʎa< Q4}Y&mD,+8p-|;bvJ #fJ'85wx%5lm/o&QkQZz#=/o2 uIf+M8!-vlQЙLfmeY`V?^DEKy{e%gy2gyQ8Y1㄃idAL[Za$YQk|Fa?XJ 1v5!-pdC2Rvp>= 4f;`Z4`kH*ۻAY,5 ځQ؄;I< G*u}#6챾Yh j*Z%^Gr#yf%6yYģJϨ3KAm@Gl,D8MP5]O? }w=wr,^9 :,t*t*t*t*t*$t?B_Fi e~GkfeOpYSL+xh IM\YY?kOX.(^b<;" Ni3J'(fY *oG8j-JKoBVf~ÿ&PE4Nc& bm };QЙLfme 1]~ނPNjh)o-ßӡ ED&o G4 fp7,t2#iK+.Tnq0l`p`IDW3iArksw8Ld"9qaī`]ˆP{4sxXNY̴,vYg-hD3+90BV٬@,.`plk.`ͲZ4`kH*;uIf0F) "/Gk4Jb&܁Mָ#Ѥ{,ڀf"y5E^P#:&Ylghb%3KAm@Gl,5A#OYzOa^#ǽae2T_X"YlHgB,!9%YlTTTTTTTTTTTTTTTTTTTTYq\gQ,Ŧ Ŧ Ŧ 3qc:Eϝ`>(sAz$IWt Ӑ1`fѲCqCi@% &:~(qxƦ:VKΩ0/gG!ƶ|0_ &Xp$2AjuF%J%`0HI♖+M @g!4U.#{e 3xI ,9;ŋki80cp;@NJ 8PYF~y,Y$ =/ ,x(Z%ϣʍbᒊgAMx^YBp>}]\p"^{_;Y|7_TTTYǑkg4,6U,6U,6U,6U,6U,6U,6U,6U,6U,6U,6U,6UY"j>h?YUM3BUa6nEdo4S WZ95<8(4DЂHٱ,ј͙ i$g!EKNKsɄtn&"&&}գY\͡$MC0Jnl6Ң79 p̶bP9a\4͔EI0ā^iCSbSbSbSbSbSbSbSf_C\5[Y TnMg(P5E@Et["q|ɮȄ+AU`hE<&jwvSP -GDKRxlVnVB^HiUbAEk5"uk"Ӑ&Z 5x4'T2:遍 =Z5[!tPddmp$=7%L?ۣ[ eN l?@B}gHK3Ȓng{"uk0FDŽ ^i5Q2-X5˝N(FxR\"O'?;#@Kqs WnjCB,"d/!eMHt|"=Kqs Wnz-! Zck%H}sQfI-m =]^׭Y4 -6a-NlU nƊ}ݚF a0BfQh! V;l62n(+.+8䊵x{E֬6߾3W B܇99,eR# qF$=P !+W8EǼ"uk;~(QX=g[Y TneqsH3OUn_eH3OUnUk}ݚfA:M:MNj yU(?߅O N.XmEDNSw"*;q jfo Y$pV7e )ҖlYSX@Y@Pa:">||^.4Ȍ=c7kqb$.Yckm|5^k l5";= :gk07 FhDNL(fT-yC [׀KW{.d5jw+O /_a&c!5xsaAsrXʤG\ɳ9:\yҵpv0%:Ȥ^l@DR%% Yͽ$dŠ RޕOAJz y^^yJg1ѽ-8}}΁gX xWa+y7MXHTaaE.>G֬r8e6!}׭YcENc"F BJtPF*IO}׭Y}HELj};2[-zrPsaF$Ê &?[ML =mtl=yBCp&=Ig*8snzC,<)8};b[rL\%ZzpPIxsnzC$,:> ʼn"2A% ϑ5aK. ="D# wЮF^x!#iⰢ S#uk[o/p0!. RRAsrXʤGû [){i⅌ImWlexsnɽw(-9 .Z5E@E<r3=/Q =2E}:LgYA׮(v 0l-n!_"O:'o;Yl^g#$p7| C+qmvTٚ Śu&\Fbe&ڞ.{,;\eL2 MH0;'mii2\Z3'a/GK&e AYDKb],CGN&ekR̘'a/GK&elòH,"mor)ma/GK&e ! LP+b2h!<~1,aGGs BE\v oV2 K%O_@%_GtOg,~"Y>E}nmbSbSbSbSbSbSbSbS[>PuIENDB`stella-5.1.1/docs/graphics/debugger_banksimple.png000066400000000000000000000072721324334165500222470ustar00rootroot00000000000000PNG  IHDRsRGBgAMA aPLTE@@@hhhɯ|ϥ. pHYstKtEXtSoftwarepaint.net 4.0.19ֲd IDATx^휍b;3y_[1$E K0lvr'fF{8Q<+zĉ2S/bÉN% xԉs'8eS_Nmn\ax |wH묫*K|燌st#6yr6[ 82:cwYV4;?p}'.~RzN<x`Eviq"HO,SU}EЫm^'_N C3.HA~&1̊C M3wOD]&3gD]vZ3Y(zXUQij6XWy׉@, )aMK9ėS ğdp=։Or S։G>~މ/'N<xJ',+| D Or' p"r' p"rpz܉wN9AF'OsD `D 4X|8t"U!LN@A!]9酣93'l.DxqbO1F!QF& cy:QSk_lއHAC13ύ]Mb3,ba.|3א 9QA42男5M\DFki ,#C8-9ݴ W~ݙ|?>܉bԞtskpjƎ"/NqESDX:#N,D55AFHJGM:ѯBH'gcg^oL G0Q8cy+*˜I-;sM vrJ5+gBB?q>3zQc ^ EK TBT<3>@'Lr*H|G$L+J '9<'9ω xN9s"ȁ3$ Ueǿ.#qw'щxNWω;ߓ )v. qw'fD<'Dܝ /ω:9w{".Fs"|Nes"|ND'9\E>'~n}N3 [D8N9AD8N9AD8N1 KIENDB`stella-5.1.1/docs/graphics/debugger_bpstatus.png000066400000000000000000000005161324334165500217610ustar00rootroot00000000000000PNG  IHDR> 8 pHYs&:4IDATx 0@юq]9< #xRIy# ^;p:O H0F14H H. #Y־{iJCۃXf%= Cۤl~ې.mni3nb*.Muե]u #κͷ*ֺtMHY^-i0DlSIڦ: .>񿿯tAnI72Wf@tA@g>^O=xqIENDB`stella-5.1.1/docs/graphics/debugger_cpuregs.png000066400000000000000000000037751324334165500215760ustar00rootroot00000000000000PNG  IHDRZG pHYs&:4IDATxqG@1 óЉC ]*P15g֖5 IIII'54mVXݤ?~KI|XI0)`R&pI_o`RLzkSzkLj?.ĻIL3i[u4`߽Y2)SLw,XtvZLT;NL] Z'I6i:iԤ3)SLX'̤NA54i)&0ǤN73)nMziL P- I2)`R&pIiMmQP[]t~ବ8ڢ{3֑Z LʤL &eR&eR0)2)CMz9ZvIIu: " mipVtJO#6`Ҏg'k>.+ͲrWRų.0)MHܤxv)&}X]`.]gǤwj@뭻w.0iw{vq ,#F ۭc҆NϤI1ߤ+-bҶ6aR&gZ)]Lʤ8&M2)8w5iO?2)=R1˗޺|0{n- &eR&eRIILʤLʤ`RuqZډEŤbR1)ĤLʤL &eR&eRIIP&eR&ʼn&mI뛴a~G Yh_&fҚ닛`>dΟ$P`9&Mϟ4hFk}UIUbPҮ2eR&XIUbҼLʤ0RMjIŤLzI5#0)>ƤmgLʤLʤLʤxIr IᶨNo|2?2{n- 0)2)IILʤLʤ`RuqRIqIŤ2)2)IILʤL <(2)Iu[tmёwT~ҡIe0dSqRIV1)Vq\Ia.pVx혔IIݕu"k4avϤLI#JyvIw5,IŤNAĤ2]&NIqr jSPL uw2xIԽ{EͻĉLʤLʤ2)2)II8㤎TL*&ILʤLʤ`R&eR&L~7T'&eR0f&0.ot-{u|W5/#u3t7;DS7g0 k4%#R/_ftI|7ȨIɪI;)&mXLϙ?x)5iM~LZ<&_ٽޤs陞sĤ%Er6oaR8=&]!=2)j4EaK:/2)IbR&eR0iɛeMMSPשȴ)(&šuGF>#Us2?OW|0ۢn- &eR&eRIILʤLʤ`RuqRIS PcRm`UI=2I=¤rLʤL n/wzI&T ; ?DD_%ԿJۏGꧨ]`1-]6iR{f`Dsֿp?&ZI7I4iCΤ ߋ}CnS3}u/Sq0URV`AIGc*3ZѮbUi4>#MZ#1)N,kUE"CG~œW8q)5- WjqIÉt|Z))v.7]6i$:ݤcf#MZ 3iDSL;‡lVObP0 dңb#ݭ˜60r f4)뤳nl 89{fl5`_0cNnM{G{=޽{P$aRI9I&eR&tI5u&&0)0)0)/ĆhT=QIENDB`stella-5.1.1/docs/graphics/debugger_dataops.png000066400000000000000000000007751324334165500215560ustar00rootroot00000000000000PNG  IHDR[u pHYs&:4IDATxm0PF`8 ё*1GJJ-'NTr8S'D!BȵJ;Ho;ǹh'B{;㇮EP!B MOHȥV;9k!BH)k[)g k[U| D FȖܲs$ЂHЭ<'n"'^eE&o`Ș&=*>Gf]S9BdϞ\í(\-kڒJUhKWWR,kzWtDzz ^5;-dͥg!BS)`!BD-@o""D4#"r:N!BS)^C"᧭Ӊ绥D_ܺ9VgEG_#R.;CE*}b爽F=fUrJ9 "D!?ÇfsIENDB`stella-5.1.1/docs/graphics/debugger_globalbuttons.png000066400000000000000000000025721324334165500227770ustar00rootroot00000000000000PNG  IHDRsGgAMA a pHYs(JtEXtSoftwarepaint.net 4.0.19ֲdIDATx^헋87 l8ądq8=h<$r$6_ح@?~=P *f i̯ﷲ}٦/1MW_YI^1g-1}bR1.&V1AtdSULg dZgz V1h=3aٳ*n9`]pIKZJ33v1%`Y*$R1' lG\Ӿ[c&}wy{L9N bR1y{LYV13ΡbqxLf1s(iasY4sSb9۳ڹ9.|J̤^=+]ݹIۃOf9A jgW3a;p9-8,fpt(L6;=;W3Y+LyĬΘ;T@*f syN>o?L183H 1<ٯƴ?L#bdY bR1lL[Qf% jg+jaab"():&w]#(SsɘIμ_'r;=6J. r׭udܾ?}~g6Jn@iGfY%cxN `KL2F$cϮZ]6|U1T@6H3f?k'|d7]61*f 3He~+ۗmwtܿf- M` s!'Kl셭/AiHBq~WK_6aDB/@%H\ק# HLItH ]O#!fVo+6m +^[Op&zH{&v۸nP {n[`ں~9.> ic_B"^nFl]@7(ކ=-X{mV?[gIH< 76Jwٺ_nS yY$#rKkru{z|]KWo(Wb1ྲྀn_R !}{ [+]%t$_W7{mV? lܥ{Ɨ퓐;]ٺ_nJ &7/,nں~mHCB*Artfi#[+M$ŗ ^[,w)^$$vݔxMrLsx5׺hbM utֵ tWm(w)z /bὶn+VajXoQ{m=-!vNXuݖw+ {͖WrO%%4ĕ{}*k/Z a2A  2/JIP2HJ($% JI %ARB )dP2HJ($% JI eפsnLg%ԻߏVlfk͂vi"yͱ/i?|/0)ÍlMY.mjtyN;n֔7s6Z:S^ٚq65{PHvgkęfիMrگ7wkcuԜم.zU$]c>X8JZGɨo ~~hrźc9g齘܉ SYw,, ~ :bB.3kLq,30AږMLq,ب ~ "[ u9f?Ŗ51S-vVZf?*%6L}ز!Ywq\/|C7bt$PDI=vt!% 2 F!|!CO9B sBe wÔI8&?tnNS+mуxU+kABǺ==zx׽ Famm D57;kݕnOd"u→b-#!FB1 ] B64?k3IM"1%KKB_TD|!{PO2k:pI˓j4ǔ/aMagjgt~!uCc, +"DBYv{~"%40!m3aWky) R QwunOOd" abS.Id"Z~@O9H %LP ~nPO29O!w29OH _, ji #vU9BLo Hϗ uޕ@=SH ))ӤiRBJL3SW;%1!P?3PL!% <<4 "V>\k 3BpI7)!}Vn5] 3BpIBG|v=תmD3ߕ@=SH )E(_9mwL)F.}yFi鶻W&PRBʦ}Vr^@=SO'3Z*Ov#z^H=* u.Hz-!jRI&Rwu Riܮfhͽ?zl 8Jd")& lP$S>s܂KĶ%8LKgv,.Wo33@X-ǚ{L}F:di%jm |n5] 3Ϋ< M}{uȮd<*EBF4] 3΋ЃO7p_զW A_)g 3N#~;%q_AI|yR8aFʙn{eNws_1G|yR;C)!}7˅N H1R>#z9W{AXƧtD( Q#7$P8;N\p7\;[6رH,aʭh 3vG4)ྂ9a CʻgEU$=`tv$PR H!% 2IBO$#H %ARB t2$ /λ'HJ($% R$$?fPE6d⟙p(z i1k)Yu}pI Yl""@8| OVH %%JH>.4!EaЎ8O\3Jwl+u*%IZ !8]^2"#m_]d@wOXA4IwQ q:5=QBzu+kFl$D#-lqW^XFpd#2%!OjmZ$ Y{ ~P^FBr Kȕt KS2EG ҆YGK!k/zGv>Onŗ wJBx?_B|*\sBg=([BGG1w('WX{ piq^;)/$ Tbb*"!H"%uD!*jͰ5 RѐuI }QZ* !\DC1>I Q uzV)RB?DKU" UaNʵH6;)/+nIfTB)NJy )#% J$u①D%s$@+%e1Þd11e9QU&0{O⅄%H(&r%A\o?@.4[z"$JHB,W'.+1kȶ Ts'JBܛ╼8$d0C!L`N#$%TYix)!2$,ʸk[B r' ~b 9؛a*HMUK0DWB`(-!{YdtQ[8,=%jRݩLb>DIAA)# $% JI %A~:ovn>ocH %Aq MД:N#!9Hf H%/r0Ш%LQj ~44OjkmNh4;r'`1kȶ 2ͪ-ʰ p +-7xͭfS)wAq x'KRH2+4={S>ɝ-Q]~s+|etΔ5)axiKQ2m,"t)!K-(WEIkevS}/&\Q$ {}cBpUD,y ӤCTeHe1its),BU q։!|H8&XjIN*"w$9(!Y}PB ݤ>s),z`VEWUV(qRUer 02S#_;:1)ig$ۙg#2By׌#3x)a`ςS.< tL0JRRIHB)䎇D̘eOĉ[g*.I<&x2ǎȨgPI-! up|\T Ar){ 9 )*䞳.2 Wl DPQaJ gaSHQW`\5{d [k_Q/u X1*G2얐x%h.Ϡ(ɐД `J$dh#xf~G)2(,[TBt}%JREb$%tA$ĺ&8OJ1~;dt||%<)$ ՗g܉SJǷڂ$P/ϸo8bbK2'oNJ*!|V>LL$ 1OCXanIҠ`oOH8&P/!< :Lp{C)SFxQ g#I^B?fe Xu22'_P?{͊0KTuz'!mS,>F[rƜP Ϋtϕu*q܉N _կ%v!%)eΫiLJ vDJŭ'{z;n)6,i6 aA\3#HH{ѝ|ssc#z8S(*)q9&!u`M|ssC7|ʗ4k 494{HB(@$̋]q#71s K2t S9 {$$i&sCˆxΦ|IBcT%d9&!YfBt7Q{̏ꎗDFo04QyNHHKi8sw . $IJh4 K(ٯp)$_nVKRBcB֐iߑQRB )dP2HJ( ޿Ϡ!od^+,!|3BJ5)MWG3I 1MB1?fɁОzX%NYr4}ժB CQrv8bJfiKC;DZ!EWHBϒP{.D[BP9 ɲ/e`㱬/uEƁDFfjdAպ3*!Kحl5bx<#S;#!nj$x~?ʝaOi_:ABy,ksʪ̝{$dk1CqE+H(˹Sc)oou6vBSp j'HHUoPww{~7ti2*Rvm?2 4v KHA=(*CNIA0H%G4B%\X"w;tҪ@tBBwI'r{ķXwB௲k`W#ΰ:凋[sŀ0xOJ&cG,Hĩ&#2Yd<`4QV#9%Ǿ4uGql3lW8.!5w&wo~߫V|$)uD9l!wdG2ja>)$ppɥa %LJ($% JI %!ͻdIENDB`stella-5.1.1/docs/graphics/debugger_main.png000066400000000000000000002507541324334165500210530ustar00rootroot00000000000000PNG  IHDR^RvgAMA a pHYs  tEXtSoftwarepaint.net 4.0.19ֲdIDATx^/U s,b$$ # @,&H2b؀3,A&Lظ=a}{V嵿+3+UYdU}W|2WUVU<'< Ozғ'?xS( BP( B9hEձR,߹VWB!P!0,TJCS1.pj? PwZd&B9-9"",^"!R1.pj? PwZl&B!-u>Tt%<%$R1.pj? PwZl&B!3Wt%<%$R1.pj? PwZl&0MG妞ke<%$R1.pj? PwZl&~C7޻%4]B9L. *"OeYLXpwHp0@UF^iL:"?Kܴzžyv=]MLBL.J/MTKѲgNKz1@t b]~*^iL:"lշKܴzžyPn0$l*TGF.*XШ VC^*IB ! Sal(48!NdNUpIUE/W47-,kPD%4ޅ=UDjZ}q"w_\ )]UC"v{஀.!dL.JX7Ku*M~oF=ui2L"{% =:XlfI_<ݶ TeB,N[ x}fG*8b;ꊲV}-z9<>7-lyޅ=U kcJ E,dRq-h¨Gg W $;_஀!dL.JX7ͬȆMCW!OegrK,IX">Noz='U٭p/\t?NdNUp*RE$FMNPɖ@$:骈{L,TBتB5Mqhcp5i S%2E$FM|HX]SK(^ kAeM/G`5x,j DHBT X1B*-͜ < TeTœ@SLzWJQ}԰PE=%,j H <d?z zhDܴb!Eb1!ux3 M5.{o9&lYˑ+XM=5fB,&UY%Dɛ^fcdCף驄"4Zvx&WĒ%T l =]~*Jzmm@LTQ֬fC%O`^^:zDSI{CqӪݣ^Ƿz4#7MaЄYӞj&&\hGs!|ɽcQSJN@C"W஀;&UY%Dɛ%0)1GPTy- <^bIBz%H{X0@U6 ,=NdNUp3dhBPSAتgzL@(nZo#̬ȆMA]h¬iO5{ Leф&1=K+XMnCJ Co wt=2*!L&+4κihe3i'{% =: )po(ʤ!tB~* ! Nb3٣SF) ~3+ TzAț^o<d?zzъLMv:!oz=Y ӛ^ϲ]hiO5^7z,9zqY4'8Jh|ɽcQSYVDF.L"K,I+Px]!pj? PwZl&{tӨD5Ŝ&$uH)Tx?43;Ek S)id^H׽@3/&W: S{c!Sb|qhfp>CfB`f= "w,!frQUB*,+UY["Oei&%$\^(<ݼ8;-6IGd?*ZydxxܴwgZxv^AEC_fG@*! VzǢxZ`*rpW@_&UY%D9*4Zv%${% w<ݼ8;-6IGd?vyX]S#W{ DG0$l*93j%uB~*#L&-/gcwaOuK<(bG mbB6eQ6{Y9EntDS1.pj? PwZd&tX]S#{F9n8Y9EnD8'Ux}3h3oZ {\b|!@=rpWh1 z7!Y9EnDBR1.pj? PwZ`>.v:?޻%G#w61 !s۵z[BSF/DUx}3l0U#paw%T5] =V rVe!6ͻCUx}3!B9qY^Rl֜'?p}_WTedp? !dtO RM/=B-e6o%J%e;;-5I+N228NdBO/AA. 7 ,|H*!]% ߞ~+ v]6CˣO@Ux}f2n HܴHGS^AvnpZd]{ovAX;T;tarQoO*)-,+N228Nd`]E:ы$BߛK7(a.҅EU=|V⦜Zȳlx8;-6IGd?vz{G/NNKl }oB.= ߠt@H&UD<rj"ϲy| B~*#o7^iL:"lշKܴHG{]^\zʤpZd]{ovAX;B0ʷ'O+gT7ԲETe_cO@U1q=Nd`]E:^t͚%}|դ A&Cd]T{uLxKSuHXN$gfrQoO*P*_[9ߔSAcLXaGO@U1ba=NdO tgе, d?vF~W %.kIY.'_$Ck&=F%dH6InG*!#"R`!e~"赼ǜ"CL.@SJ妜ZȏP6Gc=a2b cW|tm ^_B<V= nZJi/W _!/NB`^<_5i61*!CA.oқ^*!#*޿ Jw ^{ 2"'grQoO*P1 M9lyr1VN-ͩH,]<}_WTeĈx;-6=:U9+aV}-z'^YBܴH U47ͬ':w-z/G4! &=t됰 Jw?Zz4ə\TʧqSN-[f4GC Цx8ʈjxO) NdNUpa* ,QofQS_"`fKM^.u|KGDEMlpy- _ WQ_<_5ir1*!CA.MTi ^:WuHXz-Noz=L.@SJǖ)-Fߛ^*k' Sa&LTQjȋ9J*ԛY6P'd?*%sqӪzD^Y̢D:AM; _G̫^\M5yjcTBd]TZ&wAn@kyOtz$gfrQoO*:Z:^[3 7ԲEf> F7x8ʈjxO) NdNUp(ͬ(SeQS_" #lWW,3V\y,QofQS_" 轩~Ջ+ MoB!I{Q  wnR(݌{2K ®C7(mFz-Noz=L.@7ԲE~~wB|&9;ɄJl/hK)dz* B~*#F/!!.UwZl&{t(EofE=|K{Ht̬':"lW(3GgMw -="Y2Zn@oF yjQxQ  w!{ ٨9'CJ3CoPEʚ^&93|{"PM9lG?,y&1.I; B~*#F: b3٣SF%!/41$EJ_PP`W7-@b2/$:X*UJ~ Ũ]׭7uaō<( dx]zAnL.@7ԲEo}Wvud3ɎqIO@U1T=N䃡 87CتgC ⦵GisnCi wMV٥a~"ҋEU*gCh|{'ɮ'}>B;:nOp}!{*|?گTeĨz;-~2^6z{G/Nq wMV٥a0w|zܑvSBR҂|2b¸t\x}3hg>nZы$BߛK7(a.3(p#7E3#hO??&_ hP#R/eϤ V1Z" %H6߅7Y!foPCCHZU6\6z}mduh׽yʈjDN gBpZd]{ovAX;T;taoo3%e l"%=Í_$hz}!eȤ"źlrHdO_P$BߛK7(ݡ! %|{"PD,)o%U*$uhN#jDN̄C;"'(t;w/@.$9ٛG|R` Jw-r5XS1Uͼ@dc0Y(ʷ'JĒv^b]e O"taBԾɲydRM| )p b327 1(E[(^i ) w!1e Jw_U':zlH"#1ʷ'J\{v^b]e$'VvSB4ώ<_2bA;-6 !NfyF)CU^.kz=d]0J.coPsxӢY ڐ3ʷ'J\{v^b]e$'VvSBR҂|__;-6 !Nfn5&Vz479a0x]  ߠtA/=T136#2Wr$&UD|< .=Sz\BzxWd$' hΧ=)|{>گTedpɽհ.Ѕ]#4zO3]&Vz4V y |>fXz NUT "8$`rQoO*cj\{'^6KĻj'{% w<]X8/Ds6kwZl&wAº BޑNf2StCU^+kz=d]0J.coPp.bQsz Lr &UD:֫4tīuo#^DvW'{~otaBԾɲ\ b3 . \7MO]P@S@BpW zL~)͔vyj eMGSl pSx}̐ Jw?`f=F6N01\TG֫T74tīkGnJz >*īwN*P9zW"O@+N ќ,ɵ;-6K!R Y$KFֹk^o^6LiGs̎CU^(kz=d]0J.coP31!pI*ߞT>B򄊴GSxu먊>͒W/瞧U* ތ:U .,W9Y6kwZl&wABإXA<:I_ق^ڃyL~38 fJ;dvDNz-orvۦ{=2ZHYA= fcdCEU=|l Β ~r~}_T̒W/瞧U* FMZBf"bIb{2 <]X8/Dsl&L.K:i*"Q:0|ob |nGYڃi~b@ț2pt,"R $B&;>8$¿w~:xQJfcN/*L.@#dOpL=}:Pj'^DvW'Ԋ%C$ƕO@+N ќ/y3>'?ȿIwZl&wABإXA^ "<~^7N?kf=u|{g͎L~^ Y)! %H6߅7Y!fM{n3L.@#dOp6q9 s?ݛ4Zi^"U;٫'թ^fm%t BԾ y#z@UF^i] a`tz% D4GaQ4$%3멣Mb(kz}U&yAo$5ED2pZd]{ovA(AY6brQoO*![3Q8iWleW/瞧Uz~hffJJ'k|=gz@UF^i] a`Z@3M4~r&EA i{{TC(k/ͧ+Y:MY)C! %H6߅7Y!fϛe3-&UD|٣%B%Ӝ1.{tiRKĻj'{::!oz=u*+!WTedp]Хv)VHZ)E40G'gQThH$:lTCLO%o>7NŇ3e(!@&+҃Pzyl&*ߞT>+q9 s?rrW/䮲W$rԛ^Ҹ x0@UF^i] a` <`G$:ףy*&^j`~S5:5Y#|DogP( )&rD (yͺSP(>6@^|V"Ol"5~hfh(O@+N228N.Rh@XABAR4:릉WToCeiRXdKm R@߼7uB3e! dx]zJoPp|{"P4ttDxK*{% w<]8;-6 . 8GCo$?Codg',5_1LY yP8-AA. 7 ޠ~,m1ʷw9l'\ܕTd$'kUx}fr/t tY*_UFFoc>I|Eяړ] ?z}<( dx]zJoP@hYT/甍.-&.!QFZpw5 Sa b3y|[d'^ưCi wMV٥u dLn- QF.5#f;-6Ȳ`'^Ƶ'W2;" %H6߅7Y!f/e3-/'D/Nl^!pj? PwZl& 5eXy'W2;" 'A/'~!r!AA.dorICB j1f7^3dޠ6fLnEU>.-&&vSalwx}3YSy#W@cB:"x"'0_5駞5Me^3dޠ6n/)"QSźTl DOvd,fr_O l"d".pj? PJx}3Y4r^ |c|դ_uz479a0x] 7iv1B U:$ #|{"!D,\odtB~*x}3Y]_C ~x"|դ˚^" &7 !֬ԩ7Ө D^, s%bzW76O b?𴂴 TeUn^i񓙬#m+H~u^Y[_5鵲ףH6y |>f(Amܫl֐sf:f5EU=0WRlֻ'٫9. WTe]^iL6@@CE8"6E?yj eMGSl pSx}̐QzڸK ~3+JJ3Iv*ߞT+q۽z%wʒWTe*ᫀT^iL6@@C8"6E?yP8鵼R$Bym|ch!e-Ȼ^~@,Ki̊R B`1ʷ'J\{v^b]e$'Ux}fr/t5 t9l>Iɬ1,p*yo' ߠtYW1ӣ!/ͼ'K$;brQoO*S^Ē^eIO@W+N228N.RXXAN,|p2Ŏf<( dx]zAs GfL.@| T*4t\%U*Kxii8;-6K!R ]"^91,T %5V"]"ufgS)" %H6߅7Y!foP\ |{"P,^eN, * O@WTedp]ХPv&X5 ݴ %"kz=Yl:4eX'^fF*LyP8-AA. 7 ,|OBz1ʷ'Ges;٫@J͹ EH;}0@UF^i] egUM˯ ]"ף̦c*U/}?F.Kƻo;WlΌT/A/4SDNKl }oB.= ߠtY@HG&UDhI*\NCO$W&C%KN*RsE>թ!WTedp]ХPv&[/t& ^z7!Џ_АHt%&[VhHW+7?J֬̔йQ RM/= ;]cCKJQR~ZދxK*{HX9-Hd*%6:yL- Sa b3 q_ =+U+B8FuR>L:!l4dRhn$F/5+3e4! dx]zAn3L.艥vWZsaz4TWBtB~*#L.3b* *gͬ'x=R2RDglaK8u@C**r2SFCNKl }oB.= ߠt)@H_&UDRes;٫@J)ԣ5(G3xO x] egB7*o I+ŽE xz{~hukp`*#YOt&dӛ^4/$]򮨳>SBNKl }oB.= ߠtAHG&UDв*=sW/䮲WSD5ŜY%EDCTWB.pj?SBNKl }oB.= ߠtAHG&UD=sW/䮲WS(EofEZ*}+!x_!pj?-Pݑ%L.3aWHZ)Xfz%uo:CW{yQo Y+7 2{z! %H6߅7Y!foPی #|{"ptYiݫXrW٫@J)7:ƕ<݅8BFl&wABإXAB= -J`z=GER e&>dlA;d*% Kfo3f{z! 'A/'~!r!AA.Tn26N# _H CT4$~e~FxQ1Mrf&UDYiݫXrW٫@J)Tb L  S;$<.]uPIdv-iw/)3ݑ^+-!EA.nR1 U6)N ߠtA="'grQorHNƹz +_ ʒ@ZN*Bl&B@Bvlp2Eɒދ@#|դ˚^" 74JKӛ^&b |d* ߠtA/= Ӳ^) \ZHM.]BTd/$'֣vS;i'+a32d֋xژn<(^ɒJ6v]S(xT_x Jw?_U!rrz-BT\jF,7'+a32d֋xژn<(= wrT4$%S~ipzkJSYz Noz=ZTOGԌ,Y6TC6f2!dɬ1|yP8E)$BIt4JKӛ^_;TD'7(DKxOtz$gעz*d>@5,1S6%vTC63!x6ξȡ 'Wbd]7)do;SxoʭJN ߠt^{ӛ^&93%|{I,)S`W/6sUN.GWg_WĎ*twp|&ȡ '!Uud]7.$F BB.xk6i,|]t 'VTLGN=V"{wUۯrt9B>T^d *twp|&ȡ %H6߅7Y!foPCCH&K8D[XRKR3 W9 n8 UYÿ/ 010 !dri wMV٥aP҅N=V"{B*$vS RU;!'3!CNP8-{ovAX;T;taPoOj%^D&kf!{Mx'vS;YTC6f2!FP8-AA. 7 ,|BK8@=V [z]B*لG@*Nd!PɄ2=u߅zK"BYB.BxXR yԯxʒ@*N)PɄB!gRBAr.UKLUU$R1.pjͣ!c3Bf ʀoRAg T>@ [z*ʒ@*Nòy4`8dcl&WB#0Io%ӭ x&!L|yu=īh,٫,Ihtoi Sok%* H58p016KfjwEf1؆G@V (&aL2 )BH2"P]V!{-wU"{% J} !ob bH@: V*ᫀTǩ!c3ni&pWdp`mB`wU*$Iu7E SF*H5Wr]%^]U^eIB#w%'T*yHmk*]vv lٻ]YL6 :>i^Zl%S.-,wGU_%KKE $HxSDzw`+CNL|,`J^+zKN*K6P < DB1_w 8N%tuKw5"l lt~eM/GV _i@w;S_Ke^7 )E^z"TTBBT>+W۽z%wʒFK}[jP[ N+_òy4`8dcl&- b1 W5Y%|EiQ J*]-c"]M,0/t"TTBBT>+W۽z%wʒd} D/B%4x:Ѯ8~qjwpL.[ dc`+cC"RƋ.%S.-t6 7midő*d.H}h̚"~5i IBu22]PȔg%J~W/䮲WYШ׷5œu*2e!h8~qjwpL.[ dc`&]gAY%|LQ R@WJ˶4*c)uXoiC^Cu)K%42etLƹz +^eIBCZ^b͌Q3 BEǩ!c3ni&pWdp`m/pfioEV _i6XT.53^7*7Mey%v*7E"-賍z{(F/@ Y듦~ozDm.-&.!ˈTd/$'s Yv lٻ]YL6 :eY%|J]kf LƠ JƲ-]o6h%!hZhz}4R"#ˈTdw% w<4_d!p016KfjwEf1؆+!0EV _i@E[_vƠ Je,4bz{~cY )҂>ۨiB%Tzyh%Ҳ""ˈTdw% w<8~qjwpL.[ dc` FM zJjML(RJK7mT*cQJxt7Eӛ4Miߛ^f hMiߛ^oeDFՒ~WB8;`8dcl&- b1 Zy]2bĖFKyQ%^%5u _%sJvE $HxSDzw-M dGC&2kziѐYFtә-Nli B8;`8dcl&M$ b1 PM.d^xSr-H9G%fjUdcX6.!.N$pi[9uٻ@UFf1٘1fʘoBmNNNǩݑA%уW Tedp`l&BHtmtZt8N4 - fYL6e3!;ҩ]~U8;0($0#,If1̈́BHvIuJ'Hàܒ|l&dcX6B!#z%)S# rK9²D`aL!tmtZt8N4 - fYL6e3!;ҩ]iI8;0($0#,If1L]&aL!tmtZt8N4 - fYL*@L²B.N$pi[$*,`L!tmtZt8N4 - fYLfrbl&BvG:˟kHG8;`8dc`>GX6b2fB!dwSo,SC6se3,&3`L!tmNǩݑA%aL"0I#w^IK̈́BHvIuJ'Hàܒ|l&Ť@,, !ݑNNNǩݑA%aL"0OKK\ 24P_e:]c*AZR{cy*m%e"W͵,]ooĀ$~B6 }|NNǩݑA%aL"0OKK\ 2f\^i M"yX*Sz+U,tOh,lLY%1eF ݪݏ)l~xWH:S: vGse3,>-wª化YgVz4;@0+QU,ͳ<3dZ;P7Sg[1- IuJ'Hàܒ|l&ŧfJ@0җ^i1e63xftlIL dsWR8ג^K\EJqW z-]2tZt8N4 - fY|Z\Xl)-, ytIVZ|C3@ZRțD?ˣ.aa6@w0y-,@ BiI8;0($0#,Ifi*;p9cղ<"ީ@.`ΣKo|/gy6 c,@w0E@mH_U8;0($0#,Ifii<} eY1*!xB%{BaaNmf0ts]̅,Ϧ@v;ײ;mbyB_NNǩݑA%aL"0O˵o_dYlVw*) E%蘶c*eaB<$  Y y-kYl`^ tZt8N4 - fYLfpmi)\^Y/TZ^yRy}9˳ ^%1e!ʔ.,@w0y-,@ BiI8;0($0#,If1e&XMGUAY;m"%&QGX6TqdcX6B!#z%)H.j9²D#òB.Nse3@G6e3!;ҩ]iB)-se3@G6fY B9ym.Ne9 b Tedp#3Zg`y0[$WWY;Jr]$z(sD~} Tedp#EWώ+Qko P VޔX=^|TYޠ7M٢h*MGS228PőYeC,`GA;̬"~! c6kHKHi7zoƛ^lz4fף 'TӋ(@qMzޒ~fWH:SJ|QIDO/*u,]'P*l̪g^#U2d)R(fIcHfS}TV7hMGSahz= ETf UbQXEl=UN딮޳*U"5K\YsD~} Tedp#Ec"냞R2ϵٌl.J6ԞTV7hMGSahz= ETf UbQXEJ=㡟N딮רJr-[ .@G6f3ǒE=5*ڥdf=kd]l=ףzoƛ^lz4fף f0@yy-*{h mIC?+$)]%>[DI+W*uAX6o#0#_O*#U٘U(:%RG8>jGxN=7ٌRl'Me{)-!ټR+-!el1ai 3J܊Y yKXuK:]!N*F<<^_=$f5l@`>Gtׇ@UF81kQҴlY( @i~)1[j}Ҟ- CK 0]B 0EE(<Y"M%h؞e9K>228Pő"4l`y0228Pő"l`y0228PőꌢKBRd 9 TOJSo:ٲlR`>GtЇ@UF81CQd}m6fǩb ,qMg;)NN딮 $ I`>GdIO5 Tqdc:%0GdIw5 Tqdc.U3im6fdgqd22.NP3D]M*;*_w ;R MB 0]B 0[l؂3K\yNJ]irR(eL1W|Q $|ϽL|Η= #U٘KռV٬S+ud}vJKHa6fJKHa6SeY`Mˎ7_N[_*=u]E=u^x*CY.0#&ٻ@Uv$/s_A]? U٘(?Je0ώ%kz= ET-^lz4SeY`M"~g#lnB?+$)$,*hԣ'^Jm=Sz .i&PO>iO*lzg%3]ף0[4M٢h*MGS9U6Yld(QH, Iu-բRQX[F)sD4{WʎKz4fף0[4M٢h*&-8,E<*es]!N%gIW)EU/-yPz .i&P4( ?;jh*MGSahz= ETNM[pf5Y:@yyT.;&3BirKϨGO][zW]%z(sD4{Wʎ}~s>g|S@G6f3NOp>vɚ^lz4fף0[4MTdgXY>h0>es]!NP]]M*;|2W~3T&R]C*lfg8 ώ%kz= ET-^lz4SeY`M"P^fRv+yWH,όBR`>GtOWʎēX|ѷKϑ,I;ۜQ.SivJKHa6fJKHa6SeY`M"P^fJu^ڋyWH,/BR`>GtOWʎ3_2g|Nwo*V=\fdeB;@.$0 `6f`dgXYR͚~B MrّX676 Gѥ?^M*;xB fr-CQd}m6fǩb ,&KG(/@!3ˎIJ˙BS`>GtOWʎW< 1~g?_z9DZ:%0걏a~>髿s˯зK^OfPgYf̓ql؂3 Q,VƒU=DDes3/B٧|ҟZ&P7 `q?,#> Tqdc:%0 Kѥ?^M*;$oW[i'>1x.l`y*,kt2 Y0Qrzb{l:esKP(0#֫ Tedp#3E8>.l`y*,kt\v$MS/B٣|ҟZ&P*lPgYf̓ql؂3 QˣrّX67N e9Kj@UF81CQd}m6fǩb ,&KG(/eGbD:R(= .jU uFK`y0 ib߹~!r!T/1E/&-8O%~2DK9:Ӯ@UF81CQd}NjfJKHa6fJKH9U6Yl%ɗu,c'%X6rdt뎲@UF81CSd}gGYT-^lz4fף*,2ΚLFe3!GF'n' Tedp#s:9yW Wz4fף0[4M٢h*&-8&##\228PőT[tzKz4fף0[4M٢h*&-8l&ò#\228PőT,M٢h*MGSahz=dgmdwX6rdtv@UF81y#ZN ?;jh*MGSahz= ETNM[pfYoM&Ge3!GF'n' Tedp#sW9|,Yd}gG5M٢h*MGSahz=ʩb ,+`l&d= Tqdc.UeR+-!ټR+-!Tdgdr0X6rdt뎲@UF81y#ZN 3w M\H`6 )lv )lb ,Hl&OjU\Qh>q 6fTdgqd22, 92:Su@UF81e46fcl؂38k2̈́੺]M*#U٘K̲yf̓1x6Yle5 fBNTݮ&P*l̥jf< ̓l<,2ΚLFe3!GF'xnW@G6R5T6S(QE[&aLȑ 228PőTi46fcl؂38k2̈́੺]M*#U٘K̲yf̓1x6Yle5 fBNTݮ&P*l̥j~~+ߩ @8>.l`y*,RZ l&OjU\M'Ի~]$OK`y0Q<"R MB 0]B 0[l؂3KiM&ò#<* Tedp#s?򆗨k_Y,ud}&JKHa6fJKHa6SeYJk2!̈́ຣ'P*l̥j.HRY=RBY18ώ!kz= ET-^lz4SeYJk2!̈́ຝ'P*l̥j(ˇWvɚ^lz4fף0[4MTdgҚLe3!GF'n' Tedp#skeʃOzuv,Yd}gG5M٢h*MGSahz=ʩb ,qM;)#\228PőT͵+_'>1r%3p|^^i )敖l^i )敖rl؂3 Q/x \v$Ml&e= Tqdc*gPPOw*gDd}㣐:玡) ̦~!.~!w6Yld(QH,`Lȑ v228PőQtBi,H=Z<Q%0.l`y*,kt2WM4J~B`^eGbfBNTݮ&P*lPgYf̓ql؂3 Q,^UZzF/@̫H,`Lȑ 228Pő"l`y0 ib߹~!r!T/1E/&-8,ET@C4MBQrّX67#<* Tedp#3E8>JKHa6fJKHa6SeY`M"P^Z @LL5MJˎIJ ̈́ຣ'P*lPgYQgtz4fף0[4M٢h*&-8,E<*es, 92:u;YO*#U٘U(iNFd}gG5M٢h*MGSahz=ʩb ,&KG(/eGbfBNpN@G6f3ǒEv.YT-^lz4fף*,kt\v$Ml&d= Tqdc;|gYQ3dMGSahz= ET-^rl؂3 QˣrّX67#\228PőYud}gG͐5M٢h*MGSahz=ʩb ,&kS>)#\228PőYud}gG͐5M٢h*MGSahz=ʩb ,qMg;)#\228PőYdf+-!ټR+-!ټRNM[pfYiM&e3!GF'( Tedp#s:9yW B;@.$0 `6f`dgdr$X6rdt]e5 Tqdc.U(G4Yf̓ql؂38k2̈́੺]M*#U٘K̲yf̓1x6Yle5 fBNTݮ&P*l̥jf< ̓l<,d{, 92:Su@UF81e46fcl؂3 .l`y*,kt\v$Ml&OjU uFK`y0vɚ^lz4lQr&h3/oͲ̾,} ƛ^=,kt²RB̊z4=-eH,`Lȑ zUƬwFX2ώ%kz= ETڳ<Tfkx-wEף M[pf5Y:XaYB!dfEdz da-=ЦeGbfBNpN@G6f3ǒEv.YT-^Ҟh4i >7ޔGoxT&-8,ET2QpّX67#\228PőYdfKz4fףg+y<;)dC>7#{z4fףH6Yld(kK_BjG)ZӨ43=*eGbfBNpN@G6f3ǒEv.YT-^Ҟh@ ]܌lT-^"dgXVPsB'T,ay0eGbfBN&P*lPgY+-!ټR+-!ټRm&-8,E<*es, 92:uYO*#U٘(>h*MGSahz= ETV&X3SZBJ dgXG#lne3!GF'4 Tedp#%ɻш쨽ף0[4M٢h*MGSY5mTBJib~Cb ,&KG(/eGbfBN𴥬&P*lzg%3]ף0[4M٢h*MGSl5SE%TE*!}@6$dgX|`L.;&X6rdtv@UF81Qt>,>vɚ^lz4fף0[4M)Ҥ1$dM!}@6$dgX@Aes, 92:u;YO*#U٘(iB+Kz4fף0[4M٢h* vQ-LBdY`M"P^NElNK\v$Ml&OjUƬwF:>fȚ^lz4fף0[4M.J6e)}؂3 QI͚/XZ.;&X6rdtv@UF81Qt>,>Q{y%0WZB y%0WZBJfP">ҺH6Yld($Pz{eGbfBNpN@G6f3JwY(ιm B_Hfc_H[ʖZ_=SFNdY`M"P^NEBYBŖ3ˎIJ ̈́i?YM*#U٘(>q 6fTdgXXYhɯXx .;&X6rdtv5 Tqdc:%0q 6fTdgX@5 )P#es, 92:Su@UF81CQtP(C,P!g5YByyT.;&X6rdtv5 Tqdc:%0(>q 6fTdgXG#lne3!GF'xnW,d3p|\̓l8UvQˣ2Ԗ48, 92:Su@ET}d!CQd}m6fǩ5&f0B}'%X6rdtv5* B:%0)!dmt g9QYTV.^Boz= ET-^j6"H6PM/>k#!QϕU/} vezw/g>t QO{÷AO>yw͟+J^|FB"CR:>q~W~gm_Ef\f1?kW~[ t^Ф0W.?#Y'?rdBȪ+Gisl 0xT-^lz4UףH6HHHd:֟OӏEا>eg?w=2m_P/~k/o}M]yYAݳףMɶ'ʎF mh*MGSahz=ʪT$$T am$$2D<]|Ϳ?^ޟ76;23e~k}ꓥ[U)2 (_~3>N߻ˎO77Is>$Z旿3͑55Bl`y0.l`y*[cBik#![./~CO*Pv/tl^ϑг?wd\z{a,#׿ݰ7Bn-0n)oX"[6k<`4]x[,яEO 12ao +? ~ӟs2TLP(X fj+Z[}I-/Sl'?`e ӞWdh_O mף~'Ann87. ʣ(!s2NL!nlO/"{s9G}CO :x /˖5x.8wDl>}ztBt{X6otͤ̈́BȾ̷)?V_%ϓ/O1WO<,ꏿ7qA?]:᏾Ye@J+COy -?㞢[~o}W}h@[ef{gLZ`L![+U/C|GW~YW~ 7<'w ? Z-_G>B+/'=яJ#kˎв$Ӆ.зϲBV6K?:{/lis!息^?ͯO{ؿh_ 9=O|c{_@}?z>盿 ]/ .,7e3ie3!/n6Bֆefl&l&BfB в}^FY6e3!/X6rdX6ouaL̈́BȾ`LȑaټZ["z#Y6e3!/X6rdX6oͤ̈́BȾ`Lȑaټ,I;, !}#òy3X6vX6B!e3!Gefl&l&BfB `LaL! ̈́͛òB, 92,75y__yT?9', !}#òaL! ̈́̈́ fB!{AS <e3!GFf)hSu聁Btׁt\z(-I {lA`L!iC._6C-!=AȾ>e3!B !a٬ ^l!:̈́BFN p'̆e2xsCP}6^`ȄB dCs?!d6,O=AȾ>e< BMO fecfa# )ϐP&l9|xC)=cLb=x !AwtpN <3ݹ~!r!BFf>х|Zb6z{41uK8>M(~!Ⱦ,))ooHOgdedɾkz=l4:% E x,kz}Pɾ#=GS)}|g81C)=s21?F3sR,"C% %YEZI,߾Ϛ^J|Zb6zEpvL/YOtisfYcJOu!x=J雼h<L :8~PJe6g2rؗ 40 kYrcq\Ӌ%c$L}Шf^{Mįhȋ9JhMGY}75U*|Zb6zEpvL/YOtisfYcJOu!x=J雼h<~+\{~PJe6 9~~콘mhP7л#ob !SY7 MC؉_i̊Ry$dpogMG;+Ӱcl4zL6˚^3Tx#~ Ĕc7yxk̍~PJe6 9~~콘mhP7л#K^1B@ț^o<&vf7Lb-Mi 28˷o^7MC;KӰcl4zL#>mJN#: oɚ"~#yCwR1$%塔l*wR ߔ1~1 0лκ%' If28iiW*Ѻ?-E,NL36 XB 4"doӿ++>d|ZZR ̎IyJ}XB Jvkd_a_{#>{HiJiJE7 ~PJe6)oх1r8\۱[2z4\˼1B d7st9o2ߡX ;faAxO]F)̊z4:~PJe6)oJG{Ql`.Ǐ-?kz=YOtȼ1B d7s?!d6o2ߡX ;faAxKQYQ@fSǏQJ̦r?8\{/J7s9~^onGzF捑Bf !|J1uL6{}|=#x|_̊z4:~PJe6Ɇ r{Scz#p?z{N01FB&p'f[;+a19 BulO@x+Q uR sRǏ\f uzP\{/7u*s9~^oǛ^oO>>*5_ݹ|Du#۞l6V}3VCOIӟ1hmI iT^'u xy'<~=4&Ê!B"R>U׾"#QO~}'Ses4@&fy˗BT,oԗ0/OK6h*D}%*Uӏ-oxɓ׽s𫄿? Q}΄ɺ+!B)*k__z~3>N?%Yv@䪲Yuk`]>{EBA f_kWZ6?RY}47Xa+ze<*ʪT^}z'_G|?S!dV_D!rw>яzjWYN3~= LJU׾.;?_4Q?\Grou=dfE=Yb~SV¿J}ek_\}#oi3TS$E"ǨD7Kz,fgU*UƯz}6 ߥ7-%":-%BQ|}}Z7g=G;^-W~gY^e~JH2%{Yhf=MY Z+{yPfhɯdfI%LsG 'm ~s4iOx[gu u.B#mx]Y/?{NJgNj ֲcmMOcGhf=MY Z+͢w^G!^z NCdp*zY}n;|'4(n8UChf=DZ+/#1_s1e3&PJ6 άbN{OhMDO<7w5|觿BenV"nW5^QBYRӋ@$ߕJH7Ydf`G;#]PRAVb+r NE7-&)-KeI%$RVB"g={f^, Z+/ff$>OEMl:!0 T^^{o޼qo!vYq C6@eE6=Fv<^)x{DId5.-.T{ӲO?g6!k_"W|Z @ԛXBZո \SMfJW9?oٟВesyD_UVſn e+["fKټSt%s|*wp~;'Mw˵e/& <ݰN*+.uӤPbʹ_АHt֣&>4 p$؛^KJkfUh53*#qitߛ7ޥ/ǫ%IAs k춱lg~eT^{dp^e !@^4{'/!Y d_6f!ש)S0)ף9 nFN dfh f֓y|FIHYK58ެl?]|w_,n-OU_\6 :LN _O}ԓ/%4y#w !Y d_xC^Si !0講F?,z&1=7> 43ͼh5PRAVZkp*pҗ<˜:Y66[6 _g~Ǿ^(Q]Syu7sΝw<*oWjɿ9=<ݰN*+YSu LWB^Si !0講 @t4*7Y E7> 43ͼh0ـqXDk*= 4-Y6nLg?ZEzG7?Ow}=o(ys1W9?o4& l<=t(?$3l&Bl>Z P'I!{e3!#X6ARkX6B!;e3!5, !B̈́BȎ8lwuU!% X6-Q( BZcR~o=/, !tq[o!B!x^6 P.B!`L!W˃[CF;EeI[n}>z.ީn*%KjZ%5 tɒVdIM]  fB!d|^6K_ӝ?w3Btg/tRd cIMr<̀v[!Bt]es+,;T]˸J]?/c 2ɱ0t$|Q}0rKpP6$/B ݯe^4&[%❓җ7=1mT1IB9ZvXP_fz MM(z NEC*R|rypPvacw]+c_CLx'lPJмhzP2ɱ0t$|Q)3h dGFmߝ7=RI[ e}$z!~-dfg]<fI)%D/x=%mZcJ; KƮ7,z% ~P܅ J)7MC.u  @GBJU``9 rKz>v\B{~Nrm%$$[T MCX6k{l`z=;T]X2v[fzd\PvaR듦!c:Ly#!%*}00O }[󁶱J-ͯQEGKN*Q1x* T*ђ_B1Z 5'! ݯeo]7@ț^ MW{œuF|rypPvac4kz=;T]X2v[*G#り R:(*]@@29恎/< U]gDnI̎ `V(T7!ZxӢ%R]'4%*#7%TwBZvj NB:!oI3EZ\T]Xح#鑱!KwMGӓlPJU!0 UX:RBLy=R%=hK;.Y!,z6b |bD e PI!gCk%k&8yPY^-a~I$JG?(’zȸ]ؠ B`2vX:RB4kz45-@[q CYRiuk`]άbD e :Hl͊BΆײK6QEMp*yX6gёS;T]X2v[oz=T]ؠ J)ԁ dr, )!_T郁MEnI̎ `V(7ͼ!SJXbD e uB`Vr6t]nS7@ț^ f^E{8#><8x[G NB`zdPvanhzd\PvaR2(Eߐ@@&<БE>%;"h34mΒi f hM ybZ ڡBΉײKO@WϺ^5Y,jJ(zNAۅ:4p5%} Y2viJteg@Gy#!%+z4 %Jf"9I 84HtKK`zd?fz뮀n?Db{!~-df̢ J/RX7N%'H%mE#cwa4w2.AqRJ}N tɒVdIM]U.YRӪ@B*Ȃ37#yb N/ !ZvZ!_Jy ( c >vT]`5EȂsԲB9/(z˃ ,oT]`LȂòBWg W1v[!Bt]݊%mB!d6, !]jX6B˜eBP(%[ V]dB<, !Res+P6} !.BȎ-cw `wa/e3vF(?G?;<B"pq Bl,l,]ox2&Dd@!ٸKMH6HU_X6"2.x RKԴ*%KjZ%5 t!dcL!ٸ[;NJ~遐7U76FA+hwp*Rgk1ڧ4Qא%c3뉤-8{ dr,iUNB!l⫎^y ͒="ޙ%Kکs*~Cxgdy(0.Aq68 %!coLy|O?Z BP(nP9sCț^ MgC*֠D,Sϋx H`b 8tJ Y,2.xAIGuN@.<  rm [!;ef?/B!dqϕfAOB !oz7ͨL'yPua㻎4Q0% *.lP輩5Ed cl א%c3뉤-dl < :6O-2[wdټ;tC^7)-0XȢ^$˱Gj  BߦH)ϚR6ÑՐfAO>_Woޣ? 43S x"K͔wk*QG?(%YePd| dr,ǯ;kT2!ݑ/3M~%|GͻCWip*<"޹1vd"ˁ &R$:Kf hMGslQ6ҟmd;@܅]o6Y 2vXȗ&#ݡ38iܒt{^x=}t"L6 P UDglz4wAl5b!i1fm]>/.~Ա˸^ީg@Gy~O##Q9zBdr+M~sfmTbUW} 8T6{B">ڂ梁kX6g|[3iQ~w*{ tɒVdIM]U.l.8O##Q9}B(kc@H=#|A4*Z]-`6n,%mB!d6l&F iAJ _~Iz;*MSԣ<`͈}e3!.Ȟ²'hn]9ML>=R m驄"sd:L7hv!Ȟ²y})Y)?}t"Y?86x`%Rc X6gh|א]1tǞB68vF|GͻC ِuP)E"={`r+/1kNj}Bk/lFbl/l?aLȂòAfezءfBye3!dUX3@(A󗴛Cͷ *.l&DdaL!-R6b+~-ϿleRL!~[+6 CۅK4R } Y2tN dftewJ#A4;l&1{ f_{z!ohf H4Ѭ cwa:2.Aq~=" Nvq?>r& r0dm^AkyE7@ț^IJYx H`z*.,;ܼ7^Go~O tɒVdIM]g쎄BvF ,_(*uBz=4WzT1i7@&2ZBE<嗘ݑB.:وEkyE !oz7U76 ?,h' K&1=%d.,;ܼ7^G?(T1^Ed c-!"_xKH!dplɢ<銢rچ7@ț^*,:Rp* c K7MבqAۅߩc!hi!coLe< |x/1#!]u;'+Q[7@ț^*,oK8ɡeJ%ء’{ud\Pvaw*MC.< hy³_bvG2>"2л*Q~Bjz)/뼾MSŇ&I}rR":Tmd#OݯgI]H%%mi' 9T]X БSdpztew*hz2ɱa/<O~%fw$#sz c* St53 D~p,DO۫41TCWaLi lɢdomQlTX(FyZiDgy}"Y2+XKUDD@c0=F ,_g܄d7g_eL:KIӔ]ye,!dX ~_~ɀr](7Tn 7Kz=TqD^'SYUYGxg@K0=d#Oݯl^ ]eJyD#|)RY6 ³_bvG2 b=M-*7 ӛ^φ@5#6dLJHA&h dN/*NO6u}"7Q2u^ߦH֩CuR@HH+?ԧz*F ,_?/iØ /iS+.J,_An}2 wJYpaidvGBȁٸ!u;'Y67!X6+2Tv[+U]e1d쎄š`plɢ<v JĒJe\*x'8vFfw$ wG6bdZk٬JySu/fьd-%~!.!AATvK4<'*dpz4=>zGJaidvGB!|wd#OݯK%@ț^%K+1TBuYGd]eᆽWqWYB,8A42#!]u;'ՑQ4 MK!S*IJY{eMl')M)!cOnWY2vgob-=2Tv)!dȂ]O#;B\#1x~-ϿV )JB:!oz=RҎY%$$OnWYґfMUA{tʒm{t*WtGd.ݧ !ݑH!dplɢ<2Ri@ț^ MgC*֠_GᗴUA{qWY2vmoz=WqWYB?)%KjZB ]O#;B\#1x~-F*uBz)dJ%LE6+2Tv%c{ףqJN cXRӪ!\ ~}ݑB.:وEkyITy땐K]ףH6H*ݮv9C˚%="cOnWY2vaoz=WtTA2vXz!LNTbvG2JSѐ D3L_2ͣάkFfg/&6@Np9'kiCGR!?^f$~[+-!EATv ]z4=25dnhz}ߩ=FK7@&+!GfJv"LΠ;UyP7M͒"עOOdX|zP$ؔPklJKhmd#OݯJ/RX7:M T2Kڊ%K^ T2=2⮲dpz4=2⮲;tP 1d#2vXz!LNTbvG2JS-\B:!oz=}t*"R_̛^f hMGsmd#OݯT6Fl=U].JnW`\Ĩ&(%d"2ɱCᑙ3dt!0#[R:uBz4 G$ u^ߦHt Ҕ,TBk 1x~-Ͽv5} J좜Je\*K2vXz!LNTbvG2JSP4VЫ_oh^$ѽO{NƧ۫4Y6gTBk 1x~-ϟes ߜW19;.]bJfEZ+!GfJv"LΠ;U o'U7M҂h^'SYUdVD*!Zi!1x~-eڿM8*S2@>rSl&2SarݑT T2MunUtBz4I @ :og ̊4\وEkyG. f2&Д̬/eLH'dd' *1#]@ț^moCu 7Mr-|{ףYԁ`f= 1x~-eUtBDךbeLH'dd' *1#]'̀zSu}HDzFi͒>56%zC#1x~-ϟ5!!FhZbeLH'dd' *1#:+ِuP yL5UbH$=SGhyxTڴ+ߠBj/rd#Oݯl& E#+!G' 8ҩh !f" F ,_gLyM-;%%KjZB aLY|wd#OݯY6B![òBUpfB!dhX6B aL! fB!Wu;, !F= l&l&Y(JH ̀S?֍H!dplɢ<̈́UI/xp_,I3g?n쎄BvF ,_gLYD(e3iF>#~حݑB.:وEky, !!sS4l&G`u#;B\#1x~-ϟe3!d dUNY2ͣN3= e3iF>#~حݑШI/b!B/̮hYK:lɢ<̈́T^ RW%ntB`FnfͤȳandvG2!oz=O &y}"~"1x~-ϟe3!gGI) 7) rP*բ?3!@8nd*'dL22u^_J)~"1x~-ϟe3!&N df YkpS]6 @$:hc y?LFfw$#k58'!~d2uޣ)uF ,_gLȾѥ0kz,X) /ؠҫ=fdC|F0ݑ44jI~"L6 PZK:xL!lɢ<̈́]+BPZ|ehl|1<^#;еY|KսX3BZg/J^"'Y6ot̚^ Ai-6nfm cL!@>#~zHF@jpf-M7v:^!lɢ<̈́]@b(l)4^bC|F0ݑ[tB&GZyxuF ,_gLȾE0kz,kMQxe+ؒ^7K:!0#=r #~0⇩dt!oz='!O:/nوEky, 7fMW`r-) (`UY2ͣu43!@>#~zHF@jR%$DN/u^h$'Y6ot̚^ Z|SQ6fχȳa52#!1dplɢ<̈́+B0,l|1<^#;BI F ,_gLȾ}K%$bQCɵ(d\fC|F0ݑB.:وEky, 9;zo73X)98٧ !ݑKk$;W7 gǧ+J|zNJ _'J?, !aLT">Yˈ6:LH$=KΧuRr6وEky,o;K|+11k\OMv2LE}.:S)&i#;B1jplɢ<yط%}WEn  w.'rS0ݿ@ ý]"+ÁT H):7R *|*.~PH9*9ݑyX*S 1Kh_ɐ9kz=FvƵw.WaղdVx%KR*Xoz7K:xLPy_d=S>vÄjdvGB!|wd#OݯO 1%"O;}G%XS 1Kh_p*z@ojʲJ%ԇE7hF*|*.~PH!dplɢ{MV-@(kb <8, ÁT ̬[nbm,T2#EC>c?LFfw$ wG6bdZPO&1T2 xav_I eMG,j!7} J)vÄjdvGB!|wd#OݯOGˀ{o,Y!`rBVY[Υ&Ps>#)[v nH**";c;pDocK ^f z_nիd~msaG*+:%j>9Ҕ:Ҿ}1 =/0^:QNB 2=VwOIi韊OƖ 96AMj`Mvr)}}ŤV/ĢTEČeD?^`Tvawn)a05Es[O5`21t}vދJ"K:@XTDTfIA Ay_JR 10㰃X*~^W>/.#8c_0y_"30q3%dIS>߼do괛./ a:_0,~*r9~BtꘕbVFQ9~>;E?msƎsfK&Xd&wٵ{"6fҔOL|;TtyI+eNٰCDq8W'LttN/Y)feqA,J?mi0v3c_0y_"30qˮi@ir/jiјx遰OOIpނ_, "qFbRl߉OƖ8>aR7cQzX#lc~Ea(UmqΌ}).v}] ثW]kz @SR0,zu]2ѫ!T94K^&)>-_IDq8Wa(UmqΌ})n3[~A?7`m3OOIpBb#e9~BlR7cQ©RXm>dmt>=%᝴.-z0e-F&*jJrH2RXm2OϜnx'Ka%*I}'>fX#kh[.QHq6, m3dS!jwҹXenl?lsQƦ1IL866jK9͢cce' |rLm68C/(?*wM86{RN)m^4f}rheZٮs&L`(.6#᝝;ؙ}r 6ux]QY|Ƀ(sfBVCâV$PvĆD"i`}띅Um-v#`;EMm3&+^+AGĿah} %aլ )Bۀͼvt~D7ZzB{ѪI}r 6臰ˈ2,w^Wqkef \Y0ePqFJB$*6#9>\xOȏoTEB{ѪI}r 6臰ˈ2t^Wqkef \Yſ#z' =gE0-L_WDÆD"Ç0{ 1yghy$[LE-E*π- 15Z^MmVۤhbQym/]Fql4\^VEV*ΖkٮתYOtTNqZzyghy$[LVSf$#w5fCAtXpD?(1YA,J?mbe+M8(,>AG _Ue莛:aX9+bSP^7ݱ!6x=k^f EU =0eء_Y3ѝN鼳^n- [&bS)3?;7IAщ:Ze]rqvGyĢT~vMVWʃ(sf7CŢ2 2HY*L*L?ۙ^(aC?"MEҩT_Usq|ԔU DaIIءSpYb/Zuv7a-1)WwǬ̆UEҡ_p3ѝNJҁ;"~Ȇ\ 6O ˈ2,w^Wqkef \_QRٯ[B0e)StRNz}6#9>\ĒNr2*!_߯X Z[d;*E#f,T:od遰U"flT3>fxdR7緅4rVT?;E+*2cc)eZ<=hWԬK7*f 3eTOmHG)r|%2I0eXUZb vx@D 39C.aGYb/Zuv7aA+aGY)˩CCn{.tRB2P 6;`e+M8(,>AGm0"5 aS-%ؐx/CJTpD/Sb_"\ªe2*=LUvY(:od遰 'pBb)@DyY6)h"f:LSbR 6ˈ2t^Wqke؍ \)aV26oLRNvD;c! klUt:lk-,RRS}:2h陧KF2=߻RIҢGq\[\EMyY 3TڲX*~^׿.}Ɋndc !.ڙ"M +"\y絝^M@XZaU)E ui#8}-x|JG8ZciLu,[;EMm(XryuEcBl!=ߥ\;S)yE@f-LR2}~[+{xlehe' |rL|m6qP '>92…B{KvHSЇy{h3C/(؋F _΢m3&+Vv ;d.h. _ĢTf86, m3}rh>9KC `fmC_m36!/`ih!TXjw'vSp۴2bwo--߶z"KC ΧgNe7t8Y&;W 1#fU=;rMh2OOIpB\=`R *˙hEŵe+C 4͐|}JJP̲x'[TŒ2g&zfҁ;hڲmذ6K4#pmNfrp6t>%%aLpb2I>fgv /&p}>%*leau:bl>d~0g^DtyI+!r3‘[gdphMRp}~[&YF*GjbQymS,8c_0y_"30qˮ4ϳiio괛./ a:0,v*1’8ɡlR7cQZz݂`(UmqΌ})Nrk2K{t}~f۱G:K:@X7Za8o!N&pį[g84Q\:p'}^Cªg~)A,J?mi0v3c_0y_"30qGOm߾4^M0]^A tAs*ĥé_ev94"0=.˺v<;E?msƎsfK&Xd&/ݫ4a6lRa{&iJ)2kewt ^=*i7]^A lobHZĥz6IEX[Ul"}l[[ 6ߚ>5a5Zz`eƎXT$;GpaV"뜙r5~b3ѝW4aݶvp2U s'GRGf_T[~V̲آ^:QNB 2=*"I_ĢT_ϊY(0vG%gN`?L>\Ējٙ /WCG՗W~0H :괛./ SLDx.c(U4%vQa8돕GE9⏄羅Uvf} ~:GUJ~ð#L+zHjEjiJibs}a<aY/xTty}r 6a鴰ˈ2cY<*bŬt羅QԜ~5 ?uG߯/U&xۜPfEa˰#M#Ml~6bzG: 5@xc(U4_b.#8gQɾ( sdžIorJ*# D<˭ $U wL5%b_eO47$a\~X-^:QNB 2=A,J?m? 2LFK2qJX/l80y[Z3/às>DD/U&6gGRbPf]˩,-#MMl8ej\*AguأRvdz <˱X*~^~AeD?Ht羅lja0hݯ׋VߺJӄ◡0N'TɑMl˰C~݂^:QNB 2=A,J?m? w w 2qyT$%aFR羅mja0ޯV_J h%n(T"0epFɑԑ&6$W-:괛./ _ĢTpq.#8gG% sgG2x5~z˫?M9°#l`T iJibs辘TaziR{TnPLG>9vRkַIaeƎxYKw+S sYK7sf0ezX.0rL~69fҔ׮{WIDtyI}r 6˱ˈ2cyؗb?L L/L| 6fҔ7/G:K:@XeE 57ӹĪYtDYh&&5&#|uA]tTmWU xvRk:ؗb?L LkDl2ͤ)]vQN2=VC=4?ҿΥ;)#ጤD0bw4+^_pnbQymO\Rs"]v히MOL{WO[LՐG:Ff Cq:k:n"F80TJJWc(UmqΌ}).v}] ثW]kz |5F#~Ff-|Dw:)!*KNJ#!dT+ gN$|5vRk:ؗb?6K4#p6Cj-f:TX爐U|D7nɤn~"rxeXjfѶlm6CjEt>a;Ћ$d Q9l}:լ6@@ -䫱ft~x*ٯĢ&C/&pY,rCŢELRfmLR~?T_AKCLcԔ>/K# 2J t*%%᫡mXf/쿑褌Ȇ3 :)p|JG8Z26>QNI'%+#m6, m3V0oXNEenl~ "n&)X9D7IuJ/06|)>O%fЧ5oi=@`Ҋ`f &+oB]ʵ3 0m6Kg0/gѶYq;…B{KvHSЇy{h`ˡmƎsX5{K9HSЇy{h`ˡmƎsX+5{.ф l=ņD">v'1;_ĢT柶ckef \Yj~X٪ؐHS?"vo^M@xc(UmqZ=|_ϥ?%_ [G(a fEħ7?% R-:yէ& OnL띅UMq#`;E!2qkefIsfWaC(a )6#9>\xOȏoTEB{Ѫ;LG>9vRkCeD,>n9*;aX9+>,m1X6Oo )4EYaZAt ;bB {ѪyLG>9vRkW}g2qkefIsf|ώe2*@s~*)NM "cC?"MׇUѭʺ%`rkjVDSf-m0աSptYha/ZuZo._ĢT}-vQa823{[GgG2~VAb;na笈NOf;6##϶g0Ը8#zf ;+=k&I9wZ؋V[PDÆD"ÇXS)f J)0(1)- C2R-=迳P^u>@_8Nʈl8) ( T_-Q  j6ĢT ~!vQa823{[Gw[fnA aLJI9>-|6#9>\ĒNr2*!_߯X Z[d;*E#f,T:oC9NDg.<0Od䀐@/]cBl!=ߥ\;S)E@z}r 6w6!/`ihC 4pˡmXf86, m3}rh>9KC `fmC_m36C:-,nsiOU f]t M(ZZq1< fm|}v–_ѹn'eD6uR,}'-xy7 g/6q6߄m&~~A?0<.li!Of_3S&b0̡2}^1/^VMDZbl9c~鋸s&nj >`Aya܉ϼ 2=V@>=s}褌Ȇt-uh9~Vp2"J8 67͢sfKe(ț?im{TnlGLOlPldsiOISY~B.33}1Zaj٤YA,J?mi'e(lȮ0|)]vQN 2=V@>s>ҹn'eD6)8,Zc_}"J8 6͓r LԲ pSVk? G -MdD4Lh遰uS9t_,0R0eاZ,bQymO>/aj>;EWH+ ,(㌏~_ ϮUEjA3P _A$eZjVoJtMV_J5ͭ]bnT/J8iJ`s}AR9tLNΓ 괛.[ a| [~F纝pJTV%>?fU]DX>/ Z/bQymI3b&~f.#8cϮטUuȆ#̀/nJ%?\Boʱ*OkBS9~?Ҕ:Ҿ0nJ,2’Γ 괛.[ a|)hf9u۵[NEeT.I 2MmoU zV6>;E6+-2.#8c$@]/pzDt$%s /AR2nS:7X\5j= }."a+M*0e2HSH #˰dG:1@`  A,J?mGs'a`eru C1bZ[ddbpKf !ߔeY)yOuRnlN)*%?9ZQKn2HSHCâ/ÒΓ 괛.[ STDx.c(Uf (㌏WϾ( ϮU0[)/ ˩nU"f՛jΡ2^RӚtl$%aU:JD [xYXj+㏁4$a\TΓ 괛.[ _ĢTf (㌏jȆT]/1Spta0L/)Htn 7er֤6gGRblKwlde(%l)+㏁4Nᔩ]reSU:O&{TnlLG>9vRk9~vQۺ!j"[}vFD!d a0VL/TS.IqMY\5k/2Uv TG(aN$\ )ur2+?y2uأRvedz <˱X*~^a0ˈ2 IITgDrMЙf )/k_+Q]᦬^RӚ f(Ȇ1ԑ5$wp:tLxTt:}r 6 )ˈ20"0zYG̾(3aPޔWfG絔HJ7X}y596GtTmL1jSn2HSHCŤ2LVYtLxTt:}r 6_*a(fYeDg|l7^`TvzjAa07xΡ_kf#2Soʰcd |IS>9vRkIn{vZv)X{l̤)]vQN 2=A,J?mi'ٽs&nj >`Ai@ir/jiјد遰kuRn0CS$&5&}~[?6 bQymOcm7h/tRw?2VbH(%φY)feR:p'}TNK|4+6CFAs~XD*+Y9Df-;0n9aN&pmsdlcjZmXf7h/tR73Kd"84]^&)鶹wp2U6߄m&~~A?0<.li!of_nK<-ĪG$*gpƼ, ΊHJR&aUy(+v3&mɜ;g`⦖]#o '~̋h. a4:i#8}Lª}Ff,jJwCR2 CX*~^62Ι/o;g`⦖]#o `[(㌏!G .|vIʸd@nZ3n7X\5j= }."a+M*GX:iJibs}a$]:O&{TnlLG>9vRk~[N (㌏!a(fY̺[KwUϮ@;ܔBge/eNiQeDg|lt2o 0eToʋDw-ZK7Iٜ ^}St&ᓰL| ih. a {l̤)]η`JuMh遰S3S&b0̡}y_j2j>;E?m$}97yS ؘIS>?M3mأRve;dz |z0ԻNʈl8) O#jJZQ*QNFD ĢT柶y۾QZv)X{l~g ZD4&+gz zfT OISY~aCm[xY6)uQ>1ga(Umo;g`⦖]#o }] &Sʙ+ 9t?,j"pD<Ӌ$K#}:Ş 샰X*~^6Ob?6KzMjldh!Of_3S9t_,L/&p}."JgxfemϘ5GcGm3 ԝt~xJ@t aC3ťw立"}FGjVfŶfȧg/tRwpJ$%!2"0=.am6Bg݂mXfg6IEvߖSQYfP, l{6X>-aa՚,J Pho6KzMjla{zfrp6j>}rVl2gL"9}wM-@G,=6O4; <;0]ABa_ĢTYqΌ})=wM-@G,=6f_y?M3mأRve;dz <˱X*~^6Or۳{ LԲ |Mcc&M4ʹͷcJuMh/bQymO6!N80><;#)gn$tL|),R.uSf7cc&[#l/rh߂=*0>+zKf_lc$#H80>f Kf} 䦼,+%?67MؘVH+ f` m3>96occ| C1bZ[dԷa8%3~ 7eY)yOuRnlN,;Uo LZGZ5'T6{Th`i} VtxMR1>60~L}Y5bptrJ*# 䦼,+%`X5+bF aP])/18tS=6f:fTre]h߂=*t$OIi韊OƖ 96AMj`Mvr)}}ŤV/ZM2?{]R /6X1aef$d_=;/@n˲R2J̊"aP])/1)f1։V62K~? m[GΑS\4S g$-})J1+pFR&X.%Ic|lHtN闡3=9~rS^?WjE11+"7ߌ=6f:~vȕvm~ 6C9$%a(fYTNs2*Ggh=\K1+Ŭ r2|&`VtKTw1>c$%aFRiT闡3=9~rS^?WP])+b0}ScchFZf_TOBQms$IJP̲x'quwlXUt!}8ѫw`&I QY:p'}Ŭ2H Gj8ZmuTw1>c"0~LwJ8 0e7啥\ZJKt$%aP])/1)3jies辘TtN,%of:GZa8on~8#xY)'LtcK0)(d=,1G"6+2? Ig$['e/6/0kne*;0>MRƖh`A1v}h߂=*t>=% y {*[U0e-'˲I@gE J?HY_?Dm~L닸s&nj >`A1v)6{Th!|zJ*/;i]Z;N)aZLTԔIk0Ie,/1fe~@6Ob?LE97yS x D{WO~L|zTw;i]Z;.QH;y0+h=\Kkua%I=R鐫Xд͓wM-@G3 d3?_9aS!jwҹXenl?lsQƦ1IʴyYjۘڨ-ǦT:*V4m$n3خw䏬+ Md/L`f`R鐫X7gL^ =>96!W2?h ӗaAVmq/bQyM p7pˡmXf86, m3}rVl2gLaEfQ93`Ahmq/{f5p?v68mݳ6#IDt9+OZٖnD7Z:\O2#|uY]46_O;EGrOh}aQgc/y{+_ ":aNd=["Ie"6x/Y)fg(GRfY|(vRk3&WM ?Ml\#oy{+_ ":aNTpįܢB&V>r}(x.vRk;:( 23Ii>6aC%؁U=vakADGR9~ކ_W,dDt`C33FԔIg GjB",c(Uˈ2X+3~Fl;aX9+"|9v`Uϣ݃@XZ+S0ex'qpbNªG94=[xY6)hyE/;f9[E$*bQymGSgeVf&7)4͗/ê`V<=ZLIlQv3qp$Vꭰd/vCkϋ0ɖHUA,J?mh238&ލXh k1=VDt$y ~uVa/&p}~[&5N'2 CX*~^eΘ*^)7)4bQYzd- ׂr'N&p/êrhztNFIXUĢT.#8cLnRi_6Gd;Abz -H*/;KSid"Ь8@}FTIObQymGSgeVf&7)4Uy{+_ bNd=[TĢmo,#|e}mLŅE㰃X*~^eDgpM ?Msm6lK%`vE ;Abz O}r 66&n, dz |*A,J?mojϘ?=z$. _ĢTCf`Gm3>9KcGm3>9KcGm3>9KcGm3>9gLafhC 4pˡmXfm-,RAU`|D7ėM! mRk緵rA_4fm|JXUO͆3Ճ~Hq6, m3dv>;2#;ap-}^%GF0e86t/RdG$;6Iv>*LL ˅Ivm؍?8836xn kdb_.L# Qax͐-HLSfF\2VbH(Gj$tRBTIg GpDamOL ɜL_p'.sg#6jz`?']+89ܹ B ֙=W7 ?gHuج[w`&%y ma~/&eSq%N$>Ǵ6g&{?p!??}jl::|z`s7e&T(g$8m6|Da9;V ??Dayꢌ5}m_lm_sKglm_.۰>7/j&ٱm3U}Q;\SB,˲D7l(fcS`e-66jK 2$/`ih3C 4pYm|}_bWam3>9͢_{~OmcCE _m}7>bm3>9׷_I.#87>~OmcCE _Ϋ/vQyد =ko|o P*f}r^6KvQyد =ko|o P*fUXK7TP?dmRk緵rAm}7>bm35 J)3?;rc+ms# ]ˈ2Σ~O_{|X*P6CQ"f:2#28:QGZZK?yUVR.#87>~OmcCE MxLۈcVfê[ 0X9X~OmcCE  fE4B- RI餾 3э-1~OmcCE -㪯8I6eHH 8ʋ$c])餄ʑmc'U졢mqWy {*[Unn3e٤nˊH2eO_>ko|GTZU_)E ui#8}vv @)>/!a ˡmc'U졢mBa_m}7>bm3>9f_{f,/4UCE _Ίm3pˡmXf86, m3}rh>9KC `fmC_m36okf G3 &5FK'GLj`MWs~[.61Zxvl?hdMDdȣnk2`elעm@>%*DHFkD*Ճ~Q^c&xplfwOZ'vK]o7. dz gSf$wnu˺07I= ;ErmP=j4H%ۀC6e%c&8yM5?Ŷꮵݵ+ৃND;fe6*ŐȆfxdR7緅4rVT?;EB_kn9?vp2U '`RYZkWuX+mknw-‚W${WӧSSه&ʋ$c])餄NeNeA,J?mR_tˁn%x0,He%ʺ6d'f, keK ˩AY1 1~gCqLRn!)7IBx.Uw@Xz8osuOe yJLjdp, yY 3TS)1yvRk!rz\5n(T"0eXUԡ3K0wp$e& '7_4Y1d:٬Քsmknw-‚nWJQ;i]Z;Nk)>/!a\[2vRk!rz/^6IUCݢ SMW-ԡ3KB1$%EêYjV~(tT`ZuZLVRNZ=ŽڲKp-}>&TX*~^/!nK|#)1F(T.TTYЙ%! ꇁbR_t"+b?:V*pmknw-"&VE siOe ,Jk>n&)X>=X!rz/^闡0N'YЙ%! AK?Pd[ꮵݵ~ؕ&e0I_ĢTq5@H^[C5n(T"0epᥳNDpkWˆNF*Iemk]kwk1=>x A,J?m_@GBTV׳u)gKR%c_LlUTdG8y붲gkTu ׳I%Ŷꮵݵ}r 6 }gĈfMDt9}r 6k}t?{&Cm"&CvK]!w˴m3}r ˵gHhC 4pˡmXf86, m3}rh>9KC UQ ߆ =Bq1Vo+XӖ6, m3'Y)VON8:|,e8Dfmm@ yl$s.˺HYmXf(>lk߻Y :)ß33FԔ m6, m3QD@'Lne٤n`m0h l#n{86m36_T٤nL\`6, m3dsVLNe(.9eKC a).:|,M8WCmXfȷl5 kn؞O&\緵-w+fmM$/`ih3C 4pˡmXf86, m3}rh>9KC `fmC_m`a&Ql/x]<{zrZ2=A,J?mi ɶ6'xh. _ĢT柶y]l;r{? {OrZ2=012}~[ƚ/bQymOۼ.HT9=F`&M]qwao\5]NA:'Y)VON8:|,e8D;Ehۼ?ك?F$s"IwPdh4cw}ޅqէt9_fh!}yY C1"vRk:;ogH}:ŝԅ"IwPdh4~V%e[KO87. a¬tR?!fgv )>/!a(fYbQymu )pN[$m#0ԑ5a8eJ~*v'o]W}zMz遰]I!O˲I@ki@`(U?yfB/Sf9[Er;fg,2Z"IwPdh49̾SُЬf7.썫>i=@XI6Lpb7I=yYj:vRkgfQfeՔ9~E63iJiesϺup {OrZ2=? S%gpCϏg>/+ ÁbQym߼,W1!_w$[DaDZE63iJhe_wr6,mIj7.썫>i=@XHh>!=0ՔXY&beYVd)Z;"IwPdh4N;%eTDt߬L`w}ޅqէt9+0OYUqp }>&ѫ!A,J?m7p$U$ I6BbJ[$m#0ԉV6uLJ)0#]qwao\5]NA WA? kn؞O&\緵-w+;E6/0Nu23s6BT8⏧:"IwPdh4bR㔩R)f7.썫>i=@`SDx(c(UoZY+z2kB/Sf9"ɐ?G\&ƖT [$m#0VL/êR0UO87. SNṰ_ĢT=.I#*'G̤) r*}_˩E CqzxU^dz <˱X*~^-tGUNvIS>v'o]W}zMz/bQymOۼ.HT9=F`&M]qwao\5]NA#`;E?m"IwPdh4cw}ޅqէt9}r 6b$@ݣ?^t"_E|N|6c(Um^[$/<.m3}r ״Kc$@HgA `ρmxpˡmhafgA UQ !8+miKrh?f|l{M)K b5>8RqLtmhammO47.0]NA:l?mK%Zc#aCp9}^EP̲ĢT柶y]l;r{L"xU^dz a[JI-0tNZ,e ;E?m"IwPdh4cw}ޅqէt9H*LBD8^M ZH+ ;E?m"IwPdh4cw}ޅqէt9_a r6zMRp}^ĢT柶y]l;r{LR d5d CqzxU^dz ,B|цS%gpCϏg>/+ ÁbQymOۼ.HT9=F`&M#kpʔ0UO87. asVLNe(.>/ˑ!A,J?miI#*'G̤)uwa~fe6#]qwao\5]NA ȷlOUuGciĢT柶y]l;r{LRGZfijn=G>y޸kփLoj" =MmokY[VvRkuE63iJieaX9q v'o]W}zMz&}c(Um^[$m#0V6eTDt߬L`w}ޅqէt9 =>9vRkuE63iJheiQJ)0#]qwao\5]NA#`;E?m"IwPdh4Nne_RfKsO87. _ĢT柶y]l;r{LRGZf J)vW>y޸kփLG>9vRkuE63iJ]aX9% -%v'o]W}zMz/bQymOۼ.HT9=F`&M]qwao\5]NA#`;E?m"IwPdh4cw}ޅqէt9}r 6b$@ݣmfҔxU^dz <˱X*~^6-tGUNvP{x҉hL9ٰ_ĢT柶y]l;r{Dx P)l5mTESf[}7l>>kDﳍbQyMۼ4HTxP}JK%7'"쌤<1#󝥌T8#Dq8#A96 ςJԬaKpb8⏧<29T ;") [HY_smAhm3Y)Vbg'#b+ &3=[`DM60B96 f hrO^fh8aKpbNP̲f;e>-_f1*R&a(fY|"͟m3 rmfw}ޅ?"i=@X#^ ^◄#)R ÁWphzMRp}>/J$["e0b(Um^[$m#0cw}ޅqէt9^#3Z"V!\šlR7eE$tR)aqA,J?miI#*'G̤)]7.썫>i=@Xa7$L?84Q\:p'}^CL'f ĢT柶y]l;r{L>y޸kփLORĥé FR0ϞYUqp }>&N$I=;E?m"IwPdh4jV&z5t_,*KO87. a3EM%n#NֳEJ D7nfno,}~[[f&>ۘڨ-'bQymOۼ.HT9=F`&M#k7_$~?xU^dz c(Um^[$m#0ԑV6ef {OrZ2=>z}r 6b$@ݣmfҔ:0;a8bw}ޅqէt9}r 6b$@ݣmfҔ:ʊTrNBoaw}ޅqէt9}r 6b$@ݣmfҔ:0# v'o]W}zMz/bQymOۼ.HT9=F`&M#l?ʊY)fxU^dz <˱X*~^6-tGUNvISH+쏧bVYcw}ޅqէt9}r 6b$@ݣmfҔ:0㩬bV]qwao\5]NA#`;E?m"IwPdh49~+ =(ExU^dz <˱X*~^6-tGUNvIS>v'o]W}zMz/bQymOۼ.HT9=F`&M]qwao\5]NAR*tHIҞMIA-$l$2\nm7uvRkuE63iJ {OrZ2=VC;a6:םK L0oǚ3);t:X*~^6-tGUNvP{x҉hLwa5#RŒ$u/I00Ǚ9<3e]r2l!e98Q A,J?miI#*G O4 @ -#RŒ$u/I0OY)feR:p'|^a )anbQyMۼ4HTxТt%LVxz*Pfv2n9aN&pOoS7@96 ςZslQv'K_aa<ŋ$0RIm@ 6< fhy _aaC [xY6)˥ERIm@ om/x]<{zi!/ٖ3K_aaC DMꢈ(a )ansmANͶv'o]W}zMz3c(Um^[$m#0?V _aS٤@>y޸kփLG>9vRkuE63iJi_s辙9IIXbw}ޅqէt9}r 6b$@ݣmfҔ:һ}LOIXbw}ޅqէt9}r 6b$@ݣmfҔ:һ0%v'o]W}zMz/bQymOۼ.HT9=F`&M㽫XNIe5OIXbw}ޅqէt9}r 6b$@ݣmfҔ:һ0Tf7M 7.썫>i=@xc(Um^[$m#0ԑ52#p]qwao\5]NA#`;E?m"IwPdh4t9~?LexU^dz <˱X*~^6-tGUNvISHÖ/HJ7.썫>i=@XUEn;\Sb))r ,Kߖ[Zocx߶;E?m"IwPdh49~VrJ*#,>y޸kփLՐN2uRFdéB tXpFR8*l)nbQymOۼ.HT9=F`&M]qwao\5]NAjGIIx^0h̼ i.9~2 ^ҩnbQymOۼ.?=<YHsꨪءSIm36ߎn6b9N𬛤OƖ`EkU g$eNhn= \ 6, m3z}rh>9KC `fmC_m36!/`ihC 4pˡmXf86, m3}rh21OaUt8TS.I dV&Q6OubR h2OϜj-6d=[r63<>iVճ3Uu m36C%*S ͕*UJP1\D,-̭6, m3d:_n!vzvPTEgLn5wrO5dsmXftD%%aU d-L5bdams[xY6)(^ T] mXft>@%%aU H-NU MI amWB 4͐|JJªr3ZYԈsh8 Wr}lE&CtD%%aU dB Lp-&9Kr0eاZ\mU-s"i=@XΗhNe?7!NP*-&4"0=.˺pWb(Uje47f01 ޻eIUqU&)ЙNKzn-#`;E7U.O|mЬLURa˰}VWvRK~rXe+ 7kTpR)E ;De8Y7adfg2T˰~V*zn-#`;EgU.O|mPheCGjBrTFR9~RITJXUJ1?\z8He_jU.a&_Us)(x5vV@xc(UREii"BrTa--2>V*pvJ J)Vðt=-R68A8T0e+IAVbl֥}C)Wn깹{඘}r 6;_VH?Mm)R2*O 9}ARWS"JB$*(aZ0S'('pvf [HZ-ݐTOe$ #pn깹{඘}r 6;VH?M@ۜd=eV0oL)DE.~0"0eءU)z?a8U1TO!2 ;*EaS~?~'}bk=p[LG>9vRkoD]6U"g%fl:Y֥LlTRf9ۡZb6I^IIާSlY2 E*gEPEgӾnvlRPS驰Nʬ gƳDo/깹{඘}r 6;~ v*30{*1Ug>9vRkПxd|+ d&gpC/ĪYT.I v&tGYUTND7Z:>EbRk? lf?[f-qA,J?f(LI@ VhE "Y)> 3&m#),BfAtXpDoH,`im%%a(n"FGٝjAm}(>L׳hRCݢ6,ͲmpvSQv'Uປn#Y n1OgLt5ጤ:Dq8-6, msd-;!LsV͊tR, "qFb3эlnl QmEiV?כnA 4+" G~ Sgm (8De8-g9 b)Lp2U6,ͲmrXY)TN6:SB:}Lª}: dsXT2 CmX'%Y*A'u zIXU3 &LK/J CmXef#ᔔdFm~v]2LUZ|6Ja}:D,e8%TIO`inkr**KLuMR6qn<-IJ,+جTĢ;fMcۊ״-zRA 47Od /L`f`fmWCa_m36!/`ihC 4pˡmXf86, m3}rh>9KC `fmC_m36Dt<%V-bFEv̘$Oŧm<6;Mj`Mvr)}}ŤVSς`iVhE "ນ(Q:S\4S72? |)J1+/GC 4˶͒07#t&PRbOs`ҞmmsgT'Dhfٶوl8) ( eNٰC:t*;Lt5mfYm%~BA:&V[𫛅A:NN$lsQ-D=NB)TdMM p+v>?maҙ@IUðofQqtr*Ёz—2LN'%t*s*e̵2?inN5fI} &LZa8osuOe IJBhD=N~6IJ1xZдbQ:(f ui#8}:eZ0Qu@"J22II8\+V}'팤$t&0IҢGqvɕa8_σY)>O뀐ua%g?<3m;}ir**KL@Ev٦US1$RN:T˲tbVJd,I Vu@RVCGVJS*Q4m3lI }S*re~@6܊R? S* )+Vmq/'OFhf[ӗajlXдb/m3>92ka/m3>9唖=ae~@6܊o<:iN_f72xtZдb/m3<:hf[ӗ V4m3K FN+VmͦO@ 0 Nsm;}Oq 0 Vm" 0 ^o6gD 0 V/W IENDB`stella-5.1.1/docs/graphics/debugger_options.png000066400000000000000000000006271324334165500216120ustar00rootroot00000000000000PNG  IHDRY'sRGBgAMA a pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATXG 0 Daq#!uk'ƧaߥQs<DtD2]#c|~8]0})Mǫ> jq;/D[4C8cbS҅~ ȧsvEE1H?IvWkHr5.BWa'| 9lAvs-EV}I_%!R鯐E u?]0ӭG.Ro]LtD/ ZbIENDB`stella-5.1.1/docs/graphics/debugger_ram-dpc.png000066400000000000000000000336151324334165500214450ustar00rootroot00000000000000PNG  IHDR5"ɉsRGBgAMA aPLTE@@@hhh4aɯ|ϥ> pHYsodtEXtSoftwarepaint.net 4.0.19ֲd3IDATx^흋z+Fw6y>$[m hYw?$]jd$ɪy:Edռ EXõaR1j>{Up)T ,*<#4;t;XZnh^,pjU~=pг'hύ63J=RFf̍$+.T 5 PJ#gP eP (SKg%> [0)$"Cs `iy`ȁ⼒Ѩ ]>J*V5xB3G N{I2RN3Tt2y4+X~MUhmT<.oKZ Y;n0T08\N :-Z5?%C wXf(hZ󒊧FUR5xVs+U@5VIXdŴjTX[22I lԯ5{-:H^@zbs6քҕɆ$|Fl"?\$Jy`m pՕuƱ!rD.k_?n&O~Ik5>vQ84/LL#[,;!raa0w=◐k^<%n@0j|U`=M\G7B-"̉Beܕ2LI_Mpș5{EVϱC(h'4&{yoMs_ ȀJHd5K .8d)mD6 A`hFG!?$5}sMr\'?$5}sMr\'?$5Py?ӪCU ꨮ\j;Ae6Ez&0f>zH$\!g͏[2;L9jeO}Y;&fJχM~P $+lJV5~{}ihL<$M~`OZzn£GJZJF9jEc,hn%@чEk"gCV5@~ʏ^U/\\ᴪ_%]+|{ n~}W$OVMr>Y5}jd$ɪIU'&OVMr>Y5}jd$ɪIU'&OVMr>Y5}jd$ɪIU'&OVMr>^5 `||l Zbf&d| q{؅z̧^ն35ves3| =|gux0g>dzn0b97._Yp]>7Fig&_en]_g=35ESAx%fGLt|Z3CLt 'o0K1j^0cnl853Azq ٬~_짋DŽ LB<kzf[c3=|%&kfYl~nu@ S:&ibn\*INZ!ffc׫O gLdnT _za*%OUUR_IV4ʪ1,Mj4K¥{[46y)v'gC!w&02$f5#WcMEiR5T3Uv\vg ;HeF5 #hDӕU=5*jz>d I4Y5C,USB~~=2Jch ^㌌CC!wf7Yqs7# G`Uz'3:"EKszwBHfhk< dn56؄ U*.7yU5i~l)N MIF ɚf h`TfT5}P̪v^i&DDenaFOPP7DF""JP!J12PDFbn< N^Dmѡs#\4 '$':C`4&hmLM(hD#17W,y qXZu0b,34!0$,wImdl\7Fx@|{Mju@pb<ջI(!8%iz!d6'7۪)Ajlx"Ls!74k:#p.LivBHWOA%"0k.|j82ekJz 7ש12 z_c&*MX؜k.Hp,?/ c#J$h 8Ҡ٭7{b00 KpƾU 3 ^ӀHs^HAHV4}TM%2j~^A2DFV4WC5A%3&9<\nU@Q^媡B!:˄B9FV4yhjY!i挪S" ,[Ѿ54drGmh͠j{ 󊪡0:h0GU p`0c0攪?1r37>lowahj$101VS5,.htW0hjzJL[MffalK U; =/w234x!||w#kZ#ajY!i&fH9j!i&fHɪfijY!i愪`D༔kw2#6~d8^W R #`:Y攪~]4흼3T4:4AIF/4TMw%u)W$/BZSAo<17@l\7gT ÆHؼ.2xKEؠ7n5͜jnC `O Ffnحal.}u'76eN FDglO`T5 ի=M FDglO(~].;Tu\O1>nxה(#W2wUѴUC#Q3 sA V5tD KVwb_lDbbC[&pbf7`TN l̕OM`!T nKKUCGVM{#vN+b4 %ݍ,^QQ׉քUnvߡJPܨGw # }YjJm8$5a~ypcS=hz14qQGT W̰j՝NCCy=$ '/1|?b,$5oU % '/1 wƅP ,slZI&FFG08j[CpNb<C`}{) <⪡:)kːB UÌkFnnIR'^b|SydGĔ)uU)jͩī ("՘*o篯)M02bw`X5_ūF^5WupA2rT'OH $?X?YT[Ffבy]S5i0Y5C,MV͐4K3-W!{2Y5=j~ͻKSU ~>'&fHɪfijYiIj~U KB8/1 0ߠ-WL6eSM ARnadPc{Ã+A&TkgKU)H<0Dkޭu騯CS\Uct̓[:NA }w*"3`RpU#䦜wp*&ncKO{ ^iיl('&j߭cs?:\VuKK [5$$u4סB5LYXpYIB ! l zŶLpH۪B?QQk r`#~h0H&lִ 5e\BNA44δy7]ǓOU|?'0{j[ Xy]$z{3) l~ S`]vDgڼ^IgmBX5U_:ץL'ZSƗu)'yH4):s#Cn< `|{YTeD6q@_盫qi..h:#hi)kI7B32k|V =ryH 7b\5wpvbDZaܘRC{vw֔5Jvӱ02b{<5>dU3KWk=`w 6p0>ՃܫVKBpĢѪ#)=`$,߮WV,k;T L%tHS#57k}i.KUӀHs^cQ'&Ȫw(Ԉ&O+tj~y jj~U56P&9+U^MV͐4KU3$d I425}|{Gy)v'GXM3.xʧ5k|ê*5}!؝a0vScTn }cn QeƧf{`\ج T/3HW 91q*\:H؍0\4z@k$>9kk֦Dm|>l5]8Had̍MwsMiT_F^F@bF SDmUÔdk,QO 5֬֔(N)<`d!tL-DY# z7Sz؃x~{:A}n!< u44#ƚ@p]If!cԆ3 1'ɇUkOݺ5>TM; &fHɪfijY3&9|fijY!i&fHɪfiΨ?(PHL_}o $ڬ C݀: .!Q5^2v^i0ɔj¸mƧk*c04ќ` Kv' g`Q5R1lrB;z'FZǔZxM۬Í&&5xM2Ą303Ə-/ n-&")A܍z vkJ";`~PSsC-N;GwG C !mY=A j$똃5kB1$ W&DS= 6F1o| FrP-R\ j9wwOmg|(5ajm|!sFj\^5[P |Jkʔ!0d3_33vΔM!jS hΧZ5hNHrn@sjGBmbh<H☪EUG=p jǦ4n2V t%T)>ܔҚқ9pU4:g˝ 34pv㌯q"L D! $hl g՘ HFƒ1ߡ"i0Y5C,MV͐4KU3$ҜY5{͐4KU3$d I4Y5C,MV͐4KsxO'?;(5>ۭ$7.u>|F9L5eM@vML8fy#DhQYtDf M[CU/ur^:"#7܉5[k`| ak0Ӄx4՚0<7jy,?3Sz 7D#=Xb0X5[SnV tA'0|ZT9A k֔Ƨ,^niFbn< >ԜP5R0!FLR88R7$PUMPόM":51c;:c͹ߡ茌<`$c=!F8]S65 El c>i8HsɪfijY!i̪I&kY!i&fHɪfijY&2AQ`Egƃz7N܄MʌgoιU#tֳA?n|3ۍv 3ލnst]5qNFabR(k?S'+שbcnw팪a0`8h!^~ e݈M< 6@ݍ^)ŁqnIigAӭѤv\HJ;k:'WM}Tه Ɣƾ[G_쪩{,a#d S;## 7#v $[# $37m9jNhc0jN:wu CpIALZ\m”uf#Fp\DVPڔw6I@21Y_G:Ļ5H4dN1S.Mk" Z+Ȑ1:FPjlڄ]]XsX@Q5-i0Y5C,MV͐4KU3$ҜY5{͐4KU3$d I4Y5C,MV͐4KsLt`E1/)Pxhk82#pl_%WɐA>dcS5}UC1!:ۜɓKJ_nfr˸g]y`m |,H2s?ŭ1jl^̷U.ښ_fUݽXLl)WsԔlږ5gVPjU㗬%ReFCʃZ7}`m 17D]{:KqbQ0BU5ګ]"Eh 2և)Y*x H&{"ќ'U QGt%!O]Uԁ5陼AhPa U!~#ـpa[d|Y5SjdL9j#fJV͔Ǫz ,}UW2/ѪI~3Y5}jd$w]nC̜IENDB`stella-5.1.1/docs/graphics/debugger_ram-f8sc.png000066400000000000000000000153141324334165500215360ustar00rootroot00000000000000PNG  IHDR3q sRGBgAMA aPLTE@@@hhh4aɯ|ϥ> pHYsodtEXtSoftwarepaint.net 4.0.19ֲd0IDATx^흋(}޼ e K16/s 3`d̜̂Ɵ=2svqVvy+ |$3W1"2̻ 3ˁ,Ǔ30O9ug7MNF;2Snc| 23urjΎX:EC^je%Zesl[E;'3i{bqjhe*WޛW +CsU[0,ʌ-CL-^2'5I*ԙNޱJj֓[3J侐N*.Xtā̤RDBԳ?d?T&}M*W7خJ#+ޖaP V&}-le.3:ȪY4 ٖhdʌ#Ԃ2T`y鳮`3j9KqKFyJ9Y,fD{2c[UUJ}# 3v ;c7d?Y 3`ddF~X?s24̤k 3Oc&3 K㝠Hf~ݰ0 }Ld*&>,HMÙɺUH#Wg73TMqd7q©F>=pA $Ÿ_Ը+*>H:co&pX$2[I&uԋEٕЩҏ|BEx1G'"q4;q33VIڽ"2IM+bȵ >ZU 2LMZT+ȧ$7nAXtIkpd$4{M7'0*|킏,[PaM+ [HUsxlf6h1-(uQҩvok0kt,9iËl]"ZXqxGV3T(/fUܴEEphܖNE?=]ܴbHx9{Vr([OP@f!24vj99Y\ñ n:LQђVfXf iJ >id5bjGBe }ҵDH+ln'")q(uS*DIyT]TH}2 MxeJ\Z ?õHQ)bQȣd>)&<k3ozW3ç@v6Wǟ2vaW.̀nr}okSg&d 7=ޛ'0 g,x?c߿7ǥhl&/{7X~Or>tЊq+?tk 3gSW*C~y" BL3}`7s|U]9E"|JR YJQR{bֻDZ?MJHZ-^UTL8ŜPd|DB5#n\mEQrsD\z3tD'jE.^Uu"/3٪|tluE&3঵f{޸iŐqϡ&-7-'U1]@Z[K,.fN ?"R!4'XRsv4V\eVABO 'Z!Wp 2>" )p3NkWnN"+˴߈jE% )XcDx\Mmn9?g,w?g:+π 3`πYp?f?5p?.^` ԙ g E_Vv Vf"~a E~a E~a T 3keMO g>ke`y]3Z|>s3 3`d̂̀Y0 2fAf,  3`d̂̀Y0 2fAf,  3`d̂̀Y0 2fAf,  3`db OFka#/:hMdȊx-1 #Pob^)?:ld{HJx`Yw^x=QEOK6^w fp;13 iˏ"iE)$+;9Qb DVȉ 9&.ط&mjHnkc-mCxT7PlS{} ə鲳&p}{\r'B9eKPfVߓ ֤%:h w½Gy`M8}{`@}fŔLU]KX5D׉8]^Y3>=p)"2Q}lf P9:ZTVIk]+.6`*[RaIe%kFpM8t0t8]+41q9=0x,  3`d̂̀Yg >qSNeK}Ku*2g|SYȌgT2:jN.pvKՍHνZ2←h+3CB{-.]fG,FzdgFRF"g G[38w;lqdT% }I.+zx?-7pvؚ͌4E{u42Dg!"J.2g舕%322ޠх=8ĭZ(3n=^]&i^,e䢌 (2G2R%g5sj!3po\^d1pV XNf~3괙k,L:|d2Af::+dg-kvgkŎPQ-Ɍ}EurQf?pFjS1qf.Y~-y)C# rvtݱ2!c)֤N/3ݸsx?3\vV.:apudh5;gBqs&vxCt| Ⓨ qT8q@f81+f6v+q| dg f,XwLS6qAe&^Ջ|CfL,q| dg?39D;Pfhfxyi&';v5.NwL}72C[2R.>PHP+Hm)}pLzVJm8K833Ԥ?<ж:=pմ#2u΁́b}Q1J 3_yo䂤\ k3?íuU#3_ 5֥J@f 3_ 3 dnf澟+NfoNC0ڢEzpnv̬wAn\pp: qfU]ns@f AfsY ysf$.̃U3=Ywi{taq=p%dt3tpΊkיp2Af::L8CgܟvY63Eݥ<쬚 7.8K8+dYN,:Sf AfsAfsd~urLd拜63vboo ]C2c2wi{taqsfl, 3 d3{s ͙kuseߤ؂|s~&7L\lAfeiPdcdBܜZ|su& tt /gfٻڔRjfhKy9r)BU>x13An\ppޛf?3\[nܟw E2SYN 39t2ciHki3sҿ ]Ct2P^:_7.m.y!tm8K8L8Cgt2cwrLdC63vbk[Vn9M %dt3tpN o|esJheysdu.s}ⷪB%*63#g g73ԙOE3Cz  7p"g/3)Ֆ 2 ;`:̸ЦKsT0|nr@|e.\rҪV65rfxG<:afB< užNglvt3t33 2uN'3l!A@f:DIUȥ뵛r\?ʛf^l&RBfb2~f`mGySna+R+ 3!;iFfʰhN 3`*3_gE̤#kA< ͌l>;3P ̄yaZ 3Oe="𥲫FfQ ܛ* 2N+DXvQ ŽK)4LH?3;3ÁN|d& Afd& y-3ScPÀ 2fAf,  3`d )IENDB`stella-5.1.1/docs/graphics/debugger_ram.png000066400000000000000000000166331324334165500207020ustar00rootroot00000000000000PNG  IHDR1fnsRGBgAMA aPLTE@@@hhhb4aɯ|ϥOC, pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^흉z츍og&ɼ(dlOP mgkkEcִ;fkMcִ;fkMcִ;fkMcL7/r(΂WrF@29jH Wzdkn5^r菶~vR P].tZהkX%2gp:حdDZZהkp`bk}4ʘ:#4$ ,\V.σ<dAX5GGqDHC2̡~2~pY,ϪzhiIAX4f}[sFctst5~_*\+%%CYg rlh5('ƻM.1]`.5C LduIrH]2Ι/]%&ŏAGG9,vwA嗭xn_'UpDVtsD`4振äˆv)!]4D`|t٭5Z5ZG}u];$.I#?=wan@ⅾKśi@Sst*V0E@r*j"z@Sh&~ɾc_;( +$5HeM M, Qf'xB. &O;cD蘿P428_ږt ˉ*-Qjn!,4WH e"TnI-#Ҵ (I?A!qWKȉ`&X f⁆.ɚ6&DЈ7vL5&Aېԟt ;$|<ۍ$ :*2.iBX 1瀐&9b- dϿOh .!ymA#O܆&'\i2qׁCiΘmb 1jȐ"<ӵ18Nv 9$0%7Jbf3A @["<ɍ #֙Sڄ>1'I5 #8j{ @C9$"'9%!a]Ǵ;$4mL)"ӵw$MpZf- &D ^h`jHdsb1Qe: D'sO|k[ԎQsD\pAd"$KDwDŽ'*w3A}Q ,f1o+T٪BN t1״1Fշ=-̭~)/̭6! }*Mʎyt1BVu:毛ōpTzE[mB= }d1>t:+tTz3j"%C:fJGJX r %@\[kza|udqTĩDin]DXr %q-Րp]߭:;S /]|w-ݒZF;F Ryc8铼-Ii3&a4Kݒf$KHZJ )b䵦%aws5Ӓ1 $քҼ]:&a띴7̗C*ku4&2%siҒu<sHnc봄Ł1F[xp,JX#TI{A:ׁb779'n;@DlD<'hc1 sQqtE. O܀W_G$]:&a xP2Z옯~S8K:ׁ"ǍqNQW'n\T+T;v剎 P}Z39&r7 pDNcbj+0N,VK :do `3XKi.sb:gLbI]AC259W`k #i):8b13RuLG<:f-vMAlC2Cɉ1:)eڧHJΜJUW)vDzic1F‰ؗ08I, r,ͮ#+=GBuΘvK$d3i-Ga$6qC@r ܜ1c:ic]w#OZx&[mBiO%ңl=[}LM~hC4<} ji#~hCS)JIZci4$Oy %O| ѹ&OHWu N%*PjLEwN0f9BIăhGtcJ)ɻO~Hy L@ u7Hg,s1,8,U5*V_߆F<<Q!ԢJb;&S)*2|Q| |&0i㞿֤ "x4KKK ױ!'.I#:&J|5x3I$ $;Bߥɿt-Iq<A=G}7>x&11'K17h1,8$Zdw!5p2>(P=K+J "c0ڄ:&}w]kGwJL0ڄQ LÅTC$Mpe똭gk1guWShrp*Ed MF1#}(9>&5ܨnjTPxh>xn)YTCѩ&贅:ŎI?6  wyMDb  ds ,3y]"$g0*hΗ!;کd#G}7T9 RIDAWPX8ߍ%(:\$LrN%;*zCTxO.u Un7GZ RI;ϴ}&FԛPXH JKPAD rQ}HXL}˚u W)JY. Ru瑂;]"HK,G&1 "*DQʄ#w3 ]8#Vc^֤cc{ @Z _ $Z Kh+0C"1Iu.ʝCBe!'%9ޢn ر[n`L MrDx=#JKH%e"HEd9,McTjs#vŠT97AD- zčpc: n+(%9xVBTxt"%KDH{*}vw&1w~L85Qa_%R,¶4Ի- ͉8N|CBMSIb$7:?TFM8Ȟd1$UL$ ėupPNJkɤY#7rZ}(iO%wiuwOWc{1T"=̭6!cH&O;vǐM7IO>N%n[ZLt?6$Z'϶ۜ I$v[%ֈ2'ӺPIhbIHHJx9)*`aA18>*b@2@<[R[MNELeNUI%ir"`KHS+pct*ӉdAs]}:A -nnƄX *+64r܀CQA#`,Tm`YpS{#wN~@L"*n !EYe$!`:Ĕm&92W?hI1JbBf$TF O%kJt4˸cPT;$ 1!FzSI2m ^`f]1//sntAy1uԋjۻ޹:' I0 IeN 7%D0j7wHyATCvVȏB}v w>ޭ&CVC(mkbIKH[d9v9n:h ag=d>w!`eqOI^!ntIz@gv~N^9xT]^p1dT[5A?vՙvwT91̉yZ}(iO7>] SՇTiiǐMv*!=t:p4>Z}(iO%wcӘ)"p&NhkDi)/UBzݣk?F7.$wr`A<Vkn,RiO'tǃ$ "Xr:A%q Rg7IHBNw s3iY DT;J 8&quN2xwD8bfS)6k4bǤkmrTBh@aU ]cFPr5JSi%'O% 1(1[֙yITCəS%C:f!=z;hR ˴čOVJ ō.ɞe$ ZɵN?hA/vy:cB㎡~ijn]*׭cR’`Cr:0:9:җhc@ FJ"%)r 9c𮗭tL  F X%E:UW~펹@lAOK@8"a*'Yr*YücJ}*DIqcBXh稩vy7Hmc*!$!% ,*_ KEZF>4aZG/uTUu ^1\FF<*(aG5q 愥^uc~YK " )M/ip9%N1o8*Yt#H1[6y);NZv[mrH ٧Ѥ@xIz@P s>Llmvliw֚vliw֚vliw֚vliw֚vliw֚vliw֚vliw֚vlj/J(Ϣ{(,]RzcѵZ .jwLWcvt{:rGRtPRed;+_QȾqo$CzCmƏ֨cj:/j:Ɔ &qtz5D$.KҠcx#yw 9 LUW"1h:F`/xjMվhaPmj爊dÏ֤cZUv w@VP@ߦBp[kSN 4 θNٜ}a1o9/eht^v(D0 +FXLX8a6iJor YCn,Kca@ߡX("hW, %Kt 6Jrx6fl*$5Ljmno8%(HKg]@: R^Dhc@6fmP19 nٖco T%j.?>hQS|B*SyJz_G+7; 6HQZu .#PhW|B*;ƂZQ j Xl(7;EZKK0! CўSi8tMpC4*%(^1S,XS,)ژ*Ŋ6j$1 F;.U:VŊ6j%a}L8v& [ߖb^))ТR5T8XS,1RPZ;f+, ӟ%5ZTXwׄEdeۧp)Pc0aE hXR^cXA+kzE1O }Q)EvLMUT"ӕJ;q;d==[R ,#uO*ͽ1y*Vj*#/ɭ d OW$uO*賠91= vJxNITz阎US K@K "#sbtKg]Ǽ38db5YC~RQ49XQ1Rvb.l(!ucgo>ln9)P)Aȋfc*Z7[yD<&VJ J*غuW]cTMO nuJjPCфuKt6&J bū{+&b A,JؙZ3E)*He6 1"PfbX B⃲,T"c+cL] 1C ƊjCP+%+QS~k y}L=ep 3TJЮ`X uXb `T*qxc`}D d(lX:TKB bEWN鲹5T,l6i˝~J/%hX)]DPc$LRE&cbtiW)xTf3i{7T,PuR)xf4cϩP HnL( ,:F?%ғ JQ}F(rc$^muRP"SI?J.3>W@HqɌ"e1 $W0q `)UUq$s$WJVS J3$GI|+c^&cTzt̷1Zq+JeZ<]FtL1Nɩf ?Q-i?!l阞cڍbǐPO KAz7Tq֓Ҁcenc 6CPRZt̀Gj#p1Q_m czqvKcb|@*[y}-s s6\0r L Au*aYGJ1Y˧cN!3> vXp;~7\t28O%΂%F6MԎc<1sdǜ/|܌?D-Ž}*N3D&k 2Ircrcu*%S' 2c}L)5&Y1ɌT"z7Tq֓V!e#U֓ҷ284H >,HBpEp>/ةTT-0%s)SI&PoU /cǏĢHa J:Rr Ë`gǼ̆cߏQ/ |!@I\ʝqkR t̥t*c>P4hScS S9O-0%s)1o!r SrU1b{Ӡ16t̥<1z* HcxȩZ P"y*}+ͩv92{3\I?0ZHAs^_Eȩn,(Sc.>ctCEHF:982CkZԎv7cZID EhKr T+ 1W WSIM`_aV-1!Ď!W5*XȘ/v%91 ηcS1wD㘭5]czh/e37`1c^gc.dA3%@9F24h<^`c89]Z2cTThǼLm5>@,r1o!Oj_;"ǠdMİB-c$~jc[TKXPsL jgj6 d*cĎ14Nk$(ՔAFȳTzc:0c0> ªcHS11uh9  c)#?W˻SE98 cJIL"Ǡ$b $J ~?a;+ B YDzȏ_ԉc>.,:f7@)r7+<09- :l:s a b_]m@Ljz_%Y)kJ L$+Pq^I\L-;6ǒĀ&$ h)kJaKf1 ηcSI\>FMQjXt{wݒyZ411O%+j 9Xv ϘJBK\+Ky>f@*+5JJ%c: rBJT;> s_ G)1a4F"R)׮7<#t \ Wȋ@ŏR۷Ǩ]G{Xs - p`!+(+@TcDn#Ў):Fz11Q`a5K+j4c*Zٵ7YWlE" jkBZ} fTR\DJ)Җ U#D9cЏuR:KXuDHuhǔB:c)H" ^jЎ)Qٵ7\!/(~by0 +DX NXЏ);*ٵ71), X8P]6W MPq R:f@*P*O 8Z.{R2U*S xRII>8ߟ>v$ IH$kc51dtLF:&Y#IH$kc51dtLF:&Yc7Gy֐S2tHDŽccB1C1!!?1?0θn&fƎgn_f/CFh,.z-*1`v_M)tMRw+ry^2R"ǐI້3|B1[G4t) ,{c`AzHո:q-Wz8%8G7ɠj-׀'L^cxm%1b}NTil81=E@Y h*^cl)ᧉ}94Qf11l؄.scԷvmN^zՎ5t Q=czcu;F`_JyA3:E|c阒蔯$vLy9F6 9ŦuL¢RK"8A9:f"ud8nEA@ @X cADŽ~CZƎ٠wL1w7:璎 I IDŽccB1C9fu z]HoQ7v$ԤTDl[psu BMC?w+ziP;U=}Ưbg5b+@yb!ԤVUI0`7XgZP%>TaEyɣx*_uSrjRpMeV*ԣԪ VĠ<胊 #Y>Pզ&%5Sԥ/K^ -(P#.rpX-@Iz&f4HjP,7& "SK48PZMH 7 [=W%MHZܬ 5R%wɦ{,GYjt7"y0*A8pCSz5)WOj6+3pёuXXQM, ے2GKܪ{5}zVSZ55..jbPy8&ԤNRaU:jR)= 5}kTçDnS'mƿGDNkk1/ 9``````?*T%`?llŞQ.QM'gT}lwo.FԔr!@x4Y?Hg9jo t!RMp>Gznd*f՚ &.MV?|lRL%'wI-MIh >Oa -\ˣ԰B-IҴޣUtljV+%%s+ K  {_'g0[x-V5IMg'.YzdS ";3/{ȔZ `jPMgyl!RSqUAp;5-`````&날R ;X'ʽ ~C$wJMg`Q_s57#}+j٠Q^M A"|w7͠I}rMs:$MM,"hҨ55A 36F#}MyZǕS|f\ % ãmyԀca4Lf_Ž aGdc}-TM&Rlu&ԎXVM' Mi OpSt>Ԧp'{9Ъ&|((Ej7He'r3,de PQ_:|*D|P,g`14F''b>|@MHveH&YܤJ58>!$Un٘[XMPW٠{ kV=/6`5L\B{5'5|5iUƒ:SMEI4R1%NƳX0 'u-'XMF~sYD1jbBM0:Ŵ^M:ɸSSK|D:35JMg`QuЯ*Vk5 14Ee/]ByW@:Cu42pN6iBvi ܴ+R R"M(VqO3RhWlk`C)7ŅV :TGs.D!Gi0x3'] SjG,&yegt$tqrzP_J'P +5N±98KDБdX)†k HN&d.r2@,܃M,0qZl`Udz &5$Z1wiPK]659;>s/% SL` ```[dQ\px4O&4҃mllHS`G/9$/MMAc5!h|* {ı#Ǔ7]]j"PC]sy?H%{J5/C5'Ҝ0!jWl{t$Ya5{tT`$)NA- s.c]}jJFj ۖ=4I?=X탄eS`rJ8YV)r9g=jQHD%G5&|& uRw@Ck+;[O8|z6z*>=([XN* γ!.9%Yx't8n5v),> ǻp~)I0ja8 =E>SRI_JT䤑,[PNR]dz I`i LN P* 5G,8ݷ|DCM_J)FBM@BM8BM8BM8RĿ/_<מ73{mjĘʟU$ޔ;.5lNU5Q- >hW&V 6tZ2½"ԔĤ!%Kl?l R֦`9 5})`BM8BM8BM8BM8R-y͗n6cWGE|F~qxL cc"^bȣdeŒ.5lA1DmƮZ! Si!owA6xDRoXXפ@./֛"{HJ9v]ҧdĴ)%JASSk-(̵C.";0i1Oy [7lU'h0M#ľ=pQ%A@p*?N%mj SyW|DCM_J)FBM@BM8BM8BM8R.Y3~}?=~r@XMG Kmj+og۶aW4S""wu]j"d+l];OyN5#ݣ]MRHMYBMU\̳p|:r).hHg$9.`7^R>Ч&rT)wـ:CfA{μkYd`Б )⛐;EM !R׎t95ҏ Kp!TG #’!WuE׳*_'Nߵ@v,^٩TQj:zf~BQK' |BTAoLsykY1AM^ Ea[xTe:1o"0L YM7tҏآz-%+mj#v܊Ψ>s/% j j j j ƱW%u KnzB.T.5%c1i)9g'HA|Aem(}"$ȨJXKI5{6f$4(u56$ #:Y)sUݥKM$Sc.>ժ3 Zdj`yBg+AK=U7iW&dQ\TBl|"`).e!$c8w"_ɷ+ԔLLTs\]T8ͭ_f&f CJY\Ѣ& NG\Ӡd]w4T4dufbaHyؗWߤD/jMmlUf:"!aV2GMFIdRv4TF!jby\<Ǿs~3*\u8jyR gʓU{1oP <(_ (v"s@1 gCV4"jϜhK 5S)H)G)G)Vj_%6֤N66Q-.WIS@@4KܒGl&Xr{fKWsL&yhˍIts4 #̀h 2ύ$ $Ur|FE.Mmm >.` J"N?SHG 9qIU dT.xibV0dKIp-j bv6lRJC*d:=7 .(A'!O*us,RTa qY |BfHy@迓 ΀-I^~L@=`B@Ts|Ro 6G-Lj ˟R]tY3hS^`B>"3ϜhK 5}!ԛb)G)G)؝PS0PS0PS0PS0PS0PS0PS0PS0PS0PS0PS0PS0PS0PS0PS0PS0P3'jW$?XDbZkSX2c o}w<إ&rxc}Cn}Ѯ& [½9$2~]KzȸWdoY06 fAw<9d(+:hQB6B](o;=ʇ[׳$:SU5jQj<{Q hX z ׮5 ?F=Ug: &Moia?O%RMTQS 5})`BM8BM8BM8BM8R gM͗nz,>R iYiS_f8k/=/iHQ2yT!;*VԤQC&"Sl>X"ֽ>RuP>%&?/IjZslaºvlXPJ1msUDʧFR^4ԔBLKԔRtܩ|Ʃ%ҁ-+@R뺆O ĩO $d`m]ЍЌRd4[abψFR w]t=l-aF~RIˠ;"e!>˧DS;sFIE6- / R.NnZ&)(s*qbA^4LR@l,iOy Ƿ1lXXW埠4js. 7!=8C$u&&fbš7;si0&Oޱ "z8L=$sҧd AisA{NKp4J4 =Q^>B|~EM ! 6RȌZ4\QF!T 9OqM׳BN+DT'Oh7Xl_D}Dcnw]s/% j j j j ƱG%_<^Hc*?^) tqxL S^1L+l(X"vo!i~GɈ%]j"٨xNmҺGjʧI/hWԫyRj] Nҹ>ujKy|tӧdy4fLĪhJ `KĺKP,hQH$hA7B -pB6Y.3E,E ×4aRuN׳rҍPC*l([7CʂR"/, 5l+@mCvGi\ěc'i{Ƽc;3&_8@'V5P:lX ɣ"P;"y*L z woRl#%JTlU@yۈ[{@`T #rF8ƗӬKGԴ')~DCM_J%5j j j j ƱKR+{'̻ջ>OyDP9jѦ&Ky1m>‡=_ OyN'9w Rt|B6ծh<|Ѯ&rm`k͗Kq!GF`=#w}>5t$rT)wـ:CfA{μkYd`Б )⛐;EM !RLt95ҏ Kp!TG #’!WuE׳#:NfG![kÁ9!JY~%S3Txf~BQK' |BT1op6o}q:K?4+(x /J T<-\ߤ3HVM`'>^ a5#gqJ橽G73ϜhK 5}`qqqql&U``7"Fh^B@.EbW64Ywk ѝx]RFs4W]P%W*%F;!d%uB@L.P30G4r~cLe/x}jJ@L3Ī! Y8Xn fd3-j d#l zZRDU!bm@\#2]l˕V*@I3U/@l1}V5eiL -!*4XCBՠCK7 ]2K-YA)V{ }jJw= ԄicVC]G@GZ¢Z"DOaޢmjYe-r|DCM_J)F>&6ç5>&6ç5>&6/g[/.C%DψQ{g@c m;[,L|%JS5tؔTN%5 ~}*,G+aY,E-j b2XC]SJrq%5VႨI AKy ]ϦB;({u`$M dJ2.5jT;Gc6u9ǯ뾰MMgG$u!9@9B4NÿXkyD儠omd>5vdJ 5JK9k#t~o/SψZDZt=dy.I>~WcPuv)?Ϋ<`/m^v˜p#n|c9M=%~ qѹkuihC`#m!gydjijq=kSS΃̉PS0޿I````[΄ĺ4OtN /?&H)U=V9ҥ&Xsr(˖\`jWd2kL_#X֌ۡ=UX>!jbi{Nauρ7o ??,>!,^,uJ@B'"R˹{ѻ/cg = QK_뜮gj$5}^%*'Jm(i:wm$lG3 rDЖj'z D[_+#;iNSψH\tڠpb CْezMMr:3'jRBM0z&qqqql&iߛNh iɟȝjS(_Ck%DMfSzHrSZDZt=J%K]}X>6w6FMH月R4Wy2^ r\Qoܰj;һ/Ï4E z ?x'+|0d[Y|-l\w,?s/% oR)G)G)G)VjKGOe,cDZ3NVz mj|`xnA`Ԡe4(G ~DYD]ޞ4'Aܒxӕ!WuEV̚|8e{*0&CJGUa(ct*~%LbN6&Zڒ;5>La\`k3]&RIdpR]L\6Uth_L1wQNL\F5nYrS^x>%P |]Wz 1Q *jHeZ4Jv؄f~`߻Ycި?fef@qAxޠ'OI9mjYe-r|DCM_J)FBM@BM8BM8BM8R[RkMDk?8m@_Gd YZD@/"_iL&l&Xr9"[M:M KM$)YDj| =RǦPl-fch_>]MRJc*5# Ta+o 4\fdG~fSS2TCTc6)- JL>OTAv79b:ZAwVnQH(2c:)-, '3ȯCABKUupvGYJB=I:j0]&RIt )M7`ؠ*6d/4J~%xs 1m%68[Cjv⪎. zD:_He<{Q [b1k_ 'd dNuT#iȬo6#>!P.źFIjiHy JN*lZlP%^yh2#;"rIh3)*&u.S"EA)Ʃ%-C eIE&a:M#EM \DI=eV& B[ 4_EaVihwF`,{L׳THJ˓ͧƫ%g64;z;$q :1jB2ta5•24P!|!l+H# fҲjֲQ[O;l2? {ԄAjhV6bZH\;`:@6 8* MM{q:̉PӧЇߡ7PS0PS0PS0PS0d{wS5/qrVDž^/ݦ&WO4 F lxV~D5ZǍ %YQ@v]MRX +I6LęꓺvCy Ҭޅ>5vf3dĩY8ǺMc*?,9!t: UsA.Q!&"Y!W`^XPaz<<;#ww]t=J% jLHE bHI+\(5gXS{J߬@g$3[:^x>!S.V2-7V=xG`4BMή96>!Nr1vp7 z DI% n_zdè{Ζ\ѣmj 6 a"Zs|DRMӝ۽;iT?BM8BM8BM8BM8֫ɽ[^Kt4!xRU{65/i2>%C %vHͺsR܋J^ƧBDH%">dK쐚uܮ&N#Z#4"2&Oޱ ES@rȖX*󕬫踦OM JE 7v HA|A$ʣViGYVX߄'Zw!J̘'TƒK-`G_) 9dI WRwqM׳TbkƺjSސjv1#\" Cg,(juB-2!%|) Z \fp9[ymҏ6{Vbh ';d LVMMT0c.q2K?b6#,9KDᬺ5!Pې@R8?> oWDK8|Ț11]z +f7 hDe2Ng>VCY&\K.κx&-tMvʐ-kq2K?[TQ\4M!|\x.y⍚ nnEgT9Pӗj 5555JMa5Tdm ʖp4Cbc{4;".{ Ƽ;y3/jbA܀r8 I 7gx,E4[L( h0/@p {(. pQ9$78zjL)XN^ 5})`b 5 555JMP~xFG)xFr)/"o}ihxawE}+a<ջХ&dk5s*!׮Pl-'txz]MR9s ݁!gN۔2}KA'dc}M}j s1 L4PMZEMun ->9"͓|׻Т&)&XKĆ~Ya xѱT[x|Fn2~X UrœG̅P<\.ߊ\q#I|TNųe_L\zp;ZE 7bsxst]<ۻ}:1?W;|ZL̿FٿZOyL2e-q1O/u}Čb\nvOfse}_Y8Y( ~җ,Č .U-H9^dr)9q\lCSH>ftO1[y kyxs!e +jsD]Z̑XsE\~ 1c1 ӳt//+T:Q9 9TLnSQAo,,Ymtbn9}q^vn|?rxHpmbSaQ62}u6-棒_]钘sbnd1]s4: 6#C0sΝiN)Klk!wwC3-HcװGLs\{6l%ft&ُE=b~ReUI19\{F]m_3F5L0.'b6qJuR^3<۷" Ub1`e܈Lb(@(1C fbv!31;a@yQ6n:#ty'hw3[EÌbN+ק^O^٦} f^r;P!BלxEB̯bc|.!_=ViLKl` 1/^1?UE/Ajjםwc+z1#1e~BZw !̖sʿZļ{A9ȯ^H̘v<,&crWNecǥTUzj?ݔ(Ʊ21#."q,Uɷ?11;Eq)3V1ύ(@ fL̎23Db&f' l1Ĭe6"&M]i~J/9zb.3يzs,&-al\(栳YF̅Čijb. ,ƭ}jXb./炘_hn0l'f+X * bbVEzwQ6]* bFL$ȡE ,&f"k+E٢l13!31v_eČEb&f1CSTHAӷ>E)1,fQ62}i՟EͶ/c.Q61pMtYm[xm[Q61 b `=>fb&fbE-QqgY?\ ;Fw9~pKտ ѷ`(bbeɔ~":1ݙse։Mbip1=}{{;>.I˦}%M$p1JDώZ,-H}񬘯Kgz|jHh-g-!g*ndF_(3l\L̢l\1'~#Sty F_Q-cr(x^sy"fY `|ƘQ6s(탿`D \3`l30Д!LA !nwm .QGfleQ( .b&fbv°E ,103@ fbe;aKr4T~w11sa޳\ļ {d2Şcن&Z1W9D~kE l `$XWi[#31bt^N~Gb1b#1\.'K:F31ocnڛČEUQi4j[3snVCDḶ;|[s=tz61bҙtE~+٫?^p!Y"fKsU w[~ίg`1Luݸ ͝Qv;Q6Db.@Ge?8H;U(%{U<Fe31y1( f 1ĬeSZ~k)9O'J |9UV>.Eȋ9b\( b[WgネkEh^6ՂloS9wn bF^̉ꢝ?ZB*eTj6ۤV|q-H\d Q)13z--~+3vs b.^*s 1W]v31l1'Fe/oebvCÈܥ޾w({=.Ĕ66513N[nm1WK[̧`ibNXd\%O&1jL/"G]wi1U.4oH92b~#f4ºĬD٣[_1'ÊYEb((^3*;8*euc]]ng'l߯wv]qL kQ66j1 b~D̑(|U@̘[L ^K]4k([ļ5c.=ٚ}|1kO-j^VAUN1Oz F۔ CoUrX}):֩R=atsǥRS9\b oo0wr_Č6"b.bN$௴ ?\'zsxM sRoi1Gb>#_$lSrb^|Mqg`\79ӍHu[]Ĭ Fbz`h.{F$67*ENf.AbXĬeC f<1 (A1 fEČ= M^aߟI .|i/ڋ;L̈̂^.A\SUDW;l<)'fby&fb&Ŭ bSbbe#Y<{>fb1Q}Ļ[̃4Ţ쪘EL Y3L1(eg{\`3y FlKe1l4Sr;%Ae9e1>=u>}K fb&f%b.~1Kl`\1?ALb.dȑ;+\W;z>1EF}GOsQv??Y=O"b(qܫ驎b(]};zt_1xV@bV3@̃8bn]>!Ƶ+̍ E`>ꨱIHA1cV̉9}KL_.u 8%ܱoC#/57*)1w_ަdqBq^6b<8 K%5131-Ow֑sp V1,szIQ6syCSbQ̹6>fb&扣3|-&fbXo3(=o31b>^ b&fQ6<.E֏KM0"`q;lbFSrĬ'fbQ6@ fb&fb( f31 blb&f' 3Dbh bsʖd1C=Sqθ;P﬩ p>cĜ(݋61b~-s{\p:sq31)[l)0I9E_1?·3Y1 ԩe;~ 1b~r%GAtۂSj,|W>{G/G~k`@1Z1Rit@Q6c:>A>!sٔ-jݝ˫_=,-F0&fb޴<[9KU%}6a᧺/s{_s߮}bsy({1<ʲ=> OE}\Cb\yS1'Tn&t11(ļR>ꨱgJŜ<ǜ~"f:5}ǃ;7>#ýl9+ȧ[x`P5zE@^cgw`MINGʔLyQ60 #fbv@1C 3@섁b( f 1Ĭe 313 f(иڤ3o=Ensmb1w^X"*( PH ^bwg=fb&hmb1Ob^L̢l ү5B3o=_h=bzb&fbYb1&(ѳ#o1x9R_$#9Rޡ9R31WBT#eƒ\񪀘F[b&R b vc%q[n1>h0y=yTi1#s131,6%'1;a bԔ?Jb} gJFWN్F+JĜ{)׀K_؍xi0һq50bwE߫=%Ή9|1OeC cQbntso31j.Mիwӱ91ek19ם=}eyI9KYb>-sQvK#s#{gv1k1Kb͗}>f1Tp bVϋq)9_dzr~yo1w eL9Ku fsz<~E,({?~zABvV;Lolb1_$˟gcy>PGZ̉Li_b1 bg[31Gr3#%fb}}S<.eǥY CF|{=.El#cں2ȷMMX$ fz fz^ 3@ fA,wm鍘Qd!۶Il!@be;a<1YMZkLZ8V^p!ngOQ)G LLOZ] _{T4Q6W\gI쨎)xPЈ[s9IU+ ^CT]+hldW 寻1AcE_ uK~31k@2ebFg1wLr?CbKyՂ&Fǥ}-Cvީu U(ۍ#$ ʝnQ61%mû0AX,vAbe;a<1YM<1YM<1lD9*2>H'3F1tbǜ^LlՂF̨zsH1#X(hl,|@EVv`s,hČ5V5wZ-Ե8쎰b(>r9t﹮CDU1H^-VЈj:H9j_YyscF|Ae*1bVݥ7Ut}̍4bFg1wLr?+l1zMΏK31'[Hv_FY315QGI;4Q6 b1`e܈Lb(@(1C fbv!31;a@yQ6ڎ@˕YLs\3Օ]^T.e\>DٸPj \rc9f<+Bnuhcuvus'Uq[مLl<1y+g/Q6Rǜr\rcpDČKZ_F$lDe=b1`e( b1Y fQ61 fQ61 fqAXW\i\>51[]i \tVseB1_5x*rɍ)9%fb1c:rYE,]nHw1"f֡£KԡNΝ(W!fL | %7甘ČiUd=fbet>f#׻"YvZ >f\k/Qn:1;wl\5]xZL3*~F1e=.}+%7 LL̸\%`Dbf11OQ6#kL-f3V10 f3EN@=Obe3@=Obe3@=Ob(8ָ0u+6Q^Nû UAtP<bP^b5-[)(ȒtK-y*רK--TJ^bL1}'1cM1Vt*߶Syu[W-l[̑NB}t1W{%0e-~)Čb.YyX;~:tö˃Eآ|e+t}Z<ʎ'-f$+lz9}T1,2"fTO<5_.a&eY>n3+F fb3Db&fGl1 Q6 bVϋq?Di'kRگ4L-3hv,-U1c3,4 _faR1w_so쵴(#9ι":N"X-\iZg`X[b(5f\"!psd͉^X$%sece19ߋ]c>߾w/ b&fT)},垛bHR.taO_^`* fL4M9+w47ZWnuseP}K-\-,s^+7b޹^>)i(ļRcn#?#eC S{/+;sn!lbpɐ,9* AS"31l1 Q6 b(@1EٸĒC-Pl|9ZKObF^埇sn^xF %OQ6Zrǣ_^+hz-w1ܾ61\5:Btm7c&^=Slb&I$Nwb<sW\;$]ČJ;ob1]]MY_=XU[ b&fb&[fbsp(1qR(0b9}r;EĬ}VYTUI/1;ur(8q)3V10 f3EN@=Obe3@=Obe3@=ObƓQvur@{Y[>Kyնg|c2qcR1 pb))XAQՕUPZWsVsbO^J ʱnV>:.EVP̹z[AF̯"}<)$ZFijpIT[6&-\ؤV+17f/ȮFj|Cgc|sKy31?؀B̉{˿Rek1mm>ي 1G91Jܼssh/-fb>ޱLL̽mRwlL̢}̊nrcsɳ F 'n2Ӱ !gWK]CA3%'p?$P3V1oeLb(@(1C fbv!31;a@٣S$-nyڜ8-g=.M=j11KӽCA[g T\xnuuo0k(hG-FIپG3@Yy6-棗(5.N#fb9q}mbNg|"%scg<1o˭\q[8Sm+e,^>m>Bxk1A̮Inbr|A[dJp1s^'L(ůr|DbdnstoRОs.y6ShuG(;y\TnbN G�eQCR <1`eeYybQW7_2 @ f1e50#b`(]C~OIENDB`stella-5.1.1/docs/graphics/debugger_tiainfo.png000066400000000000000000000033041324334165500215430ustar00rootroot00000000000000PNG  IHDR<ke pHYs&:4vIDATxAn7Eu&qr 7{ Y&6@9|Æ-x!LXU,o53Mj Bh"]-BhB@Т.//E^8u(?GCۻW@K,--hڋWYMmXGqoZfw42MGt7vfNhwctB@ .ƷU + Zcn3 Zt}'hwR]ǺbWgJfyNfh[@kIC{.p(h]RЖ6™ֽ8峲vLL^A[B ]]Z״q&i<|πH%@ kr W2K>cJĺ,_ϨK>M>)1fU~״lcTokS@6Fb hh(@ @ @ ho\&{~pE U"6tY9Ƭ%u @ hn%@K1+ #th׻;?5Y1ni5+mjp'iLm~r5Inh5Y18YᘢsAh1&v1 vh tH cNnj"Z-qk&1+}V+'&֒Ӊ Q f[SVNg1&4+fzCyyӘs>=>­C=ε&,o*Dc@T1冁vihh 7--Z"fr"!Eh5-fQ=zZRŒ6 4ˆhsA[mǹXLq/~c;~tj&E=L̃-8C(-& rh[J&vSwIPm8rTh&.jh[hRA[Me]."߶3lMBu3;So+BCBXӖɠdfZfwMxqWMY<ZǙֽQMuJ\C 5c3 ݌kky5-d=AGxZz,/JA;t%U-D 3+'65ZncE@-B@ -"{rF !E(rS=Fh-aF@Y9B@kjMn?0խFUU?r2 xr؜}n: f委>Ŭ\m-lj3na f=>%[#FVE\m\,=i=>v4۫Y JO HuS"HhmZnZm r]!Z]eh#,ǀvMnOo0ic.=S:YpsEY{Юm|,s?Tuv-rƸY9B=F-B@ -"#!׿w7-Bϟ׿_r{[E(47/n0>}7ZXBIENDB`stella-5.1.1/docs/graphics/debugger_tiaoutcmenu.png000066400000000000000000000055311324334165500224530ustar00rootroot00000000000000PNG  IHDR@rsRGBgAMA aPLTE@0HH@@@hhhooo-2bnBTţ9\\eҤJɯ|JT@s pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^훉v6 Et_mWK )Yd2{,avr2[/i0Vw~80{Vw(0;ȇAÀCA(0 P` 2?,3;qVw;h;C N3h;CTi/#Π !Hwmu w`>ɣ@+0P` BA(0 P` BA(0 AVw&XU3νo2@gν%kqTaE%e.$$ƌ |j~u`ԥͦ.<]rYdA~Tn=%-E]ENj@%/+^I2|GϷ|Ni|LFkL%?C2([4䇬 ʖfcCA(0g\(0 D7ox͂(n<"BuCE,KsW6}K#KFԢ&س޲@'Dy[ɮ|`BE%Q.6- # 5Q QJ>'3[BU*SՔ-lj |@j1wO[ecKL =fKG˶gtry]mMFt>g "i*YIL)=\ΠFRyQGA`'Ny9  2<~Por\!yP`.yP`/yP` BA(0Y bnpAABA(0 P`@2npAA(0Y pp7Ӡ ++S|O/S? S` BA(0Y_K$AAnzCq?ڵB(0gW=an߉C*'!Jڹ @Bl„H-vn/S SVTB(e&˕Ϯ'reR29rۯR,D_R!O+\MTepr y"k k+ 7խ.|berr'BJB5ϧmK#W0 :b"^J>5ϗ&TJxWE)"F|auʴ+(,MZzųvn/Jy,JR!gP&Qc~^b!BBiS #(ךn">>!U\|<kH\,rx!j (u&: u22[ u22[i3 +L[I0&BI4`H<7A0QM(&Lt& ݄nDA7a0QM(&Lt | ADoy 0fye햎Y!PVNA>&uZSCp(,h~Vs>m߼ajDz YBla`N ,g͢N Ɯ vv:#4U)7sla",NaTZdӨ_N#E]ڔ Y7F #Rjs(HGq riEnao3 Ӳ+Iߋqle"S\ Z6ƴ@7R ,>1 g͎;Q*(WfZV Ec76k2/ r],(l*ߏner6k2R.铞û Y0e4%vڥjЇ.3$uBSysiJ,2Һw`!mAp"Xa؇05|{pbnDA7L|bLQ/&8g0L U&»[=uČ:V$@b 1H $tW=+pDk܂ĜB(_lqߋrߔ&q~ =*'6[ki7aB2w:LDQ&= aj&_0Q -YZXTAè{֘ǘ<(^ԩZt_x71q~ L~!&IE%ENhLub5Qn-pD b_bqVD2[3fT3q|0QͰǙń߽U&w]괾&Zk556g+&:K|LrDm06a0Q7=ΰUh"< H $@b =D ) XK{T3`?N&Z8(N-'O ]yvٌ^$Gn-ee3DjqfΡql᠇slPMƥT%Opk뼨H`D^1DH2HH>9++Ċ)a"p&L*[p_lngpfȭ:\i&/rdЕ@ʇnMdެ/k&8Nj pmTTZZxAch=qj!MY"a*hQ9ǘD)DĊ{[qqa:[n!&F2apÌyƹ}Wq|q&Z&LqzDk4>1΁Q/DU?+pDo06a0Q7=*awSHz[K{$~3~ց^MĹ,UKZN;uDIk9 <-rLS%L_M[bJ%:g*}p#c 1H $kiK;_R)(Yf"_|D^٣.4'T^q4Dbrt#u67%t'ɟ/WӖ֥`K/kwAq'S@0Tl)M4 ǘpى0-ǖX1w/UmO1QZDKD$.QiWЙLDi dp$3M a&Ia&jG_U7M@Q&Yap6:0rIz(LdҖ3L@ǺAL_(m=~؁@b 1H*Tq0΁Qu;zgjXሉk06a0Q7=*awSH@5%ǺL:-@o"U9(^ԩy]HFֹT4Y2xG- jub;Uu-DA1upl"w.z[5@["u2+&n(] u$_l)b;S%HI }MW-u&b() ITgꢡ3Ю; ;<@b 1^ۓbcP{M=53L0yKܪM+&n>D.e$3 &>i"^"Ss,NXǂ&?:GLHB͸l,tL?H`@ )w"MԎB8lg|%LŠ~ve"ߪg8̨}yD=ξKh ALVGr {M a:ĒjD'0H & ݄nDRk9n#L6n&zsB( DA7ag%ҢPj[#&*x@Z!ܡ0]B>̎M6eotKX+Lg >fr\z70Lz@Ma qgnXHbJX#&z=cDvK&J&]L6qD'L&ƽ(& 9A ]N@Z#@݄nDA7a0QM(&Lt& ݄nDA7?i">* Lq*p6mPy6%Mhcow3YB(Q6DW@Hmp`愷7 4nZ¼c3>H\-`ѩ.g35HWn:OiAvϧoM5FjA(y3 IJ &3Ljf kUMM4 #%xOξDXɧ ׊Sdc"BTGM0҄9r]pmÄ01Nsk5GCL[ ʗ&Kh]F"B8Dd\6S^k2_\L(DH BIr6ʹ&.n."rMS'6S^_^G(MDkP;R*,a!s"=>NbP\ whm35`hnjGJXV fi* LJxMM0Y?L(5XKhKZdN B(73Qqm)\ͯ(߂DH KfiTep(-i#rympVZ}R)Ai~ LDs샿3Q MTm3 &&q(,l6@Hmp%LD6pkY 9nv:~&z:86MnDA7a0 ߱ C_oY FO׿&Byv1a-FoN mѶÜ:a-m08Uz aB40xAh='>ԩi*&lx1)ޔL;(amw"n *sJeMMC.shB?=L$Di P$K%UA;V &:]9 7?L$(Pa6ytTqm1tgyFDHcCÍ  &J0T,A ȻpS kpPV&C\ё*eV>C7bΓ< &L+ ";YcTX`eW]!WTX)ߧw"aDd\l&oXEdWp6=2k70<8k0P7G@Y`n491D\5u&S(*nXHp&e?"zZj%A?mۚD޴TX2nLuVȭ6Si7Gɖ1u\8w"e[RtӸ6D :k<ֶ?bS}HnB6{"~Nt4*a m1z.D$Lt5xqFF*L4},.ӘLEZmpfP!S=&ʫx&OgoRi. aɇ$ɇҶ^r\sl"kGJXW)k2"S]75F#Q!qN0Нhf kRAQp=3QB MVI m6BP{a- 43MdNm35.ȗ"iLMdڑeV-^I>"E֕{|HRZN);Ompf' 9hڑBYY{|[B&JZ곖'r7$&TםJ օR0QZ曑#%,:hTep(-i8D| impW%LL_rb"󧳇I˘Zl:m)ܥm05QCYgfa@DhmMt.a"bL{\#NΡwxZ9:MCw)t;Ltpml(6݄nDA7acA~6>,|( bIO.&L >W݉t>a-6S\}3~^^'LŰ j[o!LfB4QL%/ujl|&ۯ2^LC7%Al(am&bV̜b>)N45o`Ρ:0MDm"A],B ݵrN0ѡȑt,ha"fD V A{uC;5*'EDnnH1Q(&hb!LHMDZX2nLuV-#a"ƙ< &L+ #rǨ:ˮ9q/B.S2Oc7"LĬ r `d')FY\MυL Lh+Z"L,\,^7mo"@ٚt)pc`7Md82cq=]-㌶mM"oZ*AY q 7FG:TVFF ģd˘NJq. ;- )i\AE`õ vbk[&:WMp?AIgLw*]En&Z%Lt5a-Fo葄o`r y#MtpϣY\.MnDA7a0QM(&Lt& ݄n.3~F tsx'6mP%;'svcFajaS&B =Y f";e =0QfO֫L0[0QY&BG–gb{$6Ó`Go剠 6~FB6[C)"14+ KSA2TgTi$k"-֘XBҙQ8080Z\&ɀ|I{L$5,lmEu?4I4\ \ԏ\f".,hbD0n o"brILIJb.e" g*vThp͊IOj}&[@|LC&rU#ڔaسl-E5*$:MhQ%e'XE 5][.m M$EqIL$Sjlo(GJ0% 2}B3LhDnˊ (n |#^X ޙ?DӥйI4!a*UfEaa_XQgi4NY.N*=P0c#;Ù$A-V̈ǝJ(,#a^|=yD{H2D|r1MbFꐾ1YQX@ M:3lY2k,NԳn™)^4ii'3DKc"))X6䢉&ؘiҀLE+lHFhxH H9IE$Z6!* U4if׬(N>ɇcRsvILV FK&J}\6D8Z4JGTԂRvf"h xŸKg"AQpd"C,WDΰ7͒ ͗P8 kj9| OO4Lbs2VgiDKJ Xp;Q'b;QPȊrѢO2vI6͘,Y)g-D.;k"B[",>diʹK Uf=Uvc녵)"['4QhPьI6C'4iR 8e.XȸWO/Tl`majre:){&EfUe9؂cWkz0$"T3焚\?Տ$JZkKiyڊ&e*VDU uS: s"[Ż}ZKO'a>n0smԏ<I +L彧}hoyƒ0k\*rmzMK̤s٪C\%mڸܙ|lUUC=&MY]XjQHjBDq<Ă& l  )GS|;LөrFvB$턔3Fk&BI )gn#LړR݆7}ÌwNRNH9cvS ?!N턔3Fk15Qvr埐rFvB$턔3Fk15dNRNH9cvrh6JM?!N턔3Fk&BI )gn#LړRF'i'1Z o:'\ )gtj'1Z0jONH9cva"Ԟrh6D=I;!mP{vBaќr48m Lt& ݄nDA7a&w)HArRH@ rD ?̈# 18a[͞$wkO;Ybs0X>cJC ǷoD # l@kaӵ8biv i6P k"Z 6QUud?)(5f˘iBD&"ʭ(=3DHغ.jD0Q+a"#LLw=6,/!LM}6-yۖ'LM(LM(LMDō6-nh#:kk&|Z&2D0Q+5~Rm }T aV>k"[ZB0a 1Y3&J\]B=#nɕHhaV>šm6D|N<"!p0Q+~eH6We&j'^X]`P/5.&LGMB0&j%LdZ{ KuSq x an޶ u& u& uS7~q x an&ڈZ=D0Q+a"#LGMd??.0Q+7".G0Q(>pZǙ!-r&j&ZQGaV~慵T#L(̄Z aVDF1Q*`J)pLZZ&2D0Q+3~ody an;7o!L۶|<^%cL0`awر㔏眇\7رŌ:O $(k{x<6O%N=@ ,W<aÀ0a@zà= aà= a^À0a@zà= a@0= zÀa= zÀ= a@z0= zX0A;0Azðra|tֹDa@0ao5z08>h= zAˣi⭇wN?gk5}F?U/rzx)na@0=/^e:^ p \Û[cY.5Fv]`wreyyຽ޳rtM[C=SR^W7w&fnwIYW f \,mFHnQn#;ށU/yUP\\[-zM#3À= Y'1;zàA?a@z8;Ǐ?[={a{Bf߿G:J{t= gF9}@aϚMmcCj(z8Y՝Yw꿩mcCaN5>oѼ-^Z35_`ﯽKg}6r u =L瞄sq)5ip?:C<ޫ= a@b׭3a~a?aÀfQx=z8uN?9o]pg ?|Wz85Іz8s]aa痢Us^tm~Z b8|pk10s߹ia᤻0a@(Vi|Mpfub>w<k2Lkݷ^ur>yX0SwsA0= zÀ0a@zà= apà= G=mL= aÀ0A/H0AzÀ= a@z0= zp?ga@zPn~ØdGzð=\=夦_ 5BT'rGsy2)DZc)Ow3<K.1cL=sUl!obǷ={>~="ypp1@ߞz|, r_:>0!ϧl{b׮[\{i1͝Kc]gb׼k:̍24|X `n35rǥ%rUk`$v&@ԗsc @RsǮ|t/pX9K0u 9kخR}s;'s "co?w>Jfl{m^k0oY_-KMK}Gǣ2hMB0c/OF+@FkhmuW6EcZ`Sž2۬c%^N'v}eclP?TB @ S`󝰻>3n?~DG+L .s@&׮i~vPz~.%BGY`q~-#@F,+cn#+t}UB@S:kڎ6(.P}oTw>#@tqOI@%9|]pTw.4o@ 1Y@`T6ffg@\?ݘŵE4 lL?L)veW@d=~@ @ @ @ @ @ @ @ @ @ L)bw:J 9@}@ %@`&+|1@  ͻ~'+@f凇iM` 6@@=@@{ (Ys  `{"_@ @ Û@ %9{~%i`Nb{@ @ @ @@ @ @ @@ @ Y@ a@%z " Cap~I'v~ %{Yp ogw+zzOp@`V@ @ @ ,5@B @ $@B/ @ ,87On:8W6+] ' ܏ ՝/܏ nwٖ>@ L/@@ o.a@@ aLGA@ n|Wp@`b+t/   <]f @ @ @ @ @ 01fn~vX@ @ u1fn~wX@ @ @ @1fn~wX@ r3P7;V @ @ @ @scDCSX@ @*WƘ0ڱ`˓Ƙf憩xSX8'c1fı`>tt<8@P+| gˍ @ @ .R y- s|ؘ@`j'O{|S @ @Wޥ @ x_@yz2s͵`ÏGVR@ P-;؊]=_ PD}[WڕRP@ڿ?@lsϽ{Eλlʒz% ]>sp"88@s{@A @ѭ󬡬@ vϖa+lM䩏 "8#v>co/x+ ,/w  ~GM4~|@B}b{RPz_;>>?o=}s  @ uCµ' @);6c1#@+@ @ @  @DIENDB`stella-5.1.1/docs/graphics/eventmapping.png000066400000000000000000000160211324334165500207430ustar00rootroot00000000000000PNG  IHDRvsRGBgAMA aPLTE@@@hhhb4aɯ|ϥ0S8 pHYsodtEXtSoftwarepaint.net 4.0.19ֲduIDATx^흋㶎E{;!IrYM {Ipb$,?8Hb? afK'y5ූ3~+8f7|ݷɋ񐙼O i'{_[z#frcLvٯzm&^C)}ۻ޹f]3[ D̝߰To#3\< ^.+|o]اܡkfR@_t[x WY dţ"i5=AV4Gk\ER).ZY ?4Sg"d;XDv Qͤj\ +-GcfIi:%F`l&)9 DVxim3a:Ukm#YXA|Ln&)9 7)/SY(JWHsշe M8V$3K+0{t̤DA|5j ~qVWـZh&7ÑIYp$ gPk36z''A+eo]@Wϳ@(qS 0,Ï3ˏ?s8! 6fZOBa [Hm+m X34OH3H3?a63Uf#`3q ]&f.DiB83;?x%L(%gzzif^(3N3'yϙ(3s_,6ttBm&m6>3S%J͢q{;fϯ@3*?`}fV0LfoESEI=.3Q2hJJ6eѤ*\t)=7o>3rL^*A&]26 SM%HOmb$hf=#LEl} I,º *AC YNWWb\ssbxYLZVPbY\Z:ʲ@+PVpT:3U5#!KOSRK8еt2,I}n\eA3J)&&fe ՠpA@=(e x5pUbVz,4@efr23ق?grmts&1f/Ͳ 'f(3s<3☙p;?jm.m?I3b^mnumm3;oP8U(ռjd7LCX#5{ªص We/xvR_̻lpK=EL3fW| We/xvR_̏+f6+]'͆[jJ5VX_.p#K7L?Z``5/Lj6M$[PO>W6fjoPi^f Z:4e\|3GYB-lA;fˆlEtR‚QtAK*cf~6 @+ 1PtR‚Z3e3]։6 +QyNI*"(@ ]@ ><_(3qnro} J<:*eI G W3j3ODž%>iOm炷-1?grm:kem6 m2kefngB䙹mӠ*35%O9ynx~vլt[ߛNJ\52L93sl%(̬Y(m9F->r>fbx&l6{'>$ǷY}bA0 ^3mf1Rł.i]43űE13wlO6 ;4FHI3’]f?&ͼQf6{Y0ӽּr/qzST]=;#L!6PǵrI)@S4S3m\@L4Pj{9H`x]tΜPfeJ9>E R*5m::fn5JDRI'4Д.5̤m l^QKZ8u.k`Vm"zeL{R9 "歐UhVm"Fg&A=j)}Q:SD׼r3ͪM3h+T Sa8EZ` 4("3<k( prG0|P"Y \<3-mˡgϸsIzf&'3ߙl2ߙl2ߙlgB䙹yf.33FK9e*ŮHL<3 f 5TMld䙉}!i(+4C+vJOheCRZb A0S,3S[$JJK#`@SPVQg6DNi]d)8U]j(*3$DIir3ͪ2;L*IX-G1CѬ(3 k$%V+`@S"Jg&=-^Z!ƀ#]S>(̬YeM3^3Ne3V339眙)g#x̙\<3"̅yfhz)l\@목yfB+MW-%jڬ&d䙩l_"N x}yfJ;+ 򐔖#m"T)Ug왩ݬ:-)-ZpAMiRcLfU{Ni]d)8U]j4;Ln봤j9ZEf\EivDTiIir3ͪ!>3fMRZb 4("{f) 5Adf-DivFq=FwQvAF/<|O93c'gB䙹yf.3ӽ)^jԩzvFCcN\G/)3hvjf`䙉}mUQV$hV.jF:vEYӌ#8geJ9>E R*5cLG +IW$IB #`@ST=30۹"*Pp zc{KUg&m`E+y+(fh5Ug&m"SD׼r3ͪM3[kl)a> HB W0E{fӒ_}"@TpC 8>Zb3ni^=3 }Ĭ6_,fN339ddd<3"̅3s!}׼ULFQ\q{ћ,3- \q3,-( .$9({LVu}g3ދ戦R|a<36_vepBc )[ +$4W=g&-<8ʃyfȓ*L`Wy$CL1  p _339gfr#dɹ䙹yf.D gB䙹yf.3}[pe V}*n99#Lm:J3g3S6L hVt+*`ܐ7(f) ]g69U‚)^ N>4sf@6U܂SRDVHhZ/93yh2D 4!<3 U] `fmH2[8TH {*<:;>cvk7fbf>kQff7(=);37em69T339(3s){g23 yfN(3s<3f^@4|i浌2os῕fn<3SGo䤙 f.D'ɿ%7C=MFf.DiB c/[~mb&~D/$mfq#ACf i-WfL$!YhMM+Tf7i&D3<̜.f=Y 9мLnc8$4@0 ̌Frk4f☙dT5@DfB^K3@'"3" &ײyf~B13@iB f.5f%hf24s!̅H3B,S2;b&=mv̅H3"\4s!̅fO c}7*39y2 ^|2CW1?'4s!̅H3b*38Z(f6HYn>&*c&vylQ<+Yݻ6L[4sH4sŗa&J^$8`if@ÖҺ2Dq35W)qR3$e-3^1R2Zkf]6*N+c&" S]Nf,Qiv˖:^oDPW1bTYP3 -03\oAT_8UrT)fTD3l'8`&-Q2s'c6d pFxi<̣f4C̅H3"\̤)Nz# YVWO c}7*D3I3"\4s!̅H3"\4s!Lg2?"]b`з0IENDB`stella-5.1.1/docs/graphics/eventmapping_combo.png000066400000000000000000000051371324334165500221300ustar00rootroot00000000000000PNG  IHDREjbKGD pHYs&:4tIME94~rtEXtCommentCreated with GIMPW IDATxmGabRQ.)@pҊ;p DaIٙυY|Mn;}xW%   an[~%m5~b jQ<~._èi?<(Ag~3>(bW?_޷}Z>O韕|)C{˯=(6_QJ[>W<<,F^ȟE^"&8((zXsytkB8:QŴ[~(|,('> q+z,(X|l7c3㘢(^.}.}yYp9sF4ڳ>G]WE@D@E@D@D@D@D@֋o{ޞɿ:%y~9>t)>䘢(DgQQtLQ](|/QџS\5{>_>zAQcGm)֎Yv娡gQE(G!-yW:1Ŗ(ּW/숇ϯbU4KqzN ~Φ;սpŚӣS$yfེ,ݸbc%gs#Mb(FS S+}bW9\޳Ͻg[XzG3}NEϐt6>|gQthEQQEQQEQQEQQ5?v1ϳN}=E>E72S\z38|磯'Dg2?/DQEDQQDAEE>g(}ϢD 8"(((hyu@` ikED1]{}ϩv{' >4#7Z>5vGW}[>GU )}q3}^v)}>me~^(((" ( }&ND`'ZQEEQEEQEEQEEKmߗ((g3>gsOX>54ϣ7Z>v#hSLcpLssKevGh ^e~(((" ""g `TQE`Yh'ZDQAEQAEQAEQA>6q xɉӈ! v>߼m3hl]gypgsHgpO1s(ᘢ爏a>}v2?EDDQQDAEEQ vE@D3}E'ZQEEQEEQEEQEE[/` sEŴQf#h>o>54#hSn9}>g)}}E`yYQ ^e~(" (((b>8E>gh'ZDQAEQAEQAEQA>w?a%'N{Q((b/ ~v>wGS }yL3}jy1E▻FcvCwxJg'o}/2?@EEQDQQEQQ3}0q  ("("("("("("Q/c.F\_\6u(`8W b˦6ſDbeTEQEQtEQEQt((DQEQ]FKD连o(|͢(?[5+]G}D1 wgJ>C׉bI"ﳣx>vt{.lQd((KEavM"޼|>| {FȌbvQzIőfZ?W=ňAN'Z"=[nѷӔQlx(z{R_(zbc)h{3ϣ/v)9QώbŜQy:Xyi3%[P'ogzvᩈϵS/2?Qt}q(((.(((_bm pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^휉8D{?b 6˲-Ӹ' Ŋ\I珪Jo1LTѯew@hJ HHp۹G4ndHMC7ϲysi%/7^iWxz%_Ml*8|eHs<7i>t2 I6)aL>Q6i=G[siYV@#MV4}ƮҊ ubHsVZ`"樚pEU*gӔ˶"o.Eva;<7YO fpxϡ 4ʛ8bK]MT|Ֆ'TAN-,i=E^FtN<*Ɣi}N{v:.OS/;1d!Mi4phFܑ(/L%4̣,:pQM ׈zBZL(QmnPb+hqs"i D% dE~JSi_+VGyFZv*͙4gҜ.iKދHnȹT_iފKV7oWo5=+RGbUK&h56OoC'3>8nl9xrZ þomᡌ[{kA=vi=]C,P-;,e1e0í49/IY͘7_Л{s}H=OP3QiiҼ=FYiNE9LD5OIXG\*@6kc~\inZȬ|ߐy^&}G^]1R@-GVEqG°lJz _w*GeihZLQdvZgZѵUVZҞyJ{-b(!#a۶b$. {miyVL$8Jlk5Lx Eg=aEޝBUX %^,7~ϢcNfZs˄NB4!вw'Vt&/yFք c Cޤ'1΀"0cʹ Zp !|Vi!^&j~(S7afH JaFx LF`bTFimBb0LV4I$ %f+b٪`G'ΆX4j QiҜG yINT'4gЛ{Js&*͙4i+h&*͙4gҜMSI6`:xTGL?Q0Vf|f;Ҥ {8c:!:<7'&3)MBw7bFo3M}¼cs+U ,3b%)wT0J\uHI]+iʩqd>[Ap,J,j7<8jJ6!gCD[79VsL%M޾1A -6ZNs h#'g*@fC[9*xh4lee`i^SI4GMQpxm3 8bK/T lDjbf%WgBVB:$gK4GglA0W}ߤFi@&/iztV͘4iU=1cGlZ00,ޙ&H[Ea!ôe!+]yI`BLzTNiE9#22RkT$Xq^,04[4}OaVGI*͙4gЛ{Js&*͙4gҜJs&*͙4gҜJs&*͙4gldҼ(̓?'JMv4A9L\&~~ ZΦ;=@?r y^fHLVGq1?7ʡgܿ:^&>q]TFq5HgqWrpiNf=ӎ$4#>6hY{[6ͭ,YŒŕ s`cqE7eH6y2V֨N ;zBli!GVվ'uiEaw!ϥoHaS`zG8aR04v'.4[t{HTh݉@˪;A|Ǽ> k9f#+2Woęx,FĶfIH\1:04m;׮'[֖`-.FpG;KӔO|-Dps_iZb^0=:M*,^ek՟͞i~fϋJs{GpzOrW/Fx=G4gҜJs&*͙43=G4/ r~zp=4gҜ9_ռ!EͬޞH>j#NiǷ{YH`8m3 콏4^J,[7Xqڀc"sTQCs isa>}tVis4ff{צ#6\Isv$gѓ}Js&*͙4gҜJ=KГ}J0O(~z09LT3qu቟>Ɂ4R>w#Ni5us(M iE6Zµi#kciqi7X4v/GB}[PF3 8m1^^}J,I3V Bwp.~4A!'FG,AUFK4ݶ/_n 8qBKk3*M 8 l`6ݮfjh4뼁D(p6Uji,4P?aeua Q 8&b1Gޑ0?7?ȁ4ϑحni*}=+}EHϢ'(LT3QiD9f{'(Ea֟PA`&*͙4g4jsi6rxq*?2KTv|qx)mݽ<Xl3>gצ>BN9|m4E: (M~,c3 **i$a`D+#{1:GKpTzQ^}ssnoTH$ ;8VLh &MM)NF,AUFK4.n£M2Tx13L0lWR -.xK4nZu4!:DömV[/Jsxm&vZP0!UK3f1I_6콏}6x̔{GjtT Ϧ0+ofnVi~3]@OI~+m,zRiD9LT3QiD9LT3QiD9LT3QiD9C?2jBioF4bNaO.&&q0MĀ}ƷZJX#:IϴznOsXG&|Ғ-L# 0y|TA(x5A 2x5xOq,vzWڒ-gwbYi VmjR@۩k>wZ]GΊ^Z[8gwbY#Th@3q&*>L}g?7ycyFɛ|:lFR/9 3wȈG[ 7K+xsE { G AZQث{Ol܆ oā-V*\!3P|ja3zRe4KY=`CHQ qtU[ ma&2AI4QhQi|0GLSZĐukEaVSQiD9LT3QiD9LT31}ɨU| }#?j4!᧗u?Pw&42DP_`ʋRi"L1 q&m|fE`1{XU4[+DC*b]1ga&zn&7!+#iXxKB =6 1R{A]CiRՓG׮'[ZMA!ofEPEϑ4ہv ,61p+Oԅ0^͸G` tJss};IΥ>!nD=ì4ϥyS*MJ_fzonOIokH3;{߂ 4/ҜJs&*͙4o4gҜ4.rX(4JSi>xn\iT@8x媖:ъ $%;zMV4H0xG0 F=:&oTl\Pm?HY!pDqTl \X)BOaSifx1dsP+\4ig wT €zO=:,\PkjuAU o5e a Wl||#9m*u*͙4gi>BN9_fb}FߓfqJs&*͙4gҜJs&f[oi/_MPiD9LT3QiD LgDv_'YW/i?u9/K9LT3]i?eaҤA2}G9Iۮ^I{_Kso<'ٝVo4H$MCqsX;jP~2ҴG׊ Nе"LS$pgaU8&>,Բ{7Bb?(8k<&caNpCV?&"kiq"A:x(M1\喸sш7Lg%t "Ƀi]ZD~4 :r8m‘4SNmLتM]0ONx^l%O† ^!ӼJ(}4ҜJs&*͙46z zII]z""ٶB/0 54ҜJs&*͙4gҜJs&*͙4O&{AOB$IENDB`stella-5.1.1/docs/graphics/eventmapping_remap.png000066400000000000000000000154011324334165500221300ustar00rootroot00000000000000PNG  IHDR-sRGBgAMA aPLTE@@@hhhb4aɯ|ϥ qt pHYsodtEXtSoftwarepaint.net 4.0.19ֲdeIDATx^흋6iKr^teK3 pZ3q'?IC`x~Lf ̜3S^wOp)xGqfR}9IzsW3߃=kfJq=a;f? Y#\E3%b$OmIshae׳؉z^e5^'Pbf4Y[f?6TXhw`&Urc3m쓮P_dʵ|)_ˆ]DkcsJAQZ5Sw!UITujL%/?Xack6`D]j4fqVFcfh촐y~娉e9f>GqxLIrfs9X%QúV)(C1P@H3SZRRi 3IH"3u[ \^TTUB3ͬ5Т9̔TZ=:fr#/_VLW9/. fr1`eV[ңHE϶2-x H(V2LeEM_UԔD^2:v,ۃ1I*X M13u2y Be!Bg[)_&'E̛fCaa;fϟ?oe&zDp 1fG%)`t̉3'"̜0s"#Q1?Ga)40s"̉h?S$g7-l?h.I6Y{i2[13|ނWc̊0 Z39̅۬c[ՠhB+6=|ȧ=3Q$ҶEZ3w%A:ҠK:S9ufkTtiХ5s6|ҶEL 3ì8$X5s6Hu۬J-P,3&el Σ5s̜3܄|f-EyL1.3?Ka>3d0[fnfD o)m0.f;oɽ~0s"Z3n-͌wx̝,I;tњ6,fؽυ.3?K6f&MB+)&3џ"dJ1A693UL6-Z3Vmb3٪/L VLP$*;s)Z'rl{eʿ> j238+S,8x[t^_{;/8+S\80[+s"3l.4Sq bKHEw4;v7f~m3Hq|E r7UŒܬY1޳cG) q+M?Dcىʍ= -{kf$iƢ=#9|MC;TA3+4QRDOqu0$Hf-AV(43m&l#6fR•hQ)safG}̬ZIq|̔w 3ĥf+@Q),K~@c C\JZi_?%!Կhfp&aDtLG~.tDQzf0t\g<73So}Hr&NA(Ebhֺ5&i9Ւ^ftXDK\ h֪3(75$b*o)rHeev=LHTL{ EjJEaT&F$Ap3LMPR\3j7S6F?!$Z5( *-۩)UcTzfow_5QLL4~mD38X'f~0s"̉3'"̜}fm`!{͔ofNA3S"[wۤb[l+û7cy -0gj>)I͢ǎ*VST^nl<Ԣl f7U)W<+beWÕhA%z[1C% jG65)qATl~¡*eR%_NE*=(͊"7m3ۤf ?P%S<92S>˴̽sgT^-8b&lD %)"8EJ}f3p-Lh啻3u\i&S |RߗN@Q4+3/AY7nͥ|rr|PEK$Ys]*iu(r&X5n>M̉虙\貉0tH38#,aDfND9aD̔s|De&Fy>i ƤcXpoq󉷉RkFkwfI# h= -ę#X>p[jmYtG͋$*Q̴ p^Jhgf9}e1 t(B12ךYt+bF`0 i>Ie=l v.g5S fVk tFapV7(Ҧjd"mJJ@W0G\I46yc7S^u0dJnʜLlu6slmv^f:La8{&'%a8hf bof~0s"̉L{yhj3mvgf$5SH<}k$hu@kuf7$=3ӑ ]61*bX}_[`t9 :&,t:U pg"zf~l{NQ}ĵT\k6ړv:kk" WL^1B2:W2 Ju۠deR*\3*ѹEI?(QE%J{9iQ(,GORhŪPYise.ߺ<~W|mfND9aDfNDLO_5QyM)ZL۪)M+WX'qFfڭ}|S :D%\miqNQ}ĵ<ך);i 䑸-pUAU)L{NQ}pUjB#*a&ffffElO-JTQg3sҢP"Y.-LWъUR#f6u}Z}.〙)/Y-̬SL@=^9f>0s"6,ܒܲ%+F-Lވ;rcn';|0[fNĕfӚ7\o7=N[5{t5S8@*eꖴrȟ@tBMt̤:v{X@&GoMwJo"sI>-N-uPKɹJXlR2Zr@k$/)SD [ZHU=Whq+==>R;#M0NQ}pUjBa̤v JVv*5^ -l*RSi8EI?(QEቅ4=Rrto$eVcqc0ǘ1>cz9"aDfND9aDqh*Sv۽ʞL9{kWNՙސ\m&*0mOmaԂQjL=n1s͢0bђRA[M֢E꙼BcJet.2R͢0bJWhLsͤFf-ج ZCe ̤o^ ԔHK|')UbU2o]bt?x+^>6̉3'"̜0s"̉3'J3xUz-,{<=5ך~4j-]):8C+ fRh_"N H(5/4w0? >|S :D%6;imaf%%$h!q->mҠ-&k" WL^T\~eCu'-جdeRAU)N976S4mafDHТD*+mp`f.@Md9ķ|2]E+VFJit4Lf\QvB|>0s"̉3'"̜0s"̉L~Z@bSVk#nglrȟfRh_N1R50=zk`&h+_ $t:Uk(qmONΕutU@PŒ60`ђPL ( #XIg m .2ݣ#\3RѷAW+L(ѷAW+Tӑ2p60`~"$hQJ#q3ٯTȁ;PE %ItXJ3_+!.53.5f$3fQU3e7')"xTJk:`3dJ>4ВQWRfmFZ0.ʾ7')"x _lUU`($ W&#)Ρ7#I9.ʾ7')"x ;=.3n?&dRDB`rhB-$n *Em c Hf~Y$-If'*"9%@Hh-K(DASYEΩbҥ`Ψb4Zf{;m6.aDfND913].fWfND9aDi FG͔_s&&6; aDfND9aDfϸ@`z/(̔7Aw#l+3g|afJ:a曄fND9CJٚO#>;NQ)GwK1N \2skO2v gtDih?`f~INWł#$#,NaL= X`HUzL3YY` ghd^0PEK%gYB>@qZ∙JUzx8.Kf~\UGdŪ,IfGP`fߒ "g&m/T-fgPQ-ضhdv)g˰\h4e|9fKЧ23,̦g 3R2a曄fND9##CL)'u2 _;|Dif04aDfND9aDfND6SϏdh0?}7M`IENDB`stella-5.1.1/docs/graphics/jr_pacman.png000066400000000000000000000053741324334165500202110ustar00rootroot00000000000000PNG  IHDR^/gAMA asRGB pHYs  ~tIME k ~IDATx=Iw!p eK8D@@ @օH!IΐE~[{ 5-m{zGxvg7[}X}P!  ݻ+Ա% kWv; /0Ia3%Vkkloe.ۿҲնѐP\h3fÔ Zx۷o߭?JcPܜT)#ҾF{:8r޼y۵|hOU7իWCLDfi0\6UD˗/H Чh)VՒAY{ً/?^ƀ(C`4$Cs| i"U 07GGGB@!V Cqv `bo"B,:rf钵%2umk!v(JS$k Mz߻=a!B!Np%CR/`5tS:-2J)Os0|#痦3t%boSB 1dH1P(-S]FC~ v{}J{ߪ?S  ~h`q  ˿"nMhP;#X nzV i #D_\#k7|U ]D4N `_0מ̥]S5*C40UD0h} y hD ѐ;k<,mmK1X#paik[@4 hDrlme 4P5@rh6${XkZ[qU hD `vf9Z46~5,^wYrd[@4 @05s7uAR5V hFKm)`w?׿.&ëhP87l RA4,TSCA@ ݡHCaq\ֆz?_4,RѰPvemȡEÂ:iXP5P :t)@4A`dѰC7v뷞_gc9FU5 hD0J4lfΦjt(0K#՟}$^DC!.Q_ض63 u* 6m  o\ t~lݏ\@j ]*YZGv^wLnE꾟:b"D;M}o |f}#F hڪi?~{s hD Lm& m:yW,} ,AmV8O~졝H@MN.d: }C{]cփh`fPlӅrIR)u*3ަO(=(&&\ӗ7MZT XCiW߿@4,~>}صpugv(tDop țv}uUZ 0ê!M G60"#j^l\5=}ɓ'?~Ç5B_BH/N]|9c!# i!CEɶ!#B.NKX& WBcanEm:_HbPPhFIx?6 гhHdSj}4Qdfb^ 8CiTP2kq5?7PPشc:tLP45  OK0+]LA}t:CY2d Vm 4:UӗCSq^Cxd}FChi M7uZ5lp2MpbNNSbÌM5~)~=kB@oR~:NS+}3sጥ\t(0aP}Sit`2&HKMR.MPuLRS\EKXQjî(}3/ 埩ϲD [)KIENDB`stella-5.1.1/docs/graphics/launcher.png000066400000000000000000000573651324334165500200670ustar00rootroot00000000000000PNG  IHDRsRGBgAMA aPLTEB1JJ@@@hhhkkk)1bkBRƥ94ZZc֥Jɯ|JRϥɮ] pHYsodtEXtSoftwarepaint.net 4.0.19ֲd[YIDATx^Jdv=cN|HIuXYgi?4[aiޞ֦zXCami>֦zX;q3ĻyOzX_ama-aiX!@+y]Wْ>Y9Vyp %A{Y%uatK>j-,.R2OV}@F"z.rURʰN\[rhݱS|Fςs$bVMs=o/ވ-a-a-a-a-?i>֦-ac`ÊEz~ Fy7saO Ŀam~duXl^4kacpe6aKϬK{Ş[S/f{X~Ԛw[~Fطݏ\[ac>?><)wo)<%RaYT6ظ0*Vߌc\0?x奈D|{&V|oN1[ꈴ䊰!f{(,s)e(Ȥ熿 ̪Nk/aP&(ʕہLkQS寅D703=Lz"x?IXFł2zR C.m2 J,K\!dn[fU;=:%xPM0輁$:|R"z); -g DAzXd\LPk \67 "endԈ0/\pm0u`1bκ}EcV'Kd4ZSNv |t=>Omnc9@6VN:7>Omnc9@6VN:7>Omnc9`q*x[Xcps<nPm6YzX?|ௌZ?Ty ,Notp+j7m(lrX_ 6VK+z,QXPBU}с%Eb+Fn|l`M)|z ~x[X9;+ZbR#A8#X$ X襢azD-P%*r W:u:c0@U 9JM"k`&C F K9bra9Z\'a彬YVc6V<xݵg3{ mlq/' c6V>gXC6VN:7>Omnc9@6VN:7>Omnc9@6Vx[Xam:u:;۝grR'N=vVv#/ܲNPkr΢\a:1X nlݙ_b޲x>\[ O :ybXq2wNr°f(!RD"UԗU>/Gotp+{QFH3L"`A8iJEaJPp!z7DnPJ3jX+ |1FTsm<0 _kV\h j( ŴLjd!VZTěRnr艐qaqUNw FKD~D‚C(XLŴLz1WlSmQƚ 㦵OOuR0w:xvS'rWp ,s) '\k&!^:{Vf/i> m3VY:@N) '\k3כ_/Á1XSJC%9͗k.x[X9;+ZbR#% W*cdM 8-"$TE_n`Jt3x[X=3 YP$&Vj2-I@\yN I,UHI8ы]{Y҇Cϓx>Ab uotp+CO'U탷u:/&Nr1|18ꦇYO D.x[X9 #|4bXuR0w:Jx[Xam5 6V>|ௌZ}߁/?_ `u:aJ{w$ gQZu~ .{Wa:1X[?P=d;4G!Кo!MxBf(X,cN.x[X9aXd~y (9;UsOCG} Ͼ mGa 3HKPZᤕWس#!XjUx!@KҌJ(lv[T8j4h0oxIe')1}NR(&|?YqJ%hŎ/ʕFJMN.@QMt1 B '*{J=k}otp+{`aDL䟴hPXP( "B!7`j0֔kn Rx%xdHط_~ >6Vvg'n7y ('aAq$|-N rSʋ)#6!Pe^!;Z.Ģqz m4 DDaA U!7I95Ѻ _ܙlaM ,L^8=Ua%9cqNrwV FpF(aB+LBH\0=pnĆ.w$PL+ĩ41eOǷqŰ>OmncZ(}Ρ߂ mt n} :Jks mt n} :Jks m19@'Nuotp+~ >ksYv3 =]>Omnce{X&G?n`) (}3,JKؼyhѺص\ b{ҋ]G6V(l=w{NÏ{lO x :yD9&i, q\{6;^J'Nr°Ncw@!ى_uͶsg¼6سbzX'Nw e4Sϔ+"-Ai Dk/ *< ָB(ͨa2|FHҬA-",mncaPLRX"DK\ҫ4 yJMN.@ղ(&ג٫+BBYs17 gW:u:c0Z"&"=0\=e¢Jo:y5;6a)2r.sΔ`V< xTI4DwXkE(Y[Ѻ \ZDgUɲ*]άZŃsa[!6VH+z,QXPBU= 8:]ӄMSsL _W!!wf-͹ej^$J>u:#Rx%V(,5Udi) (= 6Vxׇ9= m6a:IoWu:=x[X9 Omnc9@6V>|ௌZ?Tmm MF[% =ܾRP .%fYyyWR%?V2p+`}ڶ9=dǽ<  `Tsc f2/r°Ncw@!ى_դ^nce<i0)WDZ,^a!4AA,Ux!@qa}PQZ eHm3 J fE(W+£%h+W#\-eQM=cZzc0Z"&(=0\=e¢Jo:y5;6a=nZk|<: \rp+MeDC4IXP\qwVD%\kIE_K4{Vf/i֋mSVYz%](Rqu^= _ܙlaM)|o{ = .s#Rx%V(,5Udi)9= .s/-$enr1| ~en"p+} np1xc 0sOnc9@E6V1_+>R_7Y{XMF[% =[~^n.:I@ A86/C>p*z2X>듴8! k۹5˝ĸt-R3ĂQeޗ1 '= .sG6^]ۻܐ'a)"XE*[MKx*o 3Z@ 0sOnce<i0)WDZ,MP# 1E +DCnoܠR_3f԰VBR+Ź3x1Y@ 0sOncaPLRX"DK †i=)QbErCOشX; %`"?gCaA +z.R/ ĴLzWlSmQƚ 㦵ſ ` 0vS'rW%nglYF.5Lr S/_=`4]oOE6VJ+z,QXPBU=?FKkQ`bN$Zf7 ^6cԇJr>34m6VJ᱖XW?Fd!MN)ÎGEc@-CE6Vv iV1(y6Is(+EyN I,UHI8ы]{YGq10sOnce{Xqsض̫^r;"p+C\t~cE6V>gX{V߀֋mt n} Jks֋mt n} Jks֋m19b0sOnc9@E6V>|lZ+o릧x/34m6Vn2ڎ]\'&,p4-//sjClw=X>蹽] xK) ˪iygviT<} .34m6VXݐ9RD"= `w/)ᙋFE6V0X |&Rb^\E7lUD8X !(#Ғ+%jnxk> 2Xy`XQ?Iƴ̆ 29 CfͺBDd2d#Zigzc0ZLUm(^bFwܠ!VɁQ5 ّ@֚ޒ>_ncewV{p]i߅6ILlh]d-7 +kK$&hVVAE@\oOE6V+m_T'/JT.4G]%Ѻ6sIȕڪx``{h@I0u-_s ʵƴ, LHR3KcvY`;k$Qs4DSzc0@7D |Xl@ I0)1NlR/zH&!"YQ[TZF7=Ob0sԁnce{X߇Z띣9c_2?X}6VM+pm6aŜ pm|1y> Rs.s_2]nc<5pm6$lnc,x\qm6aQ`ncm`\fnR MF9l^ouvvesKؚԚ=ڳEya}\6p+`$3.6_띗F}seJk5y+nce0#wr Vaڮ:kB 8*JW^[Br}EՀK`RbN&SԻɥdP!iRˉ4cG !?/[kyco"p+CDZنgm4Án?֋mt n} Jks?46X9 1^p+=zX/t .z5__EXcQbMj3k4⃎>f?#*XVy'?yݷ]Yܽ5kڕ((rGl^hᇱfx] #c^nce?zeQ\ټZay_rgd)#֊l+.aQZt|1x5*`2Zڨ{l^iټof !%NbXo^S%\~1v eA,cœ\J1&R8k@) *<`N(0 Zju(H4p,'-AהᯮJ y *U5>mXwVŵ@ʌj+4I vT ԕJYq5Kn0]e- 5E-9 F%Ǒck$1bz"%>qXuߕ%~1X-%T.,8tp,%"xu~s!UGZr,ÁZ_Gy4KqWwop +~BYSC.Dc,QXMp1aU3ڤ$ԃb80TP+;jr-,{d4ú2qcp1)[UGS=jd`lYtVm0i:0_t&̅XKpQC+Bw|İ1?SoћcࢗX9iXݼo gX9 >6VzX2ͤmu no| !Wɇy#;ְeuw ncwQvrTB{JksJޮ^ nc{cWG`qc\[Wې+mldmvٴY.]i؋.Ԛ7,ln_#W~7>_0Օϕ-Zp+`}qh٬RO}{ƃRxJYl_0*V|o[e, uᵨx%5CGn]Xl^vWnyP "\ymKx7~ c(cv!K3ُ\w!=x Ux\M Z&ó,TiI%+ R0V%Kr-[őR KWڣILk߂/CcZz"9=X;sSN(%BWII=a&J)XY$TF#y5;65}"HJ֎{%57Oc6Vvg=Ț$PSl+cvu2]vy-7 65}VMIZ]*箷"p+`lʉTe쒰"TEb+umz0WF/[#h%(A1"p+*V e ՆGNlJtj_0 YJE(J菡"p+` ʅg(/X-y;Y_U`KE; Ġ--٠NnXͲwkcE6VMx>qڰu?֋ml߄}kcE6VzXf~/kܼNܼ} =w} =w~zߦ1NUўC`NP* Rcl^pj|Al!'&seɝã:K;\]+H|' v\dQr"i@X+`5ԗpś;;=qx訅Z!,^ IE0DP#4a]y\.H7-Qs;y`Xщ<*Sf pͪJk*I*s#0g}xB7)db`ҍkA3XSAHR9a蚄HTp}kMKdwYV +H$Z&x$Ě*u-oIE$r)7=w .O UkKu朝XSE,vM("9wrwVNDj 1L@"19\L=`XÚʩn- T7A 1xaFrg$=Z4!ɔ ߿&$*[͚YQ[TZF7}} aOZvOS/!18X"} ?3cPHz=w~c6ac4K|'=zXdNd|'=zXc?3k?s/u} aտvj\&&,,JdotNs*#DiI\]o6Wy ~ћIH^n o)<%,T 8d9gfh[ޘcpsۿtiW-pRD"߲=CdޛNc,:jaE,5o4@5!#Ғ+ŕ&Z) Az' +,:Q'P%x(\:B1ґ wD^sb͆w\'>;;qjdSȤ]SXl;UWI5fȚHDbTM(м1Nvg-Oe:PZś1AXe_tnf-7 :5gpKAE$ a|HRŹacpyTg,Cޔ'Vכ_95P&h@:7Ho{XI;9;Xzn*)9G >^Ávs/u=w} n[`R'\YWxr,[+E5T sӖV+D!]Bks:۝zO88(ѾV2r!W5->71m[]BMmJZYJaXop9Gj|?+jRzXl+\S %G҂5_h(q~ k%TZc0M9;"OYu^p@ںwre4؛`߮,(PZAzu=gcfgB%a8ۦI14yݳ`o ;QQ-_1lfL)U]VDe\'wIhԤ +Kh39Va=/9ְnsٓxcS1Zl l+V}I;]$K Zp%Y:dQZޟ?=w} ȞREr4w@\ O :IH%C/? VxCxhXӮbcGDb3eES_V[z'{Q "XuJu)T(PH__\ TX9"-R]Ƚ=,Yqnxk?idĖ^n{!ڳ{[y`XyDI> 'J ,kɘ:a7=~ TG(5RZ:kNYoD 'U> $.Cwٺ^>ܻw S*I^g#إG0"\MN1C$dGE$R={%5%[sH0)%Gq.DU-?2v%%U啁rnvgҳ9s*M.'?$ZED"\\ {)HD[=SIl`V v[AXo!~ VuK=1XH"TqCޔg#D뺈HI I@.h8$PD"I0u-?u6M3RE{pG.(՜`Z']XyU?2tSM!\N`drIxJ >Mgpkz"J^AS"ucKȎ^p߾$(7Ӵ}Q1؂#?'wf6YMbZM65ܱHDžf-y@L(4Ye>c~'(ԨU+uFci397`.ZMպlk?[ͅl yzo f1=wx1٦9@191XMN9ԛ~wD]\FzXVuX/L o191xL9' >9m/p4v<:ÊÔظccsV{?0rdv̞?c%Z^]C'7/c{XVwB ;i*q 3p4-[tT<|?ă:=˾rۘHf pcީĦE3]4$(Zp4-[lwbc:bBMhEEU7%<9,wUjWi;0g![K8r?ְS{Q$#OH.&QnA%`!CX#-au na,G"m$5{=PC0AOؾ1O,C VTUW֦Ԑ5H kMgjk}|W@gG"7 j4&hʻD㡭+:;"UIu K!Q*HN:v *SﬡpF79 ("%rCY“ AÊ;;v#z2'9֒ͩSR [#Q)y MMb,7ndww_=p̏V,`<1ilm*ef}$AB@ksYk|XjF\4q1(~ÊjUs6}dFy>7:@z =cps=zXc3/@u . tvDc^4&c?7:OGAf *͘U ?c Qx}b"iK45π#e=K3am9'p ^%9q1t=\^.=ŧp#8r]J:= ёU-ɢac>IqZ{f^SS׶<$&0tRi+n1<7?q>xE R9;Jmb(#"X˹Q_V{z'{QG >#:BYe")sk-Q=9N-SO.AdB  ֩rn(1`JU81, )]<2d'֩>,AbXVPj֚ޛ;>_0gAZSyj%FԔא2uq9QE$@S岙`qz{zXdOTY5X k^BOip9念IKPƢ"ͩY桒=*=WqP@VgSdtR5b: ʡ!)IU#CP =w{ GO ʝz$y yH8,6r$ -6QY˳J!}} a}+O3ڞ?^.zXd|:xk*7ĠWs~>;\z n>'k9@z'Wg;19@龜9@} >9k/۠Bd{X㿋sypȚM/ (Kp%Y:d劉Np\zãhMYNK*AG]+61ZVG& œX oٺN{7d< bdd.k/@"R[\EEh б&dsDZr ݴD Lo0#:BYe!;w vM91 TG(5RZ:kzac0BNi2aPWM^Nj&'՘!k#"R=5}#} YOd3f[%kP rSCy QN("ݕKacp(wu]D–֊wȎ-R7 w,qEKUEexӷ;k8𘯵|J>FlfA龜9@} n>>Iks;cps>Iks;cps>Iks;1h:ˇGclkt{lv<5 t0:;=ؕ;>vi6QDAt,%=bG.1NdX|q;E*blš`I} ]ac(3qTҕYP IE0ĊW "zD@Gc<2# hREqr52慩 K(,r@!A'艐]k1'"XQY,|GD*Ǿ?FdwV{:yXC,%Hb}k]I5}k=aoV8w=zXd(WD UTE69gg᫰ZF*冩;9wVNEq3\&s1w$^N($h҄*/JKY ݡHj@ʄwyJ6dY'ULG{ߦw=_MR1tz$>>Iks;|>} =wr1||'=zX羅|'=zX[^hWtw8Z翉>h`!XnY^ k$uQ@AvJ8uj*!/M'Z+̈́o[acpltGe.]˹yx)=(Zpdrk$iYve]e3*VnYwv::2VS$PsvWl7egZr: sSG77;޸ٰAG~nQTK=)"t1\hȭ1`IA(ך%إY/0U\:Zך} Gul'= @YMyYJ߰*ګzJMNtĴ=,%eZM4$S`"蘛z#HsdOU*Z).Z \K V6O2k"W#9\ b"N}27 y |'OqCadcu )F/:$˱ʾh]ӄM9^V _/;4ґf&|͞͞edacp(eȢXҷ"[/:$PKrQiB&l Lef[Z:Õ!kaQfYI#1N,?$Px-B8${2>!ED.B3"}IfsngzXd?S%[KW,:N%S"T@3["=mSޢ)(d2o8#A)T3ex1N1_Ɂq}E=w} ~CGAcnX{V_&cpc6a_E龜9@19@龜9@19@d{X?H[pʎ啹 pּM7{1XC_v]g' Fu=Du&u<,gzXd>FN'?Fwڳa?E龜9@-|'=zX羅|'=zX6hL꿛*1N5;c̛^I@ A޵(n֝,~;>w!;&YIH^V>k[NeT~j:|' FaKzwLٺwm5|#=ww e{ӟrf*f9n̾r ˑBE7Մo`/5 2CDe jnf|' @BX2ˡQ#’YN\i E+dr_?,,/p'(1! ~^$UzɫY*FX~*ȩZط1NvgG>fW% ݅W"Vk&׵aǀ(I܇rDB)7;=w 0x !Cw!UE&Uo #9<9owr,a,eM7*#Yӗ~[Q/kIX /Nv@g9Lܛ nbBLJb?!Jdٻ1N.7͂>Iks;ycp1NzXI1NzXI1NzXiK/{=:>Yc:3>I@ A86o^G:4ԇ#y xtW*$$ VYMB.L|?YUFl<9t$+^ܪHdQ8w;?#QW B*A/:57 ^6c _/;4ґ/Y+ɹ>ɯgu RM,-KNZ)@p4[D8f Ta9p{j錈d) u;=3@pGKCy^k^5#ER,UHI8ы]+Xr7 TzUZVZ|'xNZyϺN+u_IlşC龜.|H{Xcps} =w} =w} =wr1]UfAd{X?ls r鬱s}M#%r zXdKyfr Rn5|CK |+fG6w3*V|2;yrXAr6]kh9.#`n*: UNgDŽ MxJW( $N,Q45ۑeFVVMcV`i)xp!إIQ-̌Rn|-{si& SRk=@0 q$2BR-_|mv)hEGrbTp}kMo@dwV{b7OE龜6'u1NzXI1NzXI1NzXMz_\U׽>`is$ ]J]=?y\uDlqYfNޙNx w$/?^^elegTewr˰z#v aΖ Kl,^NCW;;2."HH8{j*"c "E˻RE D ^ͺyap#+&Rwa~`JU֥ e@#VE5Rlrò*YX_,D|-4?TM;=zށ2=w 3'(laUz,|#, aT-k["W#9\ b*Ǿ7kewV{b`nRX(k$;޴fs:c XKGr]X,JN٩Cg),5uDn|]FX~鷅яJ:(-`-J w=*=Wq)BVQiK-ɗ$1{!j錈d) u~/soz9`E#8ɱͩNR,UXɲ-F[0-,dզ3RTJJ!uX|-R:} \ج^MaGamP֋cps:} =wuXQgszuXQl _{VPj^A9NOM?Yy_zXCamÊ4+Y4ami>֦zXCV_siyV+PUj]~Ad4rJV2=\xt~e4Oú?Q\-w%h(vVw\&@5#LX׋v]MMxOV1%d}X$a)F 1iraL:X?4(~)o`|)9?\X_I]~19/?w..OVE\l__9姶),?a5}pwO>]Ϲc-lXǧ?aWpݯҹ0pհ. kܣB37ej̟ѼaWa.?ԈTQ<ˇ5 |&t&_ǕjHppU?$xSY7#QKUXt ?rX)7J&N.s#a*Ê?)i0da_qհGr導 \pFzGT^9m{c2l3|a_qٰa3j&^ƥ.\?Η?rz#=.?Wz#=no]l +|_>eXR!0|/r֦iޖ֦zXCami>֦dXoyo1i0{WPIENDB`stella-5.1.1/docs/graphics/launcher_filter.png000066400000000000000000000031741324334165500214210ustar00rootroot00000000000000PNG  IHDR2bKGD pHYs&:4tIME}:tEXtCommentCreated with GIMPWIDATxm:aa:@@hul6-C)>xEeٺ.-`O@PA@PQrc8 ʌ8 A9/{>X<b#(KAA,y yoA>{A ,y"=(Db!(X4ʣ=Aa怠Z~mP oҒ1g.ރ= {_ﳇU?&c)(;6 =AdH$(8"('CiK{(Rf JfAqP1)ʖ%z %sAq egy%uPvYZdy$JDX8FRe, A9D=_癶ʰz YPEPLϭ2-yEP n;Ai"|#AcA/2Vr:vDA"(+/FN%'&*蠔= t_FCPrHP%5Q:,ђv15ɜVl۠d~P4(2GPfN"ЋdI5vo_"( (bPAɃz/|1g AiK^"( 2OPAgar)cLAaAreϛTJGN{ASxlDPEPELEP%}b"(L񶓘ʰ^ۉm pHYsodtEXtSoftwarepaint.net 4.0.19ֲdwIDATx^휉:9s_,eV'& HmIk~ b$Y=`q,>xsL~G`WQpxig3-oX&o8'X'}p7 B4;_R莓: /hn;≈ٛ/ق|{n%@J )YB3pGJBRoof 9t/&%+j&(4[ՋvɚG{ZHki`,zAAi8? towKW^P|6.8*!9L LvOCQ`B Mࣷ^8bk.Ko|P͡Kd1Ʒ @@>&h෈3Tx3H8o3yorܞTqGpV!hwPߜ>-`VCxf|[췀 ǂgHJOwW]nx)o8uWos;epG*`s+Q WA`q,yg=kd(p7o 7ۆtE2y4 C[9&;W?>a w\hSNK1l8:N\}{RGثx'dTVm m|B:m#z~|z?Qз^ڽ'u4͟pp!ԥ?f9@NDPKփ&[ƋȂW-85*ɒQJudE "7j%Y07!K?`I`\zQ)QY,#4q yOUG(%Y^8IYG$.# WS ADq0,#0$/l3΅$AR*dJÍ;3¨'N8[:TTd'DJ7w@nm!Q+Y8Ц1'NÌ3X1PE y!sS{mf[^E հ[\1$UhXm[Khu\q6EQ R)'PdQC)A( _lEp+TlNt`-cCPGhsd-")I$aETKj5' @ϲ7aj> c0gH1OnWrX=S5<6SWy7w ~  {gX_ :c  wo;{J'[^ ďc./x;H8^:>ܝť`\N7nR-[^na.v 7׮D-h]2Ulcv̑lT6 @{ڋQqhG]I6 *dD62~AWB-YQsTYP5FE I3i/77pUF2X=`q~Amfc-ԂV~9ďq./s%x0v gׇl`x9>ahÆ͵+ѷ^ S wIo V~vCa;R '*Vm>%8ȴ5_Gv%v«[wBTZCXCD+`hDd=hkX,({ŚBX ,TQGV rVnPRr>Oߔ^h\Ax9Z !K@;-9U(,\Ӽ' ת#j A,/$%޸.W))IV\A]3C/őðp<:QJSNf|@(0|/0;+Z$9b@zlsSQ CQ*PX܂"J@m\9HA ,/"sʹ8lg$ܜÊ,UKfFܣ̥Tώ] %2^]ER]8Jx/ @Iڶ&f!.l,@RNԡȢ: D)yG(klN98]~Zepk3@:B@#kII" sd-*7X0(iZcN>X wYy6s 5@ =wp<=U}Ov\RԈ7^%\$#CTn@>\Tcm-MBԅr]YTGHCʼnbLu3TPq8MXnAu ̑$8je)[Yq%1~lO'?=_>^{ ?v6s 5@ =wp<=na.v 7׮D:[{5ʹm] {inJ"&6>t (юuzg䖙5B ,Q;e9@<NDPKփ&[ƋȂW-85*ɒQ =38Ëh[@nVL*h0i-3$NVzQ)QY,#4q yOUG(rd vyX`dSb Qz ADq0,#0$/l3΅$A,JEQ6MܚG%4$%pw5XScJz섈,B,k$©([sIG a1;) 7gbhC撙cGn  @m^8ʥD1 mk mb.+¦Ȣ: D*D {y@N^. \^r8ZL7Ї:ZDR要f͓ 1OWc9{dWƯ߉;9y x;8 4p5,8{gX=`q,8{gX=`q,8{gX=`q,N__>R|"?Z\Oˈuk},8j? z8o|F8+o։ÏQjΩhMyaԱ`vFWPpړ/ tȞ9&`1psBpљe5TR:FUaQyc|RscWz`IqesjJ`r 2ܺHъdW@PBYrZP(rnd&$Vcє=P[Cw;F(_NL؊"g _4 *Düpmm,8a sս@Lʾ |D,8{gX=`qx͚!,T3 IENDB`stella-5.1.1/docs/graphics/launcher_options_snapshots.png000066400000000000000000000111101324334165500237160ustar00rootroot00000000000000PNG  IHDRsRGBgAMA aPLTE@@@hhh4ɯ|>m pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^ {8G-Yc x `+4v;@秥7r* T3P)gR@>e%-R\!FL'cG)J9r* ͘ lHiw 5X^/|* KTS)g`%w6*kXNU$+8!T3Чwk\x]8񫸖!ee t*.a]{Q)gR@g)?a6Usyؗr|ΏowD>?e/\1Gvޮ'ELkUwbR)7R07ƔyMO;8d`s}L$zg[!e WZhK u^HY|QzJkYOyR ؐ2jo2nj؜2)ޕV[;[j.-)Z$|UCsDc kV&ynKFhW\SEn;C-} )#0u ZY!\R.ΧR)D|=rVR[.ڨa9V\As8!T3P)gR@J9:7eN :_-Jr* TȔ2 TyTCE8C!oF KYz/$fVR–Ǚ]81KXz8faa,H抐ꅖA)SKS9-k-{w/;gA"]&U'>t(ckL[xo(um厵ZkgEI/Ua% yƜծG YiXѷHӹ}˚FlX ,sg>eӓ/ fH3]pn['p,xE3^a]fvtX(| X-2(Rf3ֲhFng)Ch,B>cn/| XɰL3`2fLxOy03L0y%BLY$0gYX1WR1g52uGߵS&ء"鋅 EMoâ͕8=d3úK8uNKdqHOq[M0Klt!}HZ'S)OTʗ!)J9r* |?ÇJ9)u[[2Οϫ)D+wOoI^p "ۮt>aN|spu>C3ЩbJy0L)tyʯ.?<]GwKaP2't0 SG>>aOpʋِi^X8GLzja Z"Ts{T7TcM)OXp+Ĺ2|i w{ #ݐ:q :ކE[uF[jPjZw,^ %/~^ 9T;8T;8\R&u9w?nк}J9r* T3P)gR@J9r纴?!8-_ɗ3W|2!VS&8,ڠ,@a&cHhR޿Vk7+cO 6l*QV[*v atƍ9V c&MlAGXHh[ 'xv)VSƑac3; ",BĔ2ԖZMY}oMŠݔJS:dEC["U34Moâ͕V1||[CNRRnm>Om)HJ9r* T3P)g`O?0`Gȗ9(>])?W|271kG 92 gewuyxLmv?xoᴔME‚ ^աMڇ0Ա':E ~^l݉S6a9Z6k7pBo=c+h#: SCL-zsڣh= hƽ"eFmmDa Dgo&xEo/MA^/TB/ >N67,^'}?lw =BqoGSnG"ĦmaM-l"9]q䎍9['e'\ b";;RnϥRIsk7©3P)gR@J9rw1`Gȗo~-{~#eWQE#Lo1r]Ña~ݿ)_y,әݿw " gq8/e:_'80gMa, 2hvN2mz`dg+9}KPRUۻ ,^v+Hy"sQMh[KS)J~IJV9eF A w<[ˠ ͗_217eٱ%6ދ-0*%Q߅S]"3 ]]XqnNj.WXoєJGDwbrd|1M/F#U:,obOxcaIq1:o ̎۬YJ9r* T3P)gR@J9r* T3P)gR@J9r* T3P)gR@J9r* T3P)gR@2 |G8]h^=#)sRg:2שR@J9_2;`avR3e1 ǫR>V^k -z[cHxOܔحZ5&*e9Zm혘>凣3q|G$T~\Lg<:.ilODw=*e? d zBZZyr9kIQP';Wug32HW5,%\4J]&:-eð"#1Jd:>eUؐ2\١BhbyR3e!e⃰wv)M1嗩R@J9ߐ2gQWKܝS"[u{ѧ\ܓJ9r* T3P)gRC7OK7?ՙwIENDB`stella-5.1.1/docs/graphics/launcher_override.png000066400000000000000000000153131324334165500217510ustar00rootroot00000000000000PNG  IHDRUbKGD pHYs&:4tIMEW%tEXtCommentCreated with GIMPW3IDATxu-!Ť"\Rr+ 5>όTH.uSc h@eb(r63AQ=lwH}y5G 6\tRfϑ^DdIplѡhoceH|ڦ+H\c+HʕcYNUmdqdSqۖF4f-_wtE΄Md9 6FYmEu}`Lh&^q3؎nkl+=gΊvHPd ١әT̐U"E=VzeVgo{vγ"F(Юl xm K P$`( xkk^;&L"U?߂  6l6`$c{,6l 6 ``l _ۖ_|uTMzd9g:w -ӸW-'64ؾ/ruEyʔ3l=8̬/-ˬ l0xRL`+h"#yHu UfH`GNֵ:"C#An9#Ai}ʻz(T! a\c[lC!U=g[6FzTUc Fza[dW DuOsز#f{FW 6`A o Lh #걁`+^'LɣU{cs vkl3 jt;_c;ZNU $"lf̊jPGbf{Vlґkܠ9+22324zM 'Z M 6l 6'l  cR` F=l`VY @ 6l 6 M`:|eeU|fw%Fkyt߱&ؠ8"`^W[#eyrP]+_[yhTz3lYhh;C4`[i`˄e 6[2F}>2924{e"S=쑺LE,GrFޕeP`C- =9ʞ0lVl UUu>`C-)`;>9+22324zM v=Sź=R˓G@u 6~rōܧ&\>@ 6l66lZ/6l ظ56Ɔ`"͊M`&@!l l o"zr{¸W,v7XwcMAq-fuq`yYU{3 7L<)~[`Cg)LÞ ȐHм[H~Z߻!P`{@( UUu>`C](" ?v`]-\c`9Еf8638:DfǸ~m&D*=챹Ɔ`I5NvvUO 1`k ZlfEY3ol9GjymM 6ܪ62&@`l @ 6l쇯Z/6l @ @` oЦlpbyGj`C!@!6l 6)-U- s_9@vV`+jW6Ļ4?þ2l? v 6[Q`>-خboldm؏>DYUHݺF]gG>w4jzhC{p{[w40Sn&~ >2yHEWnR!؊*-ӓ\Ul>llÈzӂ-2S1]N;E?YWN ui庪ʪ`U>s\Uu:s|uϮx[řut {FwmL=Ih.r]3Z6k$#{g2}M9#I֙9`uFUd<1fO*z)g6>[bN6: [u\1V9ܴjr`ש`l;]md&<<ֵ=9تnSSfj<*r rߨq٬t&|5&L 5;+23YU~U3FqF]N"gϳZY՗f3fEvt =y`EO  lg"@ @`ggWp0JSvUM<زXvyްm>( *e 6{6:!ت[c{9r#á3oei/px93FĮj,Ϟv_G?Ю]phOpG9po$\ן-O̜WOg[U>ko>G-6u-b'6WN90*X~ꌳ-S>3 hlfP=>"n(=l<3gl[&Nup[EÒ lgtU]>Qw]  [P^w0u=fʿ:ffΈGއUѫuE?;E>"["ЙjӽL 3U?;yhV >|2y$s|g^HblSݞkl-\;+M__J7`{p,wu~ȶs` o-kd;nwQ}ES?آ\t;U3zlMg'T}lhe=`~o62|83\]`l>ԯ-L2ӫlMg'T؄`iԯwUOݮ+6|W*Gl7z~կrD`` 6x}(;m=Q`DW`~CMÇ MiԯCMÇ 6 `S ؞ `Gm_ 6l6` mwmRע~GhQI5 &*ֻy/ ضo"_@ݪC D'/ ʮ6?Omk03_@]3\~v3z/ U 6 Ys| S_@K*:~G{Tc  6l l @`` 66l l ǟ~t]d OUy<<قyO940v6<.؎zTMê`l[[wQjGTG?zMϬ]v|h\~}WnwFh#?#w'T!5h3YՁ-\oG٠; 3#hߙm>mf`;˝m#g#XVNu7+bW\LxOLP~\9*.=vHw0V6ܳg]=Lp|Bil#=cdՈ`Q6uFVPiGß gT[}fP|$xl_ssd(m##˨\Q~>ZGo䑙,P+` W|U_2Mf2Sl ̻fe`Fwyul׺Tgv(2+mk5v=K豭|Q+-<3#zK+c~-F;N~Pve0ʟHt# I,z6l @`@` &l @`@ 66l l @`` 66l @ @`  , geckݱliM 1BǪ9]`3cǪ>]l `l*K!l `l61F 66 |l`iv?wIџlC;v`8`ʊ{;mo"ϻlkv h*[6Yl##N !H~Z_հ`vo'g8Yl]u`WiWoUs͌d5`;2{|͞ l"K6fyR͖G%N9s 6Cc2{l=fK>ǖRc`r`u?~5l\ۙvkl]ckAsVHKmV$w p]dU=h11>b<ƌx#31]8j1}_;1 WA$fn1@0:r f1z*t}FfL )fFvf!]n5g6F+Ȝٕ#b6j=zbf݇Bנ=.f#̚+f1{Әx}_k7[^̜f}ZF, f~4aj-SF02ud3nnĬ@Ԙ!fb$ׯ,bV fb1+fИS쾍GO'b1{RD|y;d,.Բ>=֮:@̊Yo7_.A4Ë:@-Bn2ydy"xgnYުSZs5sDz{+6{9ٌms#@;g6k(r#ְMVl؏r}e=)3fW&s+Gf^ubvA`Ufv6[GFG3c obvb@O͈Ӡbvr}lԇ1;4@nʼnS#}a1[5B˽2fWM3y#'Vf z3ch2W̹3c6~Ys#YϟP.qⵓ^ f_`$ZFOMt58ݜy5&4@0#3&6_hjD{. f`{bVE@ "1 w@̊YĬ@̊YĬ@nɗr)1@l#?Ǚqjӫx'DF3'9V:=4f34UX,^u?UU}fvGbv4sd,:ӳ}(}j ܕY( fd9utb"[Md1=夘PWl0g<{UZwQu9=g1[.9U_X>, f!ӈOvЍʘ9C窑޳Yy f1+fٖ-#32c]+撎Ab͘+k̶.[ƾ1[qJ^me̺4]D4cTeϙ+/Uy:>{~9_̺"_$}u˺|WF$d^<>j#ҳ3ܩэFqz> 9,ct ]qb?l1+fbĬH f@ f,bV fb1+f fb1+f fb1 b1+fb1 b1+fvb1+fb1 b7CMcMWwyw*"{X^} 1{)}HzA#kyV|(ĬpbV~;"{Q,f, fbe*BmzNDzEs<λE>'l(oɚfP> f'sfgBdNcitHl4F̮9@bv/eL3Xy5S=\6lbW3ٌs:^ssL< Ӂb 1 Ũ,$<Mgb1+fY1 Yp<Sy-ORzk}qkF66ȧ`}&1;#o:-ow ՝+s_<-f_m|H[:YYC1;M r7zξxr̶b1fw{ Y1 ӎZ"4w?y56-6W==3=_a'c:ن3O\^@̆W#5A9}y#<n̸]QHuZ}rw\ޑ% f#Ɏ8\q^WցԷsĘ˺?K fٝGfwO#O=ew}+Uڳbce(kyfh=f__rVbKs[13 5z9SV|Ӫ L`m'7s$4㛹(>flUI}Vo: Ȳ͸2Iϓ׽b fo 1 x fg(~S,YĬ@̊Y,bV f,s9)z6Y6ǁo{ԻFf/A6 {8{2=ջ-9]ތճ29@ϱyFt>{o޳oz0s=v#v\}.fA̦hBt挃d}9#43'Ι퉈g媑HoYgO:m{ b6MБoV̎L3ȸC73'sX淭OA‘U#[(}mNuzyºW_yfJ딧>1+f,x"f1),Ox>bV f,b1+fb1 b1+fb1 Y1 1 Y1 @̊YĬ@@̊YĬ@ f,bV f̘+۳h_SzcV=k}Fj fK~ wq{u9׺,Yw#}TmuzNce% {7'kFobcԵ~2Y F1rl˺Ι9)ӯfXƭ+*c5[FDY?g[tݶGEFeĬ@̊Y,YĬ@!Y1'M]/v_~11*09Qk[BIbvv^MEwNMLk|i=˻b_Yl6]c}xUW3#%= `[p#+Nկ܆bFf+#'|rf 1 b zrT'焑٬yоbsf:9,] z?NJPf|SԫdS?bٲ b1+f1b62b1k fb1+f f9[[Of, @|w_úKȾ[b6!zv5(1Og}>^ fB(UfMW9ۻ<- wz_WM̎͊|W;W5M˶_;Cbvve-Ov8Ezez]y̌ٙs>Du:b@.]O{/͌*wZ/l՜~S#2Ґu=+^ ffP1'j#527jY? e#Y?g @̊YĬ@@̊YĬ@ f,bvßmZ?7002=1 fO3ΧG1 fl cf-sm,fٖZywSlٔӻUW*}5ȶ"]F}fY?g[O+1+fFug$ Y@6* f@p!fXgp1 YĬ@̊Y,YĬ@̊Y,bV f,b,bV f,b1+fb1 b1+fb1 >mnrǚq.k~)x`FE-N1-Y1{Q֥r ZG궽y-wۦe}ZwEbTbTro0U&srֺghGgdۉYਘmKUȭiP}'l 1 ]=:+cgZCuΜfGsf3$͘3KcdXպs3!f@.3{WjŬ_˃֨,@̊YĬ@@̊YĬ@̾ ջ^uOfTmOgmp_vyre_ f7_1)1kcor#1~]̟1kV>GHaf]5V 9f3BHif.u En0UhЯu83gi:^F>3f{"Ӻ=z1# yh>]9,DyV>ǢgWi`YPٲ9=qp˘}f:0zoDs z>d~hxOdg7u8puf*b6gMp$PzF"Vl˔W([͜S\Yv9~hahY˳9fA&gΘf]7x>g|h9=u=2iY1v5gdhCY#k3cvV̞G̮~+T<=fpy}a1pH3ZUf}Ɍ٬Qm4C̫s̞3!͝.œYl\G 0Wh¬\zdv\yR㊫d߭WN7G.k4szK f #/b@̊Y,bV f,b,bV f,b1+fb1 b1+fb1 Y1 1 Y1 @̊YĬ@@΍ُiLܾo@̖w![!f+Ebv 'f, fciޯnSW1<{.-xN9߅_o̾ iYrߑencYQW3 Ɏ/sb}7a֘z,1{٪ʑٞexZ,: w Usf1ZhidL3ȸb f@ f,b@ f,bV f@ f7֟m?ú}ѲWٌK~mw6}Ѳ߳-?@}р5=^mx\-w֩bV["f1?̞s1F.?rHPAY?g 1 Y1 @̊YĬ@@>=ѓg[nMv1{{jȾE,_e{nE~7zv-{Y3j=1T#=z-{JfD< ff33cjF曞4o8kj f٫qQ]ӯ0wy@6.z>;z;]ANSg͙:j~B죧d~qzns ZF_1lb1)pO21 b1+fb1 Y1 ӧ#O#z|=@̖  f,ᐽnw~ҘnTU$]4Z"kd#!imbsf[N3FHDn3v<֖&f@;͠'C6='N3 flُuǘmb} Ffgf=ۦbm3;s>.sf#ўqY1{|f]튫~nnZ~Y̏&}ٞ7" bHtjbO! 5,[lϿY1 @̊YN?@̊Y*\@̊Y*.d,bVP_տY1 @v^1 YʘG5cv!f f@ f@~|͟?b1k'{m'1&1Gb~0_eZޏ _,c}P/sCg,0.j~ !fFYQk[b`oFvVΌScv4ʘ9.f,['?:r~zߑ8X-'Z?f;z`]lj]$flT۴Ne=cfXKN{:=|d3f=sfwibvߘ<I7&2opmm5fFfŬ]=SEFfDeuffޞ029;l3fޚ3 Ιe';fsff fd}}f=j_m"ȕi7ܪTg\adz1`䱞>gM 1 f+GR03f?f8,l>@̊Y?g <>fb wfYĬ1bObב/ Y f f@ f@1 1 b1 b,Y,u}mbpڰ dtm87f~\ƬmC bFF fŬ1 f5 fĬuovҲ?zb@V=ݮ1Z$- rcv:oH}W٬]q'11u sJC˿zW=Exd{_=Nt,1*c6r,~Z:$*3:=Ɍ٫Os˓oYY,͊ٓu7hU`GȈH>J菵X(Gދq RF=0H졻sʏޛ7' F4'09Uw=0H3\C|!@4'0iN`Ҝ93g?N4|Ĝ k0e|at݊'<0P= _qC6Kxb̛cYs8"҈ڥ"Q+!)U(ssI6i;Ō9I+U ݭV+5 &_w, sto{$2n za5z+ފ)>t縌2lmSPГ".f9`2QQj sw}C5 nl̕!,r`[ӊi>d*1ኼmFcͱ7}wQǵmtq'攀lJ[ÆL"<"ɘ(AcS>{?5B\m%X&&-4'0)iN`Ҝ9ދ. W Л" L4'09Uw=0H3(f>J?B#& L4'0iN`&/'~;9nyddUk㝡DD sFkkݭxs.HpܧPWva|/>'}sJ#+T!n7*R2,0SJs]b^w6wxfN̽^%)3jNn &4vjԁ!%z"Њi9Z n(I]WAD d/A1Wvμ96Vhum0qeXGEL/~/cs!&;U' 7ƒ[FL<"ɘ(AcS'B[„:2SwN9oż9HsܜXC4'0iN`~9bBA4w=$Hs& Lk~` R{;i>J9Is& Le6/:/4ghJssCubsָ^m| .9G\9v#!)U(s`nny(#V]>i-j\On2gN[[DQ`BM>jAɽ^X:pIs_bCw9SYkz =)⢛2-IQ zR;G0 nl̕`9(5-cU4Ń<6fܧ`VXC6# stѸ Qd<7LƳI7eLX QdL wNJ[P݊{|ɜ sÜQiͭvSnfevK =v#!)U(LJͩs[ŌcshC.c[t=5Ԛ^ؤzLJaˮf` i2Mr^X:pg,e2m =jM/'E\ǧͱɱZͬ9[ Id/A1W;GՌc l{z%p k(f|sNARh4SQWjD$c9<5ۋҰ4uK纞# yN4'06c9IssdN좐e A`9I(Ҝ9IsӚ_~';:s0Not#4iN`Ҝ9Is9'_LYس?a,ٺnZzK#ڻ!>`~Nl{<1l5ej<{u9iN.F:p'ͱX -c9EaL(1ڌ(q$YoNYA].% hݰA55!sp|YjFh\ɇ̩cl%ؼ/ր| +99ƺ\ƋAc9WĜfu@ՄbwA$,| MCSEXZcB=>XF>iR6Uyf t_`94'0_3Is& ̏7^ vQȿ2 Nޜ$iN`Ҝ9iRA`9|'G7sQ:4'0iN`Ҝ9Issiq7 uS&yɀ9#,moO݊q8\;!s60k,7ʇ1Aɞ, tE#JZ'!)U(ӳ$!c~QM(aqsNFn-kB Z =K̑ U ܧzb Mbl mM-;sHB[NwaV3GC ᰡEqQZs.} "n9/ԆB+)N쳵u_Hтl~CS3#ERv=EB$E[aL E"pWN|v,^{쵉 RĒg-N E"@ EA! !@7ЙrHy[U}nѻ?/M6{ Ţ[1{ThR$ER\*L3w]v޾>ۭ;Cu$u4%Ѯk>+ 9Z2P"&ŊhIL踞|0|/g^pԹ+RZ{h87WZY8:")fGuWܒj6)$D={g&uwZOqF+bUª;}nKrV2}^dHstY5k;Ѵ:Ŋ+.^uYLڽc~ E,+ŊX !@تS?H")"@H@Hr$L@@@@@@@@@8)@Hä`#ɳx)"(o?U5p2PR$@XARe M~E¯֌eH m2#-pl lZ\"&).l/p1 E,$ţ_+yIA}&X9AHW)")bf+CfIR\53@z E E E E E E E E E E E E E E ERRRR*P=Z;HAцV)ٌ.ƫ';ߟџu{[U,E-M)MDؒ?hߓ9zX~w}%~#'Z?GحaR<)fy7-rAH1"~tj)f JW୤fHbx|~h)l-826{bg uDKitK)~&Eg=;H1$7?竤h,[L}e{S<3AfGKzWN\SSZsR\iY@1ϑpgA;-ޮ OU>Sy̏eDH )H")uI H3K?a<.f2joS])N,!Ζ_QQ"EK@@@@@@P/E;||tw^lhCIENDB`stella-5.1.1/docs/graphics/options_developer.png000066400000000000000000000147171324334165500220200ustar00rootroot00000000000000PNG  IHDRvc頀sRGBgAMA aPLTE@@@hhh4ɯ|>m pHYsodtEXtSoftwarepaint.net 4.0.19ֲd3IDATx^흉z8wwv %&PtTw&_?oߖ?or΁Or |~Bμ|CC~:Ksƫ y✱rϱ_u@0_u@0_uv:|fcq^+9WK cAs$ /Y,~6 <|>!2  &z^ٮa3AG=vrҼNJ2 8G8͜W=7l-򐵘wGX3DŽ90ardlm+bɟ1^uh<5xAJVzHo~ FͲ\8Μ>tܑ3s~/s3x;PUe⼃ɕ&:nY{n"y-&0gG(]W ,aNܾάx>㭲|Ff?s@\̖)%~@y3uXW9?[gVΗx_3û4UUgH|.'@_;ghQ}T9sP9rA圃9sƜok,^gwrNo`sXL.u望_&m?~gݯrx:6 #@ wlיEq?Ss4G 9ܕFQ햳܂Y`GKg% Ң`bYNٝh[V2BpiC|6br/RfB93B}jx9C xE7޷7 ybr $Mu |WD *s4qSxۍR\}e/gv]9_g]BI]u9s*T9sP9r25(~%eFsnwWhsW*gy={}WvYr:wQϫ9;`)UjZBJPGEԹŜw2/J*1Tr>1v#J͢rx9L v/ 1g5Gȴ`dg6!(-al-Q9OOP9OT9sP9rgsn}W͹2*T9sP9rA圃9r ! B.+Еu]K{h~rB2D0\-vx9g*DZVYDS2Md CJCoq:g|/+Gmm@g;A#OŒr`ٗH9i]{nNK/-etGeyDٜqLJ18r@K -W.sYtf/+CJF y*˹k>(\#"U܄8Dkn,%'s~Xq?sM[1?ɹx9s*T9sP9rA圃9E*-sFL ߞ7r<_ߤ7w-saEny9Oom;9;l͆Ͼgd;lh ~fg^j (D6ן='{p"݀2w(7z뉯/>6r =Ċ'qrn,q~5 { '4s) xA (XѕfdD]ZW<rGW!u4=80oNCi(c( WN:*xaؿy~q|>clabf6ޖ3]zg~fk?ܑUVE~ ;ڜ?ܞo3!/Km_`b ===G09w6s]]_+Y {͆-섹غoWyի|qgȯI^.=3[Mbzyl{˝9C07x}Oa[jvHܖֿÎ|/@+} M-~fM|eކ~nsa;;*&Dp{jQ.0\!ssnJ>W7>m ?:KGv!hg`v!hg`Ϲ8C圃9s*T9sP9rA圃s9LXŏTH83~PְW?!#kd -ӂ_ ~)wr| ״ezϠvjp-xEl]3=WsC)ͬĖxJ)8 [1vљZuϥQek6&h-mfŷR/{4td%ԃ)T澅Vplk_yMj쎃%O]]ӆn ^,zߖUfi=E蠨csl'LbQr`=8-XX %W}W͎ t#Fmņ h0aȦVᮕXs.A+9`F[ ;ţхL\ᆜfǰ>àGl\2a” o&ܣ {&LӋuJ&p{$zJ0Ա96NW2eaG!5@XE˄;mO6Ç M2::;(udhuSԆ SRԉ8$30&:rnMFwS9|[sP9rA圃9s*T9sP9rA圃9s*T9sP9rA圃9s*T9sP9rA圃9s*T9sP9rA圃9s*T9sP9rA圃9s*T9sP9rA圃9s*T9sP9rA圃9s_w>};s*T9sP9_?>wB.g_GrxC~T9cu*稜sP9r2;`;R9tNf V9O/-7OVGC>r>jrVYarn͡=n:_șxWqvÆ36 긠q>g5P*d ۯ^(\0]IGV*ݰ^aN̨EPә[ʹa7=33Uo+,$\4vF~N˙7 C\Wk$P97Lgٶضp"g B(b~r&fșL*^ m pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^휉۶E'#V[xJL_x29OϏݸR=0'iͳg!g[{³>o :'-dס*߆g[mS1 Җn[:|9E=uPC 2 oýTyRoF0fѷ5gy6V2C^ūN=ul_;j<->]YbKRi3͜Ptwyѳ򒌤QAK=uʕzq->[KƒTڌϱ4h-L A2sg3pG-7} _OVW{l J+:F/qAݳ^Ǘʐ[T4ˍj 'JOM=%Ss֞[{B Ͽgϯ?ucG=O m6x0x<s9Y_@ܮs>"b'$>3|Pq\2Yx)i̘^Rum<;WϢL4gxE_:!m@5i$-' ]YY#ciѺB͆dFw_ZKx<9ƃJ0Lmjf8<+xnWz. S%ךbXig8g&d4Ṳ3xMN^:1| x2X3ہ߇xhKkJN[lm๲& siM9rx)Џg!z.MqP"=ەlWse|nxֵ3/ |>owRW{s-[2z[{.2xgq\bs{`u% fϱ2ݞKbafI,^F)JQi5X{ ѶΩtA`$ID4-5s5nFrdT ,!ju$N^:qgl+>+71k#ql[6 _ p+<&Pػᣪ\Y܎UL A2 $n)cXxƃy&ڌ6Z@ e,/["/̀M 56 ڠ6N $֔ǥ dAŞЃ1R<^S#Jp2OTaagzVvҞ.wc[j<~}NJ.yίrgz:7 F,GvC5HW404}LV<;#ulIBcE9M1Aa~F*n֭z>z֓P{ǜ9l,q6y hXzJs~6aH\'PXסS8c[8߳N^/ s9x<<<x6哌v9x<sz߅_n#P Gx>zGwT<}:9x<3dn<tPtR{qF;uፔn^X>jk8sn2Z K3CMZ:(:u$N3=J2W4?p<۩FWL As}W5 BI炟)Yb3WX+ٿ_dm |ls=ˑm1 <rW<3",f=OqVY̧*BTx+%Q$Yՠcx. k@xЄ<]!k5 ?x:Z~_X+OkQ;O3aR9gz"!6= Zs9x<s9  [0IENDB`stella-5.1.1/docs/graphics/options_developer_emulation.png000066400000000000000000000161101324334165500240620ustar00rootroot00000000000000PNG  IHDRvc頀sRGBgAMA aPLTE@@@hhh4ɯ|>m pHYsodtEXtSoftwarepaint.net 4.0.21 iIDATx^흉z#9vv̤%g2j[3$ ߿%o's^oMބ医F=y6o|?uf͏gF9sM=Mԙ ԙ ԙ 9R$s~y{9Cܛ3_M.//y<`GEYUjL/c֙=},hRV)T=<AElFVR1`p3[Fq xDͫ95z&h.B.@bکzBI2`wu|Ճ.LjGO41gG=ne/Y jzt"92ʤCM9~ϭ]\4%?W jØy9?to<2ҙ=}U~ɟLC/&s^y 25Ȝ s^y 25Ȝ s^y 9E,)0ϹDŽwܯUr2Ybaq4:HcAs]idotVsD8Z =#AES49Nnv%|jJ&t4>e6g[93B}h! ۂJ)`NWTyS+)9ٜybg 8<25i,wɜodKlȜo#ݜi6 "fra=Br93¬1PU 4FlJvo=,6y߫|(#ȳ&17 hڝ}sWó5ajwa%QpEHvs<ѿonI9Üoo:s>`Bd~^y 25Ȝ s^y 25BVUL匄~ɜ7?b~G;}濙ٜ&3&W/`Kd̹' 9oT9uxzxVAd+9nh8'AD]. JXD_9zmn͙ >;*Ad֡'Μy.}#6*X yJܐ3D˺D"8GCe(%M|r>gssXzi,;.,d# &}fs-o0aNK+B/)p^%L^WR4 ˹k>(\#"U\8Do,!9?OH,y >&gz͘srN$s^y 25Ȝ s^y 25Ȝ|oQ0tHs!g+xo1JO[ ~<쨲5:<.Iƒ j8찥 &O~?=ōR`@'%pHMa;g ¾>k7mʅکz[ۿq97¾Ċ'qrn,m ||`RS.(XC|42x!JM%[UX+9a&FZIog;M/X9a^t$`ϐ9Op>!sL9Adk9Adkp>g||,sF;9Bd!^R~ VD})+'(xu䌏l~g;So諕 q7M|FSo諕 q2ٳ֪ȯ[6RجhKP,d̎:e@I fq#((Ągx } ҇HSKgV*ǝ2'0)Cxs&gmO_k7u[,&qJFU{a3YGO~;a_٭Е^-wY0H!-⨯K-ٮ ڒQX߮/9З*acQa=01J,haae|yG M J2[lE=0)*PN /x+9Oa&V1!F]6CMaX ajJ(;5\6:0?v=|?9{290@79'dk9Adk9Aߟ3>[: C: CwA;ڙ߰gr9Ow~dU13l'`EeQ۩sxOQ >y~p5O3#ݯv?k{6iGپ&Lٴ٘sq;r2V֪ȯ[[aG=?=˭ yx&^* (K[1m8R9ec }ar }͂-섾غoWyԫp3gQ$/¾3[M퀨zyl{˝9C07'ڰ- hv̩EHܖҿÎ|/@+}E-~fM|fކ~nswXɣUL" vעb 4W P>*s80m{&~uΧ>Gv!hg`v!hg`̐9Adk9Adk9\)+*rF̝?tMdEYrԯɇaL?gS;~69W:5mן_y=gs-w[غg:zi憜CnY-CJq@s-X 퀣3KlPM Zʨ͊ocZHwSi@m;,9gYɄJgSlu 0?y^Pc-v.JvUy果(*\0gC})Pww P0HeYP|*^`fЭH9#rsfd`DRE^;p\* k}ǬR &=ѕTd,t ii4mLtL ؆^0WB]gcѕl Y+Lc+sĆaz̵~ ${hDŽ 0Pwle ATn&9!g}z;1)Z2VF=8RY4\Iuc]]c˺R*|b.Xv_K'Mg9﷧yC_;s~asrHdk9Adk9\L/+*rF;,Կf~F[<@Ns/*sy93A B<xIOrGΚ10((|#/0|aJ7{х} &LSqJ&p{$jJ0Ա/slldB9j\񁰊Ж wP-j Dam'}&^IvZ2GErdIzBj )APXa|K3M3w}~ɜ[Ȝ s^y 25Ȝ s^y 25e`%_THp%9㗒{IOge\k~xu KxA13>f|Ozϼ,i= Z^ ^}VE>|g^LЃSz۬4C]Jy7O_,ug԰V :EY:-jAP4tdSt8-8}̎&`DZR4S ūF¢.v b_r[ 2s 89J+m6UeK6,C}6$1L݋/cn-ƥ3ܙsm`Bl k(ysuN0R[ hi0ajSnn(2 n͙ ݗ)<%-`^cj)EX_)K1V0Oi>Tί~~{U?}b0ݱ:grN>y 25Ȝ s^y 25Ȝ s^y 25Ȝ s^y 25Ȝ s^y 25Ȝ s^y 25Ȝ s^y 25Ȝ s^y 25Ȝ s^y 25Ȝ s^y 42%R}{25Ȝ s^y 25s^nP?h_AW,3^y4g,ϓ9?GdkU9Vz z[2gn)ƴ9O`nȹ{"ey:2EQ{MʹvYmf̹7غQLnkOl!gz#_ s. knNVzWˀ+り|&Mk$d+[9_Q8ya.lda99 œ^əQP'3snXyTwe+g.$HW^Y WuI\(D9c.˙74C\Wk$9tٶض03\~vhBg1Y?9zW|t&/† !sڜO9?Gdk 9p疛x녈*z xWB:䷒9Adk9APwWdvU%&IENDB`stella-5.1.1/docs/graphics/options_developer_timemachine.png000066400000000000000000000114371324334165500243570ustar00rootroot00000000000000PNG  IHDRvc頀sRGBgAMA aPLTE@@@hhh4ɯ|>m pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^흉v8EQ X5!=N)(>x?47[<osϳ>.Ct_.|/ܴם/CgBYϺǗ!upyEtփ瓁{քg_wǚt? ozr1&ofθ[q|49dz`cpGj_;ʳ t5xXUk&ϺޚY"eiAEwxh?;ǎqX[mdʧռ"ۖp鬷ӳMX-^~xgGy.j)a dyFg=m=·7S2t{) ^ <s9s9x<s\j7, -3\ chϺ?#gL TQ68gjYx8^f(W$Tl*l E %izJ &f[>N`Xt[ M|,z} 3FàVYSLM6>6[y]sUD&0]q Lϳ.AKM$"ǁ0g$F*5=hE x6:X8{Os9s9CWi#? x^t=ZA tbs{R|.3xdx^`&gl(~qy6͍h΋({<ޫ^OyXi|y ۪y35Zi"^m-^63##"c ᦡX nX_N`s{pMRNmdʧռ"J+>lyE`?W?g)g{PpUntpH`/<*ZObLyOs9s9o=yg՞'o<;?3|h'}xgNfx)#)xX~±]}7x>C=rBQ๞ur}JcʨS:vqv]j!,ĩ-^bVCq#owyG M %wx&ܧ3>g{>T[x\๝2BU|0syHLp3GfL-pMtΝAc¤gL~?31-BCix[F3<zj<ςg*^mO5 RJ#?MM9zqt!Ҋ84h+v831{z~xxn^9ϻ{S]ygs9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9s9x<s9ss1)w2s9xAY ?] z{8@ƳN.~ WK{}HYy;Yہs9WζC EW6}W\`t)|bj x.š^S }y?l1Ǡ=[3:3|f׏9XU &bA召% LJ2 i+~:^cV2="ge hx.XvR \wzVYorg`̺adR׌<`A w3]! ^`kIs~>kuY4rdkX<"X鱌,76U ,h`ߝ%@@c}Ј]μ^<L3]ʕO ք? k+!\AD$>UxcYMcqsz7A995Hk =Az_.| t޳"=gy/yϸ0H% /[<s7<ﷷ-aWٳ=۞d3oAxibRWu[{=2$olzm-}n57><x2˨N .y{ >{j*VоIe]YkیGY@ChVR6y3' 5,`=BK&\nG7fВzCc91.ܠtHx8:`F, -)_gڢ,XZfǸpp4la=#E ^ׁ\F 61gxnJ%=in9MԳaυhO 5YP]`%J1w4f+Y0wz iNsi 6|?!WS31NsN;ypI y 5Hk =Az^gN/Tya&=y({w;hHOr+,DbgJ\ !ft εe5Y$]FF5=2$NﱡCsF#W3HYO4hK c\o3%(2\ W7x6r5g! gP.hPW!R\^qw%[Yƛ|7{N~y 5HkÞKg8Oix7 3̿b/!ӤHk >8a38LRQ@xr8\\V='=8ﶺ` x9)=t߶tMR</WCzpVy?PW!smAC# .2z8A3s2S#of9=Gd$qsi!=8oh"$#==@8xfs]6(/\uG7ܷ"==/sCB|sy >}߾g,u9F~~=W4!5y읷Q93?D=RA{=|D\?>IzL`N.E|Tzo 6CkA,l=ÞHk ,x>Χ=g+1CI =A3guty6i]sgSuWԳ[盈{3uܷIe3ꙫ9iβ,# #_hSP$.\o[ 0os6SVˢ9ZcAg?LRLг'=8p4dez&)̸+`* uȘ,XKe?|U=S3LRς$˚gCDd$Y,$OzT`|67ܷ"==/sCB|sy >}߾g,u9F~~=[4!5y읷Q9ѕس~x > zs|ItzL`$3;>)JmC t͡5GE ~]A-5H.=82cW2hř.Еd)\c'W'%Ä m狤y 5Hkie\о?K]ߟn"=?Mz~y bA 83j}O{g*n|h춤QϦwX)1{h ?CT6cx~-zgեR# b{Ail)^1=t߶tD.;fCEnN2a%ՆJl갊RMۂ$WITCMR8%DzH!z 9T jɸ <1\\Fbf=43b?iD4=\D55xs\‚QPIbwގR<\H_W4秸}}1s\ U aC5} Ӟi?!ӤHk ? lǶu_8FL'71&=z֡b˞+19Q|&8sn"gL[h`LܷD5J;yf89g ^ Nx= _9.GHgW:9̂.E=sQ<_&=Hk =Az^O{._*DO!5Hk =Az^y 5Hk =Az^s3{}v>[Ǖak3v'yG^ovijڧ?)/i.\F v9 >i >y+WG_+[K@csB!=il /ʠ-ֆ,꼇> x\YB[%Ԕ:<9YnП}l54=7:Pe@i͚䀐.e,4+סLrM([fX cl:'rX>1,c+PCY3ikK AJ}rRАӘ ^jJ'.Z׈4C T 4Wakv<WeYҗ, Z2Xi7P RGNP̜5iu]+/j yX曺`R\ixݺ>-{F^OK^+|SlR04[#tkk8k byҎL$\ ]-zUˀ3hT4-hJ\JLhiJ:Jz.kk> ,r#MqYWә[\ VWU R Gj-.A+̤=g024LvC|LVa{s٢#{>uhm'8fppB[tc||M'N  W;s1\bBvHknkb<[?4:+$dzxMҝMrL,%o*8#摹u@ʄxkE|C(UxkYt~ȸTzYK-$9suTW?B`K)A-c+[:l%y[imA 6fU5XTɣ| Ag[ZD|\8)疋_!&lwZc&MTWisha51GGBfʹ];~DtN^ tg\?BH$"{'o@b5܅[{kne[8Uǽ̝Xr;{?L!~ZRS-X@ U]X*:dY+,5Ryxm+# }[FpZQaeۢS k[H=+JъsGw|3k+2#77MY&DQ*[S0C6+ ZmDMN-?V\C"dvYd|ćdhXgыCLld @[@S3\-۽[uP؂V: 1p T2mI Zm8œoJ tv?sYuP m ea*8@HPJ3[5,ϘK17[WsI($א%m+^8 y (KJH`"&#^WLk`7~݅S>qkvQ\͉̝=ܥg.E1 ՛rK=^%mQ?<܅)s]2waD\> %ޢ!]ޔLjfz8rB KL@J73fh.WՇKas9bW40 0x}wu*f06 ~\< M -r/jjٰMa]PLUb{yuj>bŸ l+ e!63 hψDP1%NQTx8Ϲ\BzWO̟W਽va$^t ,u039ณvͽ]57<^ap¶%T$+&Tf&6C?U qGsSPm'p`-$J*c!lfb:D蠜9knZ\8$! $*!TV,R8@pJU$;%tl\͞o; ά4si#ɳZL,4JjABfx͘ I6-+``w`PS(s]2wa܅t4lWobnq em>sT̠]2wa܅)sf`.~7֖_r2f .q+}CsGȌ-/.EPL}8#9wW,o望10>!9C+ӪUdLyva e䪣0=8M)XA0 7g. z.- Ϣ8l.lO mL٪ULHPw󤹽iBZxQs).(̉="O\ 3*2W*EI36={*.|&VS-qiU9<E psΘ; Ik3M)dm 2SaʴU$qAx),"f\=\R-U\(\IyrzzC4J:/_nko˨ *-*d Ur,&^ 00l; Ġ%܃^}6.s(s]KwQLv&P.Mޖ7T S.L0e” 307 \}[_y<~Cs(l*k*1o+ۈ;Ocs[W^yBwcwRs0†ȕ oU(g.+`sfnZa+*{g3b+ *h<Θ;g涗F=,Q`x\Sȯ\dG!n*c6Oģ4Ŋ<1UBFli- y*F~մ 2*Ҩ9@4hQiNKQ-7(-)<0˺!Kv0*Pz?uB1X[l)s]KwQLv&P.Mޖ7T S.L0e” 30W~v㼙? 3a\UsA{_N\HN39ʵU5uMX[39 =([eܙ_flnAܺ/S۲  ʭ2eL|BHoS7T2 S~2w&sdeTf;̝˴Woܩ{[B;2waf.E1 ՛[\B07y[.&RP-L0e” S.\9e|2w&O{eL撓eflWhɔ3-dz*eL|抹J34TR7TJ3_lܙj39c.*+N̝)s).zW.s20;(sgR.L0e” s7s.iخ܅fT871׾x2]2wa܅)sfܳ?כ?2WW܎\q*q;s0\Ɯz9K=PbXMAߖtܒ+}[v>sK sH,SL}~ve1h@ )s;0^Goܞo<Ŏgr܎7TuSQF̥̽KKw񻱍=-.]2wa܅)sͥTkb)5[oR.L0e” S.L0e” S.L0e” ӛ+Ls?t৯"Ya_7\UYQ'x 8ϻ'|x`Yb7}s+T૗7:ϓe)X-8mrqSؚW-[hE^s\ːՑ ^9ll% ֶ9 @k:xEK/hk/ :giqެCP!g:ek ++fol%)RNt-G\ eiRRha#|\D룡-H66kI<2CJrW~s7H{!xu+7)`I2h4ƙ$% P$Jit+ |1/K!f,U;u'5j(6JitErbJzcAA; 9~^Dgݎ1Ѻת7ס]Xm>4yv|,xIRߛcx 9>BqЛD>!<7.5_OR^ds;Q.L0e” S.L0e” S.L0e” S.L0\]]`Yi\k^EJ`Otlm7Eo=qsm:ed܅)s]e1bnv7Bëq4{͕#6>SnMËq4Qhwlp'?a.H'+0\-sdo%;W&8o.D:~j=Ñ GZ)sJⱹQ0񌹂jyP#mɖ#se+xHюP#1W MVu` m pHYsodtEXtSoftwarepaint.net 4.0.19ֲd IDATx^흋vE4?.'i"}[!Hct~w@B\Y܄߄T~QK I[)7uwMm< Å\6~C6~WM\_܂-\;>~rFvWw~vSvqe`)Gc͊#Dq}Ք|ٖ:reHȃ,>eE#eal:tL??qQ2:fdmBf2dZf%2Z:1Rdk59nƴ<&52fd#rˠNVaWfPܗ"7틒6L?Oe')})C\. CY^n<Td[<i'ٖѤ22ϟidIĕ1Ze[^Ndh R͔s-O2՛Ƨ͙dJf}[~G0"AG˵^}SB$TNu(Kf$:ݟd+[Y|O}~rO3O}~ra|_a(r\`fjls_*B%76Oԫ7)rJn f*y.Je0,-V-Nإ@w}MvlX\UV`j='W)7ÕA^8$RjdaI+C8%UF SfR(eKH'2RM8;)7iئz֖R2]93:y`G {Ons1iX(%R^͙ȕ+JSlMذ(eKتٜ9sd)ӂ,<ƶC Ad"{-k3z2ksfmМNXMЖڠD1{3AP6zIܳP6Eڧ<"s_c#!/ry#I[|#ryyZ~uT\`(r?H?* o*Wqr+o;-+&[]AV)L$ ]Pn:de)7@nBsMABH:*{h}eNT}eξ= Fr˓ŷ4G.9 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 CP.0 L-A#C)?|-BP.0 CP.0 CP.0 3YL8ׯf;ð5{]$weUN? rg72i{>}b[UVn~rob䕠\`(r\`(r\`(r\`(^݀2 \/2Pz_yB/CCP.0 [q0gE˕ӑÚQȝ,7ϕ'"C|v>$wػ6oʕ(֙\+!jZXj͖82f]?j̓dPn4`Kǧb4No+X\[>өt, 4J4٦$+HFQa]epD%jԗ,ژrņtcrahM6j %r3%yN\yQ^YD}~sQa WYvM@g?ʽ(PP.0 r\rrn$tr. oT((r\`(r"@m pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^흉b6Eә^UKU;Aע{N6߿$HdKR܍K\y={J\14_Q~ n?.'{>mcWNrR,$SJw&?dCq39x q'G'K_8իQ\F%5銋% |uFg.ъ2+[Ke>L&Mk gG5q1IWnq\W0`9w32h!C^0 8!FFZGǦx+pR\(i.kKӚ\ Hz.)hVȋw\n6 94 C@$`eU\8@/[xK;sqm*Қ`Xd/rL\N zc,@cQUn\$^*Jʒ97QqۖWH-Ҭ~F\:! j+X*^c[Vw^SS+ 1qe :-ZhT5Zqz~uX2=@pΥۈxY uK+|'O1W.-Еtvq/!ʼn}%ĝГ6ޡ07{-.\u}%׈;ݽCW %:wy|;O+D\龯Gdx9c9ٍwc>K&|Iq{;QgIqkR܇3|򕚐ǐ嚵DzJ<7'h ǎ9p0<~Uq08O+kkMf},V&wnս*87=H~b&MkMN[sE\:.qBã#Vj8+fM\?"Ed8űLq)Ya\'jὖQdq퇴C\ϣrx8Vj}qKTIZ0󄶴]#ҒX\(OC|+6C2 34EލVt+j+(nЅwLFzXEJh*+^;9D~hYXִUblhbd…#Iy7;2P/+eŲ"Pm h^4xeKoYG@qycF=!VH"wڇU8 BJ\Xjꭷ܄/[O;#Q2E[xD {H|īu(KQE@G/cqMnK(~1dzSL/+qdٻ':+@mf^uą@0)@ t\/n>zO#ғ\KɬuxhEFj`@IvT\yY;CS;SG\QԸV,T:eU$eK=(:0%2`u ŀ+vn`JTL9*@8׶FE=ZRbTϦ<1Sq6w V) e:A?X\䨎h`8RZ\0zPѺx?x ieՊ}`X3EV[\*a]9U6(h,PkY,? ֯^#$&xBxV3W3$gQhx'q.CI=0%B;Uܡ 7Dq I ~*5ͤO..>EL@xF.[qeR܍m _$|W4)HqIqkR7.֤chzfG-õcz0$R&gRe,bz' qUgS)UȢ\F0*-o#rIp^ ŝR,(ʨRbs\Hq:FZ#NC`2%.heɟ[~? .\CWTV)e7r3(W#$VF(%" wF{(TJ΍⾁[;@ReRܚ ˤ5)+|=&ˤnKuYW=8|#IqIq7׊k_Y rr{7^qrCO\Ņ#ƂkI).ܞܡijFtJZ12 +|͕S`#f_sI'(ѲtX@٬_)2qbN|;W0ReʑwK 4DZJ̚U ŒI# 4&3⢷6r0҉NbA3kbNq3]a&.{`PJ2ܣ*@h}/rML1&n46J@ |cXb/7Y%ݘwcR܍Iq7&ݘwcR܍Iq7&ݘwcR܍Iq7&\*y򶤸nL1)ƤnL1)ƤnL1)ƴAY:e,yf}Tfv=4V,SV:W\;烧KLna .X NXq:iZ&qPgK..iHLu:нG9RGk}B}<`,9vNr13uy苋P^ ,\Ҝ q]E-U^ȂQo`ꔪǚX-P&%#-2? iRM cH =w[ͩeHJ.,m=,/H}Js93\ndG⢳`CI.|ՙ5FwH_h]TK! 5[q Faen9\Ɲ:"5n= [Pb$:.B-|a ÝXj,D}F\09Gs+ok }|,-Sh` T!wBbY㞡 |.1:~S?{ŵERGYHq7&ݘwcR܍Iq7&ݘwcR܍Iq7&ݘwcR܍Iq7&ݘR\?0z9m^慀B\i>\x$u%wrQq%=O{3)ƤnW"Vl/wMZm.٬1Ҏ׈JW%qڐ OfDі8 .H;^+nG)H %\3Wiׂ= BIqH\ĎWeNk$DRJ fW ^*Kh Jz1R\|[R3Pf5`E\.xT=18Ă"<&.P0ZLIE)bMqOL4P/Mq6^qm+ĥc䩂n~G=M{3)Ƥn76#)6喝u!ln^(M"ݘwcR܍Iq7&ݘwcR܍AqϾ~'[[5EIENDB`stella-5.1.1/docs/graphics/options_gameinfo_display.png000066400000000000000000000105171324334165500233370ustar00rootroot00000000000000PNG  IHDR-!{sRGBgAMA aPLTE@@@hhh4ɯ|>m pHYsodtEXtSoftwarepaint.net 4.0.19ֲd IDATx^흋b&ELfԓBZMCQ@qN~$ EoM Cx7rOnCYD}+Ivp\}c㛐-<߿߿߿Cw_w)/x@{!e?իu:~bZ}G40)En-ԣ̶fNp+wrp}orR||p>[?IVzTmĂL4Noe,]j멨C(JJ`5)dZ},/,x:&z|&5 aGUt~i :ۡVJsK+i+[_KXDASb,sʟ+ugv ^m@xs!VldA-YV? 4,ir;Q,2>^ ;!(\\mqv_A-6}[ncZ\T3\9͝(u:OO$L!|_h-Jjے>Vߕ^%j%p\^aJg+a[1[K:߁J6MhSզ@/&,~|sKD. pݔ kc?FJXJXiz0d*;x1SATX+vg%0f&hO&bZ|y=u#n5N.< 0zuJr}2`Dn8RP3&dH j9{&϶CzaY=\rsJ.= _< !8'5 t9pr{or}@nb 71M &r@nb 71M &&\W/}*[_ P9_jX%K&d%zHb4y@.=U+'ؑooi~1|X]*o@VCE_g5WbJ4b\n#s_Uzp+cYjߦኔBew攖Dz5%5@.qRn8m֚6cᾴ:*YPX|,;gm@ J!ugX*;mޜsM!O42/=BQj{cmޜs  Mi}i}.<0 8&Q}gԑZ*M3Wpa*Yqwg섯\~ JoSG$|skdq_M)k?uf[MⱣYXDroOkrvD/N+_>qs]S>_`Y?@nb 71M &r@nb 71M &r@nb 71M &r@nb 71M &r@nb 71M &r@nb 71M &r@nb 71M &r@nb 71M &r@nb 71M &r@nb 71M &r@nb 71M &r10,i@nb 71M &r@nb 71^L3(|_}~1Cf3n ͖G} ]ϳK\<]bR^zQ=/ܰj^b{-a+v[nn&S3I^n/GcjZ{la (1n܎RIC͇ҝ\ksBO7oҜv'˺X^5$|X{r=uC5՘V404frvh7{;,KXǖ$(ɗs)^@{O0=O˕Citʍ m pHYsodtEXtSoftwarepaint.net 4.0.19ֲd $IDATx^횋v6D4i} $cZc]"oU?ȕ|~6+z^;^a|O( w]{z@b/^G6yЗF<.iN_.ig ׸o< z^ZWܟ *sh}p{l^6'~q-̫_[M {^ɋ3m^^5- ykVJz,R t^M*PȾ+x CbK+os3r-&y'&w#bz@|mK>9[b>_C/ '瀛z?_o7|o%!xp&c![h@W>D+vDÉ/d?Іb-_s@+m}!K֩TZA{٨ӐxS:<tx͑ɹ.:°9,[eWGCKPʪk:YΊ %Xk*JZ+ة;ֽYl*ecEAgNmk溫ޱ_ zMU;yтaRm+VBV!Z $\#~o6JNa^$  -A&sA_ib.0y[}ԝEe m9|}DsZN>_ ~cNx}9@; [Z~c׃ρbW ݽ#-{/RdZeoj7*Z ' ܜ!F#c@S͡iC2d=>If=ucOV5eJZ [ ˝6t-C㓆̆.e%~/0wz۴q7d/oīSZb%yfSpl-%-ބҫ!Kڜot^=<̺$JKlha+esu^eLu^ezׯ^1+o%+oaW ^1WHQ`\U8Bx=hnGM^_=W{kUk:=5t:%Nߨ'oV6x%gMMW9Q`5>J,2Yn.W:{y\{P]n5׍ d%h~zkb7"l]^}a&eїߓ#HC9}^Wb҃N21xW!+#`? d(S6grA'ƺ5ܫ egXۓ!ʞ҂4&Ƹ1sf!+Y>:k%dƎ WUC ({zW ^1+ bW ^1+z@bW ^1+z@bW ^1+z@bW ^1lx~] {algCW~Kq,>[xU1ÀjbN~V򎺐!2%[r9uvlg|-cK2֯`ǫG(k cQ0.a!E);0[pb=ՖE]s}t׵:>?؆zxؓu[cU Q9X;um{Ce%C~bN<%{.Cl &uU rۜ5Ԇr|oVm7yN|u{R!<4|-sα9e̾/xdk)}28}b~^šw^1\TbW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@Or/r1sbW ^1T 3\|FMt`W3ۜu«/_^ bW o?s8+{g*&WևufPP>uq!mnqWh{emfq׭ SݭKOxGӎ<8w{-`kE QA^3VyZ^W!W 1/x>JiC۽T8:!+CW%JBTЋY$w{ [e˫ޅ'25jj˪1۽ZAPc^iC5zqr9k<^+7}-^*UYx-VCWsG uz@-sE_z"xm+p+ z@bW ^1WwZr)-?yH]IENDB`stella-5.1.1/docs/graphics/options_misc_classic.png000066400000000000000000000072531324334165500224640ustar00rootroot00000000000000PNG  IHDRW~zfsRGBgAMA aPLTE@@@hhh n pHYsodtEXtSoftwarepaint.net 4.0.19ֲd IDATx^횋z8mW*6&-͹HK \ }@_1| |~~~@ J?W?? }@_1<|<[4?Uju1뒶|`HL75C{A{Ő੯>3C1oPΧMY>!_x: aYU_lN[z!7Z𲯂N[*|K!,3r^53du>uaN_oQ:&*Adz0d,yC_1W /_ ~{I_h+܍+a|o۰>9|CG}}~sk9|9+ۼлxrՔ.焯Izi3` 9,`dOm=whԽ\}{eM 8Cb{'~m,"K(@#ѹ9M``i!"J˝xe:3}yŐ ʊ)u*RXеUE8f:'|%O9 :ҧ9&=14g˲ -sck:ΌEXiJD$ Z]=Rb.ͳJ/2z_NXN>_߀s<񻎓ϡp7y<?_|@?gym?;|s‰9}+}Gv!ϾrJ7yA;~g> ?={6L;q Anuɑ3lOwh_=z]uGΔŀnqxrfsL;eb+yuhH"޵'3`,PZI|Xt5me1ߧ2Dt9EF@*ma|ː"{|fتѓ6DNH2Hh`zQeH=>Hmh(Ðw%_=LWLq7$!3׼d,H"jp,KmBK"SZi"Ϋhì-Eq4XT[|}wi[q~^ļ{++}@ssJ_1W { ?+|K$W-qjv:r5ѡ[XPWb+gB_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }Űk%`w}7l-;*|mcjbl~[<ӪqY < MY,cӽ^~E1Y&eyQ/SOB__:.ut"6Yr>FBa.H^rC΋T;kjM8Z6^1'90sD?$؆׺Lt\?z2oaY{cWMDVr^'ST!ϨC%!c 1'] 1_#_ƭhVE6g2!@4o>!jؓRE:E,,ki>4J1{_zkXcݴ NOEL"/W˜Xzٙ~U }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W }@_1W C\D?r1s}@_1W CB@W85^.¯p;Џ9r8Nk@_1W o_u8+3*7&wևuf_w(;|]H 7[|՛![L>k|nŲq[7T_._U>2GQӊ'\8wZnfq6B~_SS\ %v_-Bw1|͟RJ1vqp : !3CJ ١$w7ʖz [V(sW|DWd٨uBHQ>_u4dkk.eD_SU׌!bO/kE֙|u17D:kFx^f_C_ ubx_7%璛t#"~~3\QJb+b+\xK_P4O_1IENDB`stella-5.1.1/docs/graphics/options_misc_light.png000066400000000000000000000072351324334165500221520ustar00rootroot00000000000000PNG  IHDRW[sRGBgAMA aPLTE 333M%) pHYsodtEXtSoftwarepaint.net 4.0.19ֲd IDATx^획:D';`lC 7JÉCr}/9_ș|7+z^Y~0m^J{읿W׫^1+^b Cww=_Ҩǡ%ͩ% 5Qa7C{{]>+C6oU(¦`)%^ ,[<_i7Vy5C7^WAL[W y ,+CrҲ:u=0r[*A뼉W%|* +z@~W%X^m.F%#jD @bXxWc7T>~@d>pr9@7~~?ѿ{'^dyTi^Fʼ^哾{ݜYqGw{}HUvsB7Ngeu /MT~Z-B$Z |V숊% _~|10z{s{خ!͖ko;,zXN b%RzX}ȤAN/9 9eW9Z^6e+̻:<_uJT5+VSw>g=_#%SeXt:e+ z~|1Uøv0^6J+!ːbhyVJЅU\.yVm-t -A&sA_ib.0yW%|ouɨ)>_?W?>ʫ?_?uG/C+-?>k%ku'y}@8@nGWz@={b)e|[4e}E}c޳qT=s|^c¯'ݻ_\Նz=[':O%ۺtj5G[ֳJj:ּqF)īJ{y)[>-SṖ AlU^F]ː!$!3hDyh~Ju+9Ԕ;mZ ' ܬ'nJnGbê+xRr ]ː!!Kl0-L^6m Y[!+ꔖ|GXi^ńj[KI˥7DȒ6=WC-+n)I@>`JG\zkǩi9p.L0ybx?@N^1|ss bW ὼ?7o<>@8ܽ_ z;5p^#ם&yty*a~ګ\H)8Mч,ypF=|@"+9Km xm7 =HR ,VB`!ʞvs%ͫ ڃʍ%un!+A[c'׽Ig[RC [\ 59-ۏ< NoD#to+ YiV!C9ζfߥ[m tn+\ýP+!_ڞ 1vV<06ƍ3 YʷDY+IV 0v$eVڮ`V@y}+bW ^1|&^1+z@bW ^1+z@bW ^1+z@bW ^1+zŰuu3uI ]ݼ^d:ӭrk3 誖NfG{3ikA, y S Z-~_Ǿog~̖|2([/SY>Yj nxe-AsR1 ԥ6>(ExZf NQR+cNVهcBsY{nrQ{j!2yNBܙ qouȹdoC̉d?e 1-I]ƥhUC6g2!@h>|Ud8ġdx^S1ek=^k _,ܣs}d)cy<6Zc߲ Ni$ľׇ9pAqi + bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@bW ^1+z@CMNzK>| W ^1+@o'Qz|q~zx@[y9XV3x +:;n([𺸐|llī^ b򺷽2t|llօ)ͭKxGӎ<8W{-`kE QA^3VyZ^W!W 1Ox_b!^ *{xī%!*CuŬ[慭UŽUxBOe^lx- d(>z4= S˸k5n;<^+7}%^*UYx-V]gs{> uz@-sEz"xm+p+9 z@bW ^1W;-9P 9:IENDB`stella-5.1.1/docs/graphics/options_ui.png000066400000000000000000000102021324334165500204310ustar00rootroot00000000000000PNG  IHDRW~zfsRGBgAMA aPLTE@@@hhh4ɯ|>m pHYsodtEXtSoftwarepaint.net 4.0.19ֲd IDATx^흋v8D%-ۄe%'& =Xq+Ivb= |7_)_s(_sِ.;bi2+D |TB{}>w$55Kq#+f_ r)_g)Œ+s1_v9mA(w}%=߯qE2WE[&{.)&p}_ V)w}cpU\6.~QS5{\Wb8ŝ?m!a_ ә2$Z鉫HyW9+bAMCCCGC5_`? 9P,|͡|͡|a-̾"~ J"ᅞEK,_?9zF9` pt b]0Ƞ`>b S{.Ǣ/+x9A& ނpQ#Z %\W&(2<(Gu{!ڗ<n" bn γw(/QSZ]m(k^EH~tn Y<-_Iuˉ|0@dnͨ"ɫ.`s C~sYJ7^Bρv+xg_e-\9p)+~R"8Y2HudwHCb_oy[>t#<3 gv&DX':jfA%k?Wzeii/A>|0Epd(_s(_s(_sAYǸ艔9999dz_#]gm~}\_΅|bh_(_G.78_"WG,%ׂpQ\fPtLaiJV.u^G+em*h9ڹڱj,t}$_ V)Vp Wz \ýl k֛Bq]b+}b8vlMazVVc ln Y<8%psϓ+c $Z鉫Hq?2JږmESMiB*|=ٔ9999L_ +g[υ|kWzϏ|׭{WβW)(Tzc֢;206*_8?- ) u eu:nl-}% ) tqlqB;n}-?Z7n GڕXJ>W( k֫M9ZBD_,ڭ5W,A7aqm4ҋZ%- b ܃']+K:HX7}XFu] hNuDޯ7ۦ ~H`AZ}C;*dZaF|ҳ~H@;>Px%<~H⎊Yȁ|{ ߄i+ b#ƝfKU׶7˝}`G(^Aڡ`R9\9?GDCCCC_2a:pUmyYoa:8xE_yD-U)-ނp: 4KL"k>SF+}WD sQ%Vj mNAm}WİQG)({*VDյ`3o~ڸYpݞ L`kB5 ޯ\qJX+A"[F}m zIԱLۏ Y: |eC+c$h'"=v5xF.:~*~ͣ|͡|͡|͡|gˬB^555555555555555555555555555_{ SsqL} -gϬo'ϿwVmEz{o7}AE]yu`p7#; LyW>`X|#1} 3}CBWုxwesDy_.+? ⮯9ף>M(_7(_s(_sͭ p,'"-Wx'jD_U9999999;mm'|2GIENDB`stella-5.1.1/docs/graphics/options_video.png000066400000000000000000000147541324334165500211420ustar00rootroot00000000000000PNG  IHDRΒsRGBgAMA aPLTE@@@hhh4ɯ|>m pHYsodtEXtSoftwarepaint.net 4.0.19ֲdPIDATx^휋v8D;=;K(a-Ym%̯?' J74oh2dMŋApd x!>ȡċAp/b!2ޏ% ́xˍ2޹쏷t"ߍmҿޤEZ`pMIQ211`wKC|oq^x,po6/uf sRcE|pFB"Zp,^|V 9d6];bTkȱxM@:bkL:dwp防oxou5mO(oNsY25^6:[#3bƕR1s@1^gR*MZNH l~Ax?F;74oh|???W>\ o|p?-\I 2dxC& z+y/ƏJOWο7\.g0#g<X%@T,^ OQv8/]ԫ:zފc~_ҋ:z'^F7]2^2]h[Ylen= ^9\N?kO>^Zw d5GYE˴UUֿЂZLB9jx6wu3ԅe^Mbm-ZYԹJi~^Ȭ*,dN? (/fQe->pFۡ={'Zb;VL5 N7lx ujE]87)ڬx6yMÙ Z&&sU! ^ģ)5-UsYtuYEuBT'0GD-s9pҟ0;%on* (,́`,9pdW238oXjfNj|oh74wy8gY0_Njwo+ɻ7]sɇ_?M"x#yz.oe"I)^lSpd0#l`WMdtD> 2(wbb90{ożrϧq;:I<1}O5^C<8}kyeY;a^er%@xXa$v[ k(:S_\ogZ2%H d(7cM̻THe) 71G2ނHsW oO[Fh;4qµ71Gu)*ePTTثwP:W\ʢ.,3\/i+QXPQaq8UxeB; ML.Q>/)@ %ɱA,[TޱxeEuBT'0GD-JVڽ8λڡkQjR8^n+jRUR-8/>!|,,dxC& ]2aě! ]sɇsh74o v X&pw?{KkEu:`a)JK^,ZkOCx q6ϛ!:J/S>+/pe/7z{!T.=|}^.QFł{lնx ={-ZC$ g(^V44vd׫n\8h;0WVLXKf:wWv-FBfܺvUZb/~RUe}98h%JœBJ?qs,^ū_By/+^>qwl utFC=USNjRs`hc [DրgfxC.gY0_MM.9H74oh2WiM޵d;߽}p7~#=d7t}x +TXKx$ũF xIT0/wV9YBl>}ucg-T0Aa{/gyYh&n*wisjG+ iт,xO; kS+T,k12kGΎDuĮ,m?qn"p+=/?a [HOՊlB*XX'$J3x3ވdxC.ȳaě! ]sɇsh74o v XAx b4CbyoT%0DŽFfW{0{S>Fq,^_5M[.rm6Qv{mˣ9V%^DKi&=xOQ)Bwu]h kUc-W|s0?ñxJhW@%n;B-@˩TJ 5T\&|P[G9p.U^攡ˡS>M2 {/:PiO}/C3MGf;&NjC\/~9lꮩ]BJ@e)r] t鷪zNjC|4^%eVeQvˢuW֩Ж/q}2yaX.NWӸ&:ʜwoyK!V4<>LR-ʬx#q!D50GX(8¡{ȩ,G9/>!|,;=@ٱ5woWʶp$&z.w-aBgY2ތ7"w?:no274wn kod \2lK**Xiʘ#HX^6}=2mFJGT(= Qe*/iNu^6Κ^-j)̇s{-͎Tث-$&ص[{x-Y+'?Z5gͧřF`5{9CzpbZ9+l>$1+ނ; |64ʹ .-0qJCU Z< {lXաSh]6fTE%^F#,ԨX`G[HOfCf/߽ub]S&X`h5> 9g>㽧«xșM|829g{&^].v&{rsx)dxC.MW~=7\E n/~~mE 2<X%@o_ȷ]ݶxYV{ݾ:6v2\|h脶n\CvR.Tx_nz{xkxaxbbxi؇ 8˖mY$Yc}&K+ 'LN*u;bkq&#W^šZ@}RY ߴWHA5&Xew:fu`e./6PY{]T h٬sei-52h,.aÙ#RURaC'G{M \^mc񲠲<[c0Hڶ #vu TLPCUs}I7*Bo=\w%xFZà 6yZ`+8/#.c-),E0Si菻>s]c>6z2Kċe`xT{zo274oh2%^|*ׯ&"m/$!o v XcA_2*Nv]\~,^:9ϴxM€{pBem][ܺ.AkF۱=LubRE;ڂ m(J*}dnuY"(huK-/ߒ:Pp|q{;pEiX6kfRPr<=zvK-/ߒ:|#5uNFŦŐ/u( 8<6in{èQ&0'^; ;sZʺ:E˷-n'Kk-o-T>[bz`?@].QӠD(kk->yDE6Ǝ~ι^jñx1'S XxcSOċe`Mm~=w7B74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M74oh2dxC& M7442%0wٌ nOgm;-Մgu1;kO^=% }HP[2Zt7( # S> q̱?}BrjY kCUgnl <7ظTw=-7:'Ws<ÈWg׍(6L;Rt4y3z|]cLm{PFI]Nˢܵ2 訐m0EnV XXM'%@/AOf3*K) 9duQ)שX^ɜlMֱЁSl{7nށ74MC74oh2dxC3'(Ii>C񆦍 ;*49| .&anw3ozd& MG,0XT˘>Uiwq"ez4kxPѯ5x]fڊv6ޗK⥷=oi۫SdtdZz3KԩxM4wڃp-!-EXc-^¶ׯVhNkL +o)-\9+QPǹ#/12RWsSz)ێ̼‘xŨm* ^g+6WAhxysGk t& U/UDhb7k71]NبGvxKi2xC& ggC{w鎈&2\;\Bo74oh2dxC& ŋN"Dv.vwO;IENDB`stella-5.1.1/docs/graphics/options_video_dbgcolors.png000066400000000000000000000112461324334165500231710ustar00rootroot00000000000000PNG  IHDR9b4bKGD pHYs&:4tIME7-AjtEXtCommentCreated with GIMPWIDATx˭ap HF * Wr*pAtVY/]@$6"Hcysu(4Czoׯ_~mÂ<+ ! YCW]Z}k^p^b= [Y˂A`x-8+Vx-"‹""/+‹28%o[}lFx7tErVnm?GJokzR#[c.nÛ^'gZOZsz׳ 4+G+»ِِ)gVzӳuMxoޒ}FQ+`,i!"t% ֮osLuf&qrQolw漰r_lg oěJnj o=bT-7%-_Ӝ;׈7'̵ŒifMz lL5 h>u7n_lSͥdqB7ވ.5(k7@q-?N4boXw6,rocf73q?T3M_~'sz+}^S^^S{ /+ kYxM5 /p>7:tv-ޭeE^ /0p38GcxS o`^)Qޜ.Ixm(M[.zjG7e:u}2 .VpK;"Q%KxSWE7ejfR^x [zٽ𔄷dz);x0!%#՚ޚ^ak/  Q=G|NS{G5 /`2)S=nj'Xfx- ,uHj^`^j^@xvWx f^@xreg:? + ~x1@xqO  oO?LIxAxWxWxEx^Wxޭ>ܞߓ{t[qJn3W+b}(0Z> j^@xw̾@zϜ^@xFs[aI rJ.3cx>>ʙ߻7z'ޟGJ^s(( oL osID[>^@x;1{6Eޜf#^@x|&-FW:*5l#ޭHV>^@xD[8'Ǝj"ȹG5^&Q'5՜{"N!SF)#G|XxExWx޾uh\  K]ׂWx@xxx1@xqO  oS^^^^@x^^f ]n q=û]%߁=cWxm1o(Z7oWx(w oH}3Q=[+v ٴuR4[drQq\(}:ށS)]r32gjO^V|ހ›2Ҭȃf m}7"ݏMIxAxWxWxEx^Wxޭ>ܞߓ{t[  ^6}^@xw̾@zψeޭ9[Kx}n-5>)>LN"Oβi޽i)Ǘ{* / xS'zr75lse&'6 oMV oHlTޞS o(4b9:Q{M 225wljjb;ljÛfl{٩ԏeQ̀V3b9D\;e]rjQ /N /+ ++ /+"+. kA + l%/VTs~Y[7o޳7wuxgjb<^=";rl:+e+s8b8x)W~}殿ේ[>q*[I^5Ex@x@x^^ޜ>/) @f@x@x@xQjc|meѝydo!yk4^@xWx^^^^Nx( + y뿚u=9YxAx{ElY;}&+xRn^X')Qܦ޲Sfa / }QJd oʔtN#inov 塚o6vۛ}ex[(oc^޽^ઈν_n-[.oj5m;x*v/ޒi)5 koTsFň&rx{+|FϐFmoq}[s[  ljZw}G89ꔩzjuRD.89N锑SF:es5# k- " +&YF#ڳ:&YF wg[tMlE /// Zg# W2u|IENDB`stella-5.1.1/docs/graphics/options_video_tv.png000066400000000000000000000161601324334165500216440ustar00rootroot00000000000000PNG  IHDRΒsRGBgAMA aPLTE@@@hhh4ɯ|>m pHYsodtEXtSoftwarepaint.net 4.0.19ֲdIDATx^흋㨮EꜾ$^ƀB4GE,$Hz?5 )f֘[cnٻ5f֬`/~ , ,`/EeܒoۋCI {!^}wkޭY.QM$n`sGW/@Mq;*#Ύ瘽l/V?no熞H6!$#rWP{sFc9ZfzBz^tyBtz#U Q  wTNO hD<&dq`eS̈́!6DG GUfTi).1^TP2=B)8Isf3͜ A#C5}5g1{wkb{y^,3^|uk`٭wkޭ1{wkpH90 q|`/ܜ;\rL=w5>o;3v4_usƞ`kbo`{R!e(3?9 KE*W0Ɲ Mנ14HD.{&ٴ[e6wpsIwl1dS]1AO90\Jb4RHș\\AU.{=Qצ{ bHyDPm>rL#<*[}6CN[=d^EU{CH:Qګ"] T+8LҌ<@88dRx/)Pχ!e 2 |!J):7EQPN= burTD.貔c3!HqFq iYףr@1犈9])vpNAdJ!8h\^>$ܥtw*(JϷP>$}Z@FfK79Z ^#yܲZ-fޜWv}[d=C믻rє@1!"ge4^} Q96fo7gjgI8y÷=^X^|dw `#` {ዾb#4^2XEU51{-e1{0{?ߠ wxkhщ"s_) ٘Léf8S {Wi\^#hJ\:#v^7@DeZʀ| AjTa|Naj9-EM:<3qb adjɠ#޻Q{uh~)JK&ͼ`MB/:C$ Xxj_ƸmTc^0͎9х@NLj5޻7J*ˬn/'JKZ572LM!MICu3u|TY;QVj^>佫ͅRRC2PBMK&e!ᇹys囼(£BgG,:E4D#]g9A3"-׬?ZQ"ɰrIF0fNh??%L%kգrCi [L9%pZZRh'*HyHa7C/gpZZR%$A-t@.00<|ēw<|9.:!TEúwphԏT(G%KG~Vw N %8Ќ 8D7fr1{ݛ{4ɈX^84¤_b{׋*Eo_#` FhZWkh]mEn[/f=\VSk6zA93y¯ګwk`I{2a&떠U*Kc/ԍ;i/-uFoMX<^Ry ktfkr"e A_?u<}ħKsMO 4#1C^VS Yd]jIlZuLBB'"+$EH)jEPEr}d Bg'Lq+{]Z3!<(#µ$%zi[e 1*t ak+ :QVj,A*go $⎤DhIuDeC 5#TUiIE$Bs]M׫cTh̔%ъ/gt1E"EL|ZX/w"d8-k&B(oSp*:)_GRtHC2Zpn*ސŘ53X^k@fS3-k<ٻ5f֘[TɈX^84Š?:e_/uޭ1{ݚ'7>n0^z߅7y^wu8z#{۵x^wIj%e { `K\b!]܁æ2&NV}vSдrs8hz;@|w Ϻ>k/>:%7:vu8na0S7 뢪VB# J!FF\{]k{]K^q CDT \ګG^ E;RBĘtKPю y6T$0{}&hF?AȺ=0S7tٻS4tPRYx_k/g!C&));>FC05(_l/ Np6ffc-6pLL{{1{[0{{şe\FLݘ[S9x ~t2s74{ (m&LOƜcP7:VC)SIap^w]Tut+NJ%)I{ڋˌakIE&n|P|phמnq R$F!qC)b{q|^0!&%fïޒ,M:N3T w-I 'EQ7NjphJBq9ZR%-)jx^zOɧ#.=^]Lwtyb1{%Qs'uUcRh9TfzMu+jy/K3Ӕ>Pn\LEE:zu^, ~^ =\)K*%+6ax)K*ug:h;7C(BX y{ B!ł=ߓJBHFf/%`?G3k8^lUŏC`^p s׭? ffa0{wkφ#`n؋GhZOD&^84kϸaDD 4TBi󢽑#7Q3Kш;z *RMkw!{] \A3xf#RC)5ˇcy[k[o3-ѶTe\IEm8kFb9((# PEfޫ\X„=< UK`:›^;Tlubq>D&mCrGRI Yy^Y+瘽tJ!0|-%)iYaihD┟og櫷`혽[sEqcLF*`𡭅F1{d*g1?:/gSً|0j쥝um^ʑs=*2c|/dfG}{ޫ5C)8#/fǸ $4#YG$=/+e -ʡ)K7+N ZB-(R2xtzK+/}&TPK#2foX6^:]KRC eIr\ " f){]IY^w8d܄ %@ R! K!Ռ,Y˽zIgq&A{t$"/ sCE0(ʹٛ݀0{,ezK+|}84f. 6ڎٻ5f֘[4ɈX^84„mg{lj~.bdj} 쥿?+3\=iŎ UYecn1{:Ozni/}t1>iM# 8R$|Jx^'n|(D -mჯ^͔BbZB^KfD G%U e{O 9}|[r R`Pf@P>BbVgW/[>LQuOR8%!pFh7B'Ȋk|3e^$p*tnb0j I41{ 4[{ wkޭ1{oG0h;f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5f֘[cnٻ5Gd|?G5ykޭI+BG<#X~!vf/{qcNwkޭ*{ 81 *C-6մPҙ WSMfs^u1-F.G|ӡ%==S/F$ Bv&5{0] v{U$JqF^>_tث_&DRׅK퍅G3Qq^BRD٨&- Q^#9t| 4c/'JKZX.ȣFAxT$^zBNY1{N%#WO;{JO!-ht^z^œP"j)㹴w6?mo+ݘ1{wk^| ĶL9y{])BG<# wkޭ1{wkޭ1{ۋ߅Yllʟ%±I}-IENDB`stella-5.1.1/docs/graphics/pacman.png000066400000000000000000000054071324334165500175130ustar00rootroot00000000000000PNG  IHDR^gAMA asRGB pHYs  ~tIME%E IDATx;o&_ R"T!HD t(ETHt))t(h(-6w3ұ]ΌgH?=;g_ŶHW/(t*[[[U>|O>mʗ/_~۷6SNVnvNO/0Y;m3CLU(_ LVY},K8,PF.,޿q~~~W'L&޶ LVY޽>nlloө7,7:x۷o7oT+0*x* L9Mʉ7|Lj- 8z㉷L`XRJ7V.5^eUҍwRC[(^&Ws޾k]?>|~ún(29a S4tMŧRWœn57]iw!h.]/0iqzݷmz}'P}?S?>c5vQ&^)^ x^C]?S?>cϻ -]ms 0ޝ'sЕ@(^/w{kؗ:~Msm&&^ xP 0}ϴe{xP@57KJ=>9?//@(^Ż{b{O9?&^=ƽT׏s_/@(^ PK}ϭЍ}Oܟ{xP@65=z]OhnZϿo/ѭ*m;P(^5޻,߇5_P(^ 72=i5l&^&/:ka߃'= PKvr/o{ Y~Ke xP@O߿_Rx,5x/@(ޥL}O)s> 0VcS}ϯ@x/@(ޥg[ߏƾ'YϿ=L(^ xJm=Пߩ|`/P(^ hN}O&{b W﷉{M;~P(^ xLgO@}2?=~M(^ x%ߏ7 xPc ~?WxP9xx5=Va-wVz> 0'ָZ:owZ9=&^˔-ZmAxc5x[sЕ􏉗}|z>/x}ϭЍ}Oܟ{xP@65=z]?S?>c%&^܋ޝ'sЕ@(^/w{2kؗ:~Msmm5/@(^ `=i?=wXx/{,wr e{xxgc(^q?)DD/_m@BG PP(^ -:Y(^hY.'ܣxhRN{xY߷xP 0mzF߷0(^/@,pLm)^/~ͥ 0v <V'޴l­s KYJqnllūW/_/^(?^<{xiwo.n޼Yܸq~zqڵիŕ+W˗/.]./^-qUvUYew:t ;o N?_y )Ç9rJu""CMeuU&.uK qוn|';*ǎ."2䄾 =V&ZPu7- wʼn'J KTpJ}TWur#SG>v?;Ş~ڧп@ŮS5ZQk84}o/;b_YcMl,弬A|߮8T5w sXBZLԚ1n^,N򒵖{1f] M`;[)2wD5 `GɮSLuW``s;J#TYt2@i0y^; rwxо^5_z#7}bM1R`_魒Վqq^qJIR嵶9H 'dp8^{hyZs-8ӓf)եA|}3tZWOe/;DE&/s\G{5fC nչ$*UuP5&{پjR*CwaKqF=%;- Ғ0Sd]vIy9G yszd~gAoyH)4L+M|^P3: _Y7Z B4OT͵$bj`ywuՌ)zIOZMchkuj9mN%EgF9Yqy]LT 0+'?wN^nį|[a+"[^6u*)[Y:Acjb5)1^|BG Ϲ~/4NTK]8޻ibf91 NUXXr-BP+,C q1x.9ݿ[|iA JwX\Я:^As^_VbHt3{6/5`_l< iV$uR^bMMNAdt\EWk,\k/ifߺiS5d.[N/-=cҰdZh@Tp=fp—&hmYʶǨ ڲjkv dU&8z>\kLp N[;&KG?p PRׁ0 "͂!a KY\ϹAjw _z|͡D- NK*V(7E.PftL{or_p""=(PO]G0d'&=xSo6;MoӺtIGZ7)'ڞh]`X:dQB-M{R{~otJ+ N wu W^nxuzgJƋV0) 5 ZkͧGbHH$0Dxyʨ[&̧@%}R/knis"D"ʱO-X&4,|eU:@E{ͣf+Dlx?8'!x8:&s/ХA!_+[΄iq*[W 97\씓!J} XC:J`'XaFoW_D|_$WEXXi^Dh5YIbl7D7r0{2MOhmΔA| X9/M ~#D<ħ#f?y*uoy:ȅ8.4Me{[f*(dZ_:Ǐh>.sGY9\5pI0S){T d$Ai_['pB97\mVc cu͂l3 2@H*KHF,߉@Փ 4S VLnelS`Mp]fȐa V;n_M 3c^7D{;#*\U٢Et'n.Au<`" yV{^¨ =řц/tWkOd`@F4 -1Zƿ-p*~*x+ON@&8F(7$7M?k?\ȣ0Q~R[Ma[#J__쯏Չ)yhD{sv˰֍=h $\TюC Оr睅WX k>ď6z=`LbkNRK/Yh?!Oܥw6B{c9]E`5@}]쮱{m|BM8.LsŅ/{?W2\Ovm{*U^nJdªjXaDʋ,v@Knb&`Ѱq\r'7TxA9 9F,,gBǥ7l$jVҌ|Gc:ɕ*FNyq3̱D}]ۋ~Lb܁~HJZDm 4w::g%1*x4d._]iÜh'AAV}#41$Pb&pgDҋm(95WH52vOX w )/o>ЮZjCMUhk9|j}hl7X:a5n1Nv1~),p-\IܷVK][,WCR jMU\dRb?b@H$0Duה mtu5K3*9kURk5,iV* ]%ccڂ +W:3œoO՟fNDェqD҉_ ksy#b^bmB3:{_/*&7LG k,F \ pS, uT(6r&$1LqWui5oT};)Y>s5qSCS pzJ4L.@޺AI= 5̳^ 5ߔ=*<>`_}_GUeOUW^kw\M}lg ]N$gCy1 y4ϽFx+![Z5JӵNiW<;zE9]/nTʡīBmQ*mϷX\_A)w'X}eN;P8GV2|vZH Ys,!:\F k #c1;@s 3019q"! `ҟd=o%a3|iFix27y|?NZNU;->N!/GgZY>~>}G\RD^´Vu vu{VC2oq%x!;Am[os6r}xy[h[,=vHYBiD 6;cO,ÄOX3@%~s@ʹ87=ܪ8:[i83Y޺aYE|6y4muJ>P+U~qdۏy1&P;ܭ 8Z*w@Xtfz=F&0m[6^!hyȮHI-U$'m^!_ʛR", hJ>{B'y*4Tht*HϏz4@~F &;Ox `JCMڕLx2օrXj)&w|24ʣ)gIږ% NCGȴYrӺ ${olSQ5OO~Czx.^u;|QS\'~CݪWٮM[W%eG0@D A/ 맟\O7%Zkݲtd?|g2Rq\r/N&XߘeZӤ$ߺ_W< drzijjJhB.xAOx"1|oӍ3+>j+, X тFbz*Zu|iR>F?6:wQ:RW{Y)ZV&bDƩcѧT6[;5>DIFxkOqTWW7hدip6-JF:l/xpBx{RvQ|[:?Y7'C|[P As6 v>ỈKs)(HvPh8#j 'r79ۿ _S~nrn+c*tNyf@31G]'ĂRҏ``cElTmU{|%먠7W_+dNreP$ƨg,``1 u|#yv ^Vyi&8h`Sm-u3Gv^{a7x C 0uA+wRd2U)ЄКs<.~"gINt 22%"7Y$k "HTL8R T+9a#U b.278?dRkQC'H$eΩfhP@(ݛ` ʉEs˛𝩮yLdhE 6\κ"D'llR頏,JH.Qcf<LJuelH$8-5I ]]AF"H6p/Qdr:^wVlz 1S$Rz3`/߷4η! Us V7f(5]YGXc굕_4GO0) CtLƵkU v=?F")uw%Gy0h'::JnTԶ>`$R,s BB<\;;mb!I僧#FםVtp)] UD"HËnM\s1JDܓ߽`H$4Uxl/v.P?^H$2t6| `n5[5.Am]#H:7fFD"őZH$Q#HQF%)&|SN4_Zjytי^H$s1i9?yz6j(v5!{閉lduE˔ۅ?X K9"cF=5+,|uHiNer2[Uom 73C-qUfn V26#J2nN6R7Ju/~ 형q_n״sK;]2%:9B4^i#ϰ0_F"bKy (6ǚ`R8Z|԰O4oE=؝g-WaZ&I= U29YD;Le|alD cZ<3SUriޮqXy]gJ+.4$/6aF߸,\*cN&*iHJ[K{WL(` b~Cq-𔟜]("sSNyd `o*&@b9D%=bW\9r#7y2 }=Oh%pFVv+$Ot1S =?RU}^pbcyX/2| ` ;3+{ߩ]ee 37$}kB1aW;[ rl(mC ޴.cIOe-]|fVl}iga:N{dwOmـڨ[N|er k'GyR6tOrGz| MKú Ղ*8A#7dkbkf*:S~^pl1R<8I*飹HKq,]D޷pñ@tYY_} R臾> d@x,s@߂}H{+-Ck{{)ptj; V}f45StHLc8쩟)1x[CuYviYӚwIegtw){pu\Rڳ*ig}BE/e,.MVj8nAoA@=*zgZ "nbmU/M w|:3}}]b'(RDf7wnpMz閰s=O,qEL+ykr,F"mUkSmR+ w'O$ٖ<tDES`D҉V+ \}0)|%jF|Q#2F;;]8H$i{t=ܷ{/ū:[ERәص"(R 9H$R@"Q#H ѵ_l -F"Ǘ0)ű#"r"G6MFUeצ[攪r/,tfJd *of._7jmfd\Y7ʭVdYq}n[~}V]B69wv/ccs䚇Jh%kX+PA-M»Ź lsr×RpV4D"ŗ(Hز 8gs:=%.) LBϙbJmR1VS6 g]yV?rI9 &vjn/ka-vvO1U쨥8 -)pXoe]'>E/?h8"X+?oBWTl~Y?!xY01M7(! GaҮKvHt?ME)[8L#ܫ\WckV -؝t d['IB\8mb `t84" A'ɶE^3ҲR\- Z-wbc0c=ϰpY(+%;|A !Cu/kB]m~4Xy*olv |+!3Z+{cWJZQ;Q}ku<}l> |N&u'~I8Dz<'IϺg\XjG 'cnJ4|e,v$`nkF /[/C{f52B-e%HAsȊ髼2ÓA;A<z{]4X`oUg x(h6VL - [svT_Y֕m%HAUxJZd}8%A~!jr tl4q7qkrݧ&IZ -eγG"8!Zb&M7+cm*D5\6^XS|?DNfFsZkB?ׄ.¬jUh,̸/k!@Nd)ZuZ=%HqՏjz\To_7;n-Ė_D"KH$0DF"HH$D"Q#H$ `sS䢯n nkltk_78ݝQӍ2F Cm vLHqٞ,e*5M#1*g"Ʃ?{˹.23Hd 5IyUM$:襟>-U2gV:dkMpL #\c\t$=4&X#z ϻ~O/6):8[a)V$#헃`)U&66L|=t&vWCout$ٔڻ&kOqSe(fwU `qe/4W=H$E:bjf X>XoD@ _5Mjj͊whSLTβd3--lǃLYx#یE+{zTQnFupJ(&m1&r RuPm?%KΓ2TyQmgX:[چN;}gkC A^tƺU39M{3 x߰ \](z&ʸb30ϮFXg<ޓZd!_f/bE^v5RڰqܼxoF4TҐ<M.2I]fG9KK;@b?XϻڻÍcǽadP4H|@SϾne VtOVa\oT$RpbILIq|5?{'ef>( C`%6gk)v>C漤C,1ļr?IlQjF$)~~m[x`Ssk1cF&/Nw1FX^e?!G_:SK: S嚍" G|:Z)Kmtc&2o$ѾgM6Y/KJ-1ۼ~sw7*^pKI2h;]vzl2:G[f6`j/(9w70S1O*:Pw?.ޟfCPQE[i B7{ >˿|X ج {*Cw]Zv{bjkG]A]8gUU78b G41v6By,tvs711z0IwS7C]tu-(oZ;7ldXLyR%J :h lCe4 ~;{99N{ʓumiγ3QeZh}c8NFёp+7iYiucr\j46q܆i UUW%bi1THtvjhd^t'NGYrJ8ʃ2Uw4WϑRγ)vt (bT֭u;qNo}|ˑDW{MOS0MCxSmVZ%[ȈHdKSDK] ݢ?x}H$uδŮERop*F"yGEfbYx#Hq% `$D"Q#H$ `$DD" g*UVe/ &k2Ven!J2/3L Ny9%tEXtdate:create2017-08-08T04:37:52+00:00%tEXtdate:modify2017-08-08T04:37:52+00:00pSZIENDB`stella-5.1.1/docs/graphics/rom_browser.png000066400000000000000000000074331324334165500206150ustar00rootroot00000000000000PNG  IHDR,sRGBgAMA aPLTE@@@hhhb4ɯ|j pHYstKtEXtSoftwarepaint.net 4.0.19ֲd IDATx^݋v6Ń$oN{BL&Y$i;_!W@_SC%D QHu~m^T]Oe':L/FLN&_qb^9_?9?߱xFN2&U=rrgd 6VnzOǺPzRv͖WM+燆sdX)|>m_89۾ciU[NޜZm¤Mǡ4Y屲մ?/ձ c2V)fi2?Agm:V eaV+}tLƴn&c뇐2I'8t>V+}}-ØԱY~ݬ,:':̇a]_Ilf2Nu q Ё+(H%D QH%D QH%D]#|;_=<-7qzwv0?u9-y[hTuO2-+updbԸyCfvM^9,6z Lȡp1/Cc.8o59=46Li?1潶6I|#xCڛ2+vmrly s~,ZS*=<>6iHz[\ӟw6N@($Fp:$f 6&c@^wYk1uw:~)od|=>J'X'o7@^w#@^'D QH^R7@($J@($J@l|KwO6lwvq@׾l;;dAؾlo'?>L =p ?f9 tǯ:sk՟}np^ug8]_&}x@9{) ||22y,*=^v5O^pvZwPn|ɍ'Oq80ml(/V[\-̳19@s],r8Ͷ׬{e.p'o&j'xMja;@"Jfs/p|E C1.wb7'8xͮLr'XYx!uX]qhF;2 +-'qv8x'0u[g`n|n7V6V' l.5;TcWN1L7 `|1^x>겾9>VCݎSW87{cspPҘtvZk+.?f}{~P'mVƅvZR6ˤҏc[XӷeVPI֕SO˟; [[ +y0܃>L{'8_O|6Op,kg?>L@($J@AHB!~_=޼IENDB`stella-5.1.1/docs/graphics/romaudit.png000066400000000000000000000066161324334165500201030ustar00rootroot00000000000000PNG  IHDRmsRGBgAMA aPLTE@@@hhh4ɯ|ϥ֚ pHYsodtEXtSoftwarepaint.net 4.0.19ֲd IDATx^흉vDm_c+)(&p.,\IJQ"*|~6ÿ4(ÓQ' OF2<}S_@g{~VIwKWS^`? ׯpp[ [k(Óh/GS'c-G%m~ۆ,Y4y=:t%m8G A)^;11>_{TXf*B\[z3G(10/ p+A{&Z*Tb l,; 7$BpLbJдoE /fтx^Y-yQLcK-5TPB \/ /ɖgP0Pa9j0]@XF - ×efaQ4A DZZfls[># MC XI/;čD_`,4Cq\\bAs Tk4%ІXڭ&*.,2 ^@w%ƒ#^JlN? X%d(:V˻1c/e-1t[t/J2<.óQ'  nPhKF2<e{?!aq`sCs3y26 }5Axܿ X`so;8#c% '\`ֹg?'[^'?BB%Xa &h"LC֢B{q1ƋrIa/ѡ:>m BA8ř r_!" -,,:޲YH`T#Jh rw D-hA/faua@3:aVZaB;/nh4-т ^(¢- TxX(iOʋ PE=\%9%dP`#h iJ- XPĐi1rʼ- ٪/ Ė*!B$J(n[adu/+`ot ) ?d_ OF\z)ÓQ' OF2<ex2d(ÓQ' OF2<ex2&)9>W5ڇx h97q6x9o!*]b'^]`sp?%p*p Z|CvȸN~/ˆED8ڂ_ъn fZВWHYLҞ@pO(^08ОqƔ,]̍w8"JK镨U8ZhN`‚C+8"mx4`m ]wr֥ |N•B! J*0EgiF[{wr;Wd^ yFnJ,Bxbcf0##n^ yL*ЂHYXtGfٳὰ*-&+E  TV^- ]2`’ h hFRAf`ES-bxYTXAKN<_L2d&Ë(ÓQ' OF2<ex2d(ÓQ' OF2<ex2d(ÓQ' OF2u|=;j/C/3U3yr__<'P' OF2<O?F~(qQ@ӢEMfW)O`s ?E+- muƝe t>#JLcƦ-ڢ=%t'0.o<(-WDO~'×}iu'}Zr0|ϔ'̊ؔge ,ނrMJ@(7 @~Os)O OF2<ex2>eK Q' OF2<ex2d(ÓA͋|4Ӌ4|~eff5IENDB`stella-5.1.1/docs/graphics/rominfo_1x_large.png000066400000000000000000000670721324334165500215150ustar00rootroot00000000000000PNG  IHDR)sRGBgAMA aPLTEB1JJ@@@hhhkkk)1bkBRƥ94C!ZZc֥Jɯ|JRϥmf pHYsodtEXtSoftwarepaint.net 4.0.19ֲdjIDATx^ :g{{?\J)o`Tf{Xǿ?rEQ|-o:QWS^?AzQ5EԨOP^?AzI7Fށx15귩Q/LZuyՃ-8)އuy!%A{lQpzwj-\;Xx-y?j2pu6IM>ppͻ^n]kpAW*ޒu}bE뽫=5폺=lAqBon,kkL”(x桹,|%YSf:'K ϼ}?G@ g.X7\Bhj B@N&  .!RY|o;hPڥet\%'/lcuahD;$ U.!A{Xv#&  .!Ry,>wh.7؇9&l p0/5Iۓ4%)ʅfk $3\8uƧlxF_˦K/Q>Ou\"@-GԔ:Xj0zhz$k5I.ZnhDN`"e m5  .!RO,7G]2AѺ6=8 a`_Qh*M-5Kh$ͱ 6m5w5shB gL-ǧ9cx"D,=MbCr(>roDzԨߦFjoS^|5귩Q/Ԩ_?-yOjԋ'Q/_>_ba_-aEz~ =MfMtϔ=ix Fx1ejFԷ8~_~5eԨGmZNe3it=Zо^P[rTa|_K~*5+9:S7qX,<%{fVe5tQkyt3?mǸ g_f.1nVS$"=5/᮫|05+9>{K"Y1k!i5ES,Ux\M&ҌJ(Cj]ql6deu1`K(Z) 2 ,M(H,Q"ߏA]i9QnbEz.&ikQ_>?z$+rEct߳W6^4 *BԷcKqVӷО)t:_̍3U|A ,uw{)L3p5!\k&!^}cٳ 6{IEԨ>>{ 1/"byn=^iyIѺ6sIƖRR*Jzz nPF[ jZESQ6-g[Z\)@p4[D8f TIBԨl&n`j{( ]EzX3p4Q`fY=/:_Ѩ1LV3C|5+9:ũqcVUԨoȊ=x5bZjԋ˨Q_I˨Jjԋ˨Q_I˨Jjԋ˨Q_?ݕⓩJF=f%u#ZnWB-oڀ%^XBJ:6IȢ3A&ӓ#+m0l3Yk(.+yx ܁75lhdCC,m{\<nc5>loqs+ $Y7tق}tx)ѽqOq5w{W< nc}BdaF(τ/[wnPɥ  *$7otp{t`PZXJB/a6QpX[x'`m:FU :;DL[ڨ=$}Oq)5x[sѯ.6z$CK=;xL:mnc]?ςĢ(KR/gGBWJ tZҬ1umq0 [b)q'5')- !"-?u:=GGtz`j.m9:Q/~:mnc GݾaEQ>u:=/<EONFmy(:?u:=5e| u:=u/.sotp{jԋПտ|O9o߾mwNdNh6tp99,~WG mnc^<4,.ST 8d*V<]Qqmncϵ| f,{R_isԨmnc5 4#+cMS~-$xS]@ǚiɕ%jl(?zk?itNDZnJSf#kn1uّ E^г>c|俖?m9> hiAp'\+YLAr_ 6:s?hA-vZkI5SeP & T CWqzx[s.*#}ޱz@.HHaGEpRNuԨmncύ<\m鹫iJX<ӱ%BE:.4h o*x[s4Ϻ:G!j}`s~m9:0O:5(u:ƞFݾ=EA6u:=Oq?u:=5eԨmncO˨6ԨQ>u:=5Vuū:mncѨmFU8ngt;:L6yPԧqo0C{n67o^;qmdԽEkD|{ݞ홽n}b/{otp{!ЬHK _kFh*sK)CiG&86xpCNQP+ʕہLkQS寅D7H33=LD2ŃĨum9> )`;ѓj t *s ąB^~sހy6YipQD9D8&:o`-7 F*Ai+p넖̳ "Q:ƞ[%K5ivk*"X6FV@F CWq_~0:ƞ~VF_jlaAE(51T7A]<DW:ƞxC֔1K4 .1(%fDn+, %+j]I!y`6ZR>u:=G88mQ/.6\t/q/֨_OD!x[S2^^0?1: mncO˨NF!x[]]|~Ŧik<otp{Fn3{s=[$%,L6!E7S>u:=Gx}2O=d[ezsѝ7 O :ybUxp_6: mnc)~ݮ×[ezS yB fO-5/᮫|95x[s|o  i0)WDZ,u (MBs_jJSN4V *5CiF k%!86"?q1x[sרS(&| YqJ%hCwŞY(&e" W-5Ky59 Ml˘!_FO<otp{Bk ϭhPXPp>"0RI oQƖ 㦭_u:=7~V7d/>jN6ԨQ>u:=u:ƞ2jN|Qܢx[S^\F6:mncOzq5x[~ɷORm9uh~=\=I@A+ g*Ͱy+㒿E6Y{`݆7/ Ic%L2hvun[͞MeKǮGox[s?iE!% J^GDt GIZ$ֹ"|i&ss80[JI}$ {n:ƞ~VؗXN V;襢maE-P%*r urx[sАvMygȚXPûтR$lX\XAh,vay/kC*{_w@iNh'[_b|^w̞?c;Pzm9:?ϿDWu:=4@G6v/[|mncOzq5x[s(nQmQ/.F}otp{_\FNFmj}y+X~w0ix=Gn=Q}c\断tp w\Qx/O 6/1@o.Ӟf)A'#5CL.+,?`./rp{Nvn?x zS yB fO-5/᮫|95s|o  i0)WDZ,'Xɽ(LhJSN4V *5CiF k%!86"os$ e65 _kV\h jaUx-29 Ml˘!_FOQ~=x5ELV4{(,(Pa8tP D_FԷcKqV/vLiಗsgu{8qé̓hF9 +v F.5Lr C/_=`4]?FE6:OhZkf‚ױ JI8ah]$znFcK),o{> . ƞ~VؗX1$JW*qH=&vl* Uї[:X42p{nҮ)QlY+5sKP,WS)ȭlK`Rb&jb0^,ü&ipe6Cs;j} !GM$اestzڋ[|I0O,FQ~L2m9_8?42p{jԋx'> . ƞEq42p{jԋ˨Qƞ:q~0O,Fmj}w}߁7{;uh6' =wm,! &%f™J3l3_I.^N^<2'> . ƞ> {p|o{\h HǸBwnS+X˜ˋr֓`bYnc)~ݮy@O-_z.} @ 0O,Na>S%XNZy=hR+"cb_*f԰VBfkuآQ A}K*-;]<'> . ƞFB1KV`͊P-A.v%̢+Wڢ) 69[TNjF)7 WE C;(r 1A-0uгfw)E6A0조@!67:I|볓lSߢ:-e(\Ǿl"R{jz%/Y]42p{nnn8y ('aAqbqI6Z$\oMB-/؄@A撽Bv<㟙\Ыqz15s?iE!% J^p˳Hٮ5M$:5d [57P2zȃV0d`+ɹ42p{Yc_bR#F8-t aVlQ`E-P܈ - ]HVCiy,mH-DP_DE6834]ES$&Vj<4'!#u4 R噎-Yk]#,=\xo'_cV8Zjj9 -5iY= اes4qsxݭgGG[<{|\IE6-wQS=5W؍'QƞEq:_ncOzq5s(nQmQ/.F"p{_\b0O,Fmj}7Y]gЧz`<}|اes4v{7tKp wWm1Z]eTI/Ԩ_nc^ a9hq?}\f=M[ aN}Բu4̝Y Sg፩Qƞ|k@hH;L"`AR  ^W1ƅBiF k%k4Dhd-p-f jnzƆ<> . ƞFB1KV`͊P-A;cI A\loSlrr:fF)7 ^^5cԨ_nc^hM1 TA.IGOқN^`al)2r.ct5 [MoL/,S'rW`ѺGڒe.5M$Т%=ʈMU"wf-p<0hޛmu%TXU!"YأkIujΝk*$ά_9 sOr>9B,籟)<%V(,5UdiCLUH@) [UXCBjMp[A ϠF"p{nҮ)QlY+59iJ$P2%"HX<ӱ%kͲ+al,:z,X[ɲzHL.:pe6Czxݭgsי;)د|2_2{c=GG88c06eS^\:es(nOe`b72p{jԋQj\f=_q2p{jԋ-',e|^2mQ/.+F]. ƞ??Kg~GXW|(]&vqYncѨmFcO{Aw~RP .%f™J3lCJ*o~2p{={Aͽ;<  1*V<Oe`bYnc)~.Bk?lפsԨ_nc5 4|\i JK _{IhXjCX 4ʐZW <.42p{u ń/[5+.BI%Z'kfϦ2%cC6:lZkf‚ ,骐@j5M$:5d [JI}$ O{66<:Ǿ F ,cv7٢ ("%rt"1[JBUШvƞxhsdNa>S%XDPaGVcPCV F&rJ}PQZ eH+ G:۫7 _ꗄ5+.BI r *lk PL DZ7ILu-z"ڦ/G],ΘQx5ELT4{(,(PafEջabX&H=’g'5ئEu[*p;3}C?j(Wc'*h _.$t=3dN8ah]d-7 0ٳ 6{I|z=??iE!% J^7-!  X!fᄑKumv9->T#|ކ9gu ؗXWi +lkhӕ$fAJDR"1[JBU~V1CFeoiWє(y6Is(+JAneX3p4Q`fY=Cǯa}Eض̫^r;>!.Q3E/F&Qlp{N;->6Ԩ֣ܒ6v/[Gx ؃s!=5e|{]בa3=u/.VtxO,G%+mQ/.G=>U|W3mu/ōun? ƞQیyn.8꽤E.{XBc\n?%^ nc^m~j/m H/Xm`%ֻn1-%NnP+}#"R{j:>sgu, Zm`%֓@)%ѺZnbWlRILѬRIE$r)755sE$Eʅ+2$Zfn7 ҷp`07x GHN*冡+E6\!zi[d : %Ph!rW9ܾDS7S~=7 ؿ#,! hfR,UHIpbzCJ5 ̢%*آ2z髩E6$lQƞ|QJ/FGxq/ Q/.F}%u/.+Q/.F}%u/.+Q/.F}%u?VsVWr4دL̝W~^. -a98=ڳ>\eB/=AJ{vzXv+W*6'!ޜxp=Cʈa+{V헪JjorONYD"fkHI{[KjWr|o n:&ɥ?l*c \{#Y'J!;n- 5L(HԂp,'-Z~eEذAWrר :i+3z[Iчnߣ_*'׎Yr—^a{R tkYa.j\d6,iMD8N`$V@ODlߥF}%x|;‚C뀓z4R*١-WaKMz,v$N^.XJ=(C+[qVS+}i'2w% =X>7h{TأE'` "MBZԘd.* JpŎWZ*Ǯ:@|{Dݿ,ܣFs\f 퓦{A1*ev0U4E/l/*\Os]Qx}l>}O|qG {dK-6mKw崺Eg%,pMő[}oF}%Gx}ȁ$\ڡ]XlRWO}{d4s}Uxυy9:w?e`\:hG& Db=VdoS|kKQ!K3яvXQĐw<*F&yM{-Yu*줒džg/7bfL{6@Kȶ^e)w:": ,M(l=[J5xN,]ij$29J} > 'B/Q nܾܰeP7![/n0d)ͱD* 8'DWJ={,k*y#ؑ>;6բ}"HJ֎{%l5}/{vfH0)%G>HLg=V~ؕ42WmWw뫹}9*pJj#z:.ybQxtOa7Bvy-7 6բ}VMIZ]*ǮfwöM}=BS_-U]=|6rmf.uD\vIhX1:WD&ahFK&%6PvΏpӴ;-%_wDW &HOWVj3Cw VW+ ]){:L9*a}ؚ€d)Ab)UBǣ>D5G]hwRbdG^lp>$(7Ӵ}QG}T._| ?ԨQ8^G#TF~l} 5e<wmp4v:2vGa W?r Vs?0w<^;8>wQ*3Z^]C'7/h+/<6V/$R7T ؽ%6;G/c}3*1Rd5| GxWvxZul?>I".8_j+9iSs#&]a^T]ut;Gv\d*o u ^C} Waoo=?p|o ≥^[=POx=lH*y($b ׆RY (KJut564{ u>t$ eŔ90\ijk*I*s#n0g}xEZ|NqmY2I0F /قg=;rB}#"R{jI=gpgRJ AD%Ѻ6+wMBR؞[:$PD"+rS[U*P zD%ѺvsNF\XvM("9eߘD)Q_ӭֽz`w96%i_^<^+:1k'CR=3 9Y>ڧ4`Wx|Y(?jx2Fp,g?ŹoPBzqOzq x|{,;P^\FJl>9{їOdKEOnEzqԖ3.gvAs*#Di&]]_^sGܑN)=f)AgT 8d9gfhfZŊ-_^ |hֈn8;GnK0,"X`2eE &Kk^vG'Jk[p|o{(XQ /Pg*F&rw:քlHKTw`-t0ԺmnY"ӸkX҉<*( &KJ\@R p݄]+͎d-k6z"g8Y=Fݴ;x>Lra c BnrROBv$PD"N *&P{hn^6y)Nq7~VM*n- *s3kIթ!doZN;jhs~Wu6%q5e썺<ÓOq73f)QV|g^enNcl۟~ke8Wӡ=HЂeT4z W Wׅ9'jԋ8uxa6VZEUz| i^@{U^E9h7hW G?(oVΟ}6hvSWZWa9@ jCMIzq?hUsTFxA[g^hWZ /bWϼj,}Ac}"x4Y'3ef ѪM1֨B~ >$]$/Jp'YxJЙ( =ٿpbw+Xmxŝv %.-nGeCȤ] SXomrz-G &'՘!$dGE$ҭwz4Kj:?we:>PZś1A;\~6rI;pDr3d8x]AE$µnJǮoF}%3BU<jF.?$ZםD|͞@TꂆIE$냞T CWR~@@ \W0 TA]gQgF8-XElQ[“ 4A]CJnH$Z]9u*bT9j4p$0%/!2z8:hԯ၉j}f kP|QJWR^\FJ+Q/.F}%u/.+Q/.F}%u/.+Q/.F}%w`~:h/:i;mZ8š]Gm|jjWrt/-vh3k`UxŊJ]]=}&6M/ᑋP|kYXp1J-D% V,@V8L%jl(S7-t ƖZ6t*.",@aP<ƅ!VtDVf TA$ㆭbu_ɍmXI^:"Ƙ=5*GSU5+uWtDUQ0 TA]oBWC`,z''^Ahx jWrÉzI$rwZ2D"-Ǜ+9kxf k?T2jW_ u_Izq5+|qu_Izq5+|qu_Izq5+Y?м&C{:tӷ3Aaށ𔠓JNXqKJ{zh@A:gN7(p "X˱Q_^R|k!C'tvW,h$ur#aazTZ5u&(Ɔ+o[`Hk(=91,cGSГK1 kTq96 DtԨatО[TG.;NUD*!Vىu5 ]MVRY )]<3qhk\w7("R ֩rn?V,i:حF ҚEC{,F=/hvw$F(cHrsh֥y$GJNY ?ׂcaNƞ WLgB9t $% Jc ꟠F}%7`yD)I^rAbԒ%(A77r$ -6QY˳J! u_Ѩg}k}DjWrt?_;=u_ɥ^Ԩ|~%5eԨ|~%5eԨe~%5eԨd_mw ӨJF=sc?"[6$ z.%f™Jh3;䰄vcV~Gx}zGxyݧh{x:!V"uǢ& ˜X_ٻN{/F}%`1I_{ *< .E@5!#Ғ+MKPlӏ=f5Wqߨ-#;u0kB]ijTLSWp[ =wXS<aYxdk2aPWM^MN1CIȎHoJnnpc5ħQ|Q?ѨԨQ?d?-5e+|qJjԋ˨WR22jWidߥ'su_Ѩݻ m'ޙ& E}DTg{ZŊ\8+yQFu [^JqDJ?@B%vrXH*y($6|BdX&'zƆaFnFWvpѹXj;f),r@!A艐)F}%x< z4:;;Ċ*̢ggU =m5wPk=J"u.{NXql7Ա$Bb );cךuvM{oxn Q_5ؓS@$g9T7AZjWrO%GםW,wJDЀKg:D`{ڦ+ESb*d28-A)]IS}\/ X>zayn)+񳺍<)G.56wl}б$ɱ).F}%1\ M@0 UbAǒR:f瞹:m!ɲlK#KӽT b5+qAH/i^n4s;N%S"DyViٛT+9)F}%G{3qq7u__G&_wRԨQ?^2jWR22jW~z귉Qz7=x&%,yTA;~ P>?mGIV\[;6gyʭ"Q\5_%"/w)k(zjWr|o ?aTr}3&rS- _'^^) Ha RJCPlS7- a,Fo7rbJ[-Z!:da)_K=@OD7.5+9>fpK4~$bEGLCE9V{j*z??fG% I#5Lr뾡ClCD$C9t"v}jWrOq^#B$UE&U0觅яJT CW1S\:Kd2&ܑC?-ɗ}IX b8&!  nbBLJb?!Jɲwk8+9U<06['O] iԨ_RԨQw<_JWR^\FJ_\FWR^\FJ_\FWR^\FJ_KJF=c {ئ֝_ᱷXmGIV\[٦}֜NOj)Σ+jᅫ7޽Ay 8{⮽TjWr|o 6kQ0qc0LELaa- 0CD!jl(^BWrߨ`a,Fo7r|.Z,pfx5+9>c\#RF*  _UamÇ"z=m5RYݞ~̶KGWtUX!AF9t"vQ[G% I#+*mO -9<9t~Vg"DТ&_%*b&WQx4HٔHg l5lۆf keޟ:hWq 5+9:ũ~%5eԨŗRԨQ:QԨQ:QԨQU^lzuU]KWr4F-3ǵ@# -a9g*Ͱy:#\/'ꋩQ_^iJ @*]u՘ N=YxJH :dUxeދ:Q}wmїuaib,"X3u4]a:;/'᮫5+9>>U&0\HxJ`pWUK"kj"7wJ3jX+ _Q?Y8 ndeD*.,>:Q( I= fH+W-c_&6ZTěRn|-{s;$g LDygjWr|+Ė ȸN 耫lĊ b$NjM}02m+#9\ bp}[MoLWrgu{G+y xW*$$1u VYMB. |?TFl<85;Õ`/nU$24]MJnW:: z1lb}ѩyIƖ2|=whّ/Y7+~Vw RM,͂%֩`E zMUX(3DNuԟAJnYx ^J_| u_Izq5+|qu_Izq5+|qu_Izq5+9.3z}ly3[JF= VuF5H @7ݨQ_^K @*]u }_Z\467H :dUxe>:Q}<wm΍]F43m޻uv^N]W~( P!3]ITƖ2|=whّ/Y7+&~Vw RM,͂eIiBhg.("8۽QT5;-"g *b&83@pGKMyjިdGT,sɚ%m+ Y;NKaPizUZV黨JFCyfHmذ{"'S|4@_8u_IkQOԨ ŻRԨQ:QԨQ:QԨQe~ z/.x ?u_Ѩ_ӜmuٙKk*&|qp=Ԩ7[xgzQܑ[<M"HHsl5T\EL "E˻RE D B^ͺyap#+&Rwa]~%,>nG!׈+mQ谬J˶0~r<_K6ͯs;$g LDtjWr|/l鄅pҋ%ha0TSo_9Õ+ط~%7~V獏_ GpBG8&_}-bǛ}R'|~HW "q|jWrvBG8&_}-iE#'26:fGr d݈F$盨JNY=nC+LBH wZ˾$1{&jvZDU:MP5+qg\ۂkќ{ة@36YEbK6Čoa!+v wQKyQj=y ޸oQ_x|/:F5ר'jW_u_Izq5+|qu_Izq5+|qu_Izq5+Yv?PK+9kݗI/_*^@J:1[x{w[fUnP,uo{p.]{ UԨ8$v,D;}VKa-rYU& Y{&:Qr; -eD+VQ<tB;xa#p}[MU~%7~Vऴ0 ?3 }xUQЉ؅Rn.VP[Io;tfaVoO -9<9JVO[ %{Т&_%*b&ԨApn NrEse)ŖfɲwkXCWr4/䩫!jWrt/SJjԋ˨Q_ɲ|{~%5eԨe~%5eԨe~%5eԨ 5F\}/~:F:F:F\}WM[{^+UJG) 病3sp=ԨsPo==lNccy AHڽC{ZŊ\ؠ+9[#~3m޻uv^N]W)6Q_>i9ړ)+%˼)f԰VBF~z;lqʪT]X{jԯ{@)' - pܠ:vE)7 kM3z"l7ƺFbV 4RhEtp%Ċ=m5GrߨH -=^Ii-=ʈMfGrŭDƱyp£\EIeXhl)sf[Ju#!QǬF*nk9 z`r"1[ ˁEU"}"֩nxL Ԩ_GWMy6K3K*D#{hL\04u*-T_Y,bS(F(~ 47-EQ+{1EԨOP^?AzQ5EGR]ZDG]zF,Tu}.:YEqĭQunPqXλ~ݢ(}nm穣ީw%hEQsˈ2я[PsxҮ(cS5u4IE 6 s <Eq'Fr'=thD)p}0,b:L>ZPHa(c^;ta"C5|}+(=["  JYH8(5 (2m0uBÅDpQB(xEG(F(~ jԋ'Q/QDQ o^ŧP^?AzQ5EI_so7܀kF $ߠ_b7/P_o~5B}OzzFFQ_S^ި/Qr?Zr7+U/[{_|>,׌~W{ſ\o_ף˿k/+̑G}׻F,o~-_A5,\=QC{t\h憗pW_y/Q痣\~}P-RE5,$%ku5{@ g.%TJF_*-?-Bhԅ/BQsetkp`F}ͨ+'݃$_ţ^;z !5T7 AF}F]x F=e_Bf5Sk)xW~_;Kpd k Y\=:"׳fWS ͝Bq7ૂҋ`_䘅 _\>k25fѨ//^|߅uFFQjkԿue?5B=e=_u}?_Qo_so7܀kG(F(~ jԋ'Q/F(~u{(6mn?5koIENDB`stella-5.1.1/docs/graphics/rominfo_1x_small.png000066400000000000000000000461471324334165500215330ustar00rootroot00000000000000PNG  IHDR"p_sRGBgAMA aPLTEB1JJ@@@hhhkkk)1bkBRƥ94C!ZZc֥Jɯ|JRϥmf pHYsodtEXtSoftwarepaint.net 4.0.19ֲdHIDATx^H]YJԭm?T^`IN>b'x摕Uń(ȿEJHQlR#RԈ&5"EIHQlR#R_{qFw _>"k TrA0=zcD eؿ7#b!l{R䘻cexiOa$I@z{}uDcbK}Iy|_H_2^ %0@&e̋D| E_׌>:{$͋y O{EՍ.$:!rZzi1ϣi{b멧xD]xw;rI3HY miA֥A(6#|8XB rtФZw}%^Ąu57:vz۬ 4S3x96ဋbZ1܋J0XjDd{e/}ZHKD`f`x/!4Kg3s22!:#:"JhgL4ZWKߢ>^6:^@SZY7;1 YԈ\w3ј c:ik H"fڦ {mi&LΠ= Zh̳_%%\׬Ҙ 'v > R {A8i]Ө֣|u.\zNz:oVjDdkU| yDju.5"7FJXhS,jDn{`5"Вo˫_uZg>`׭cdLZ9._"H-esDa:tu* |QaF1!z; jDdkwߌIt?u* %=L$BJ_"X\Ҩ8]d]ٲb3r͇

?E-dﻈ h̄Vmsrc#׽iLVl1MsALR|+^h5u$ee5k>gݼŵ@ʪG2rqpL BاuQ>F-dkD壯Wq'}xDtfml-xx']nc)>#?|m*> -<51S#rjDpYۘ .pp3[#w} װË@FW1=kDpYۘZhY}x=\gRo^I I4;?jbX.pp3ok;v،kDpYۘ\hI%:xޏ03=h֥~Au>_sbS>kZh 1w}T|^1a]M(ō2w}saǎg戧Ygi:u0n @B}7.pp35"#7]h}\6f@1F )yIp-,xAof8_֒ДS/r]m0jDpYۘYh٣ΘPiKߢ f{e܏P3J)q*1 [7ӻz e߬q{>R \6flFc&r c Đ D죇6u.R#89~ʲIFdu8VCmk̵,fAzg?}@X}dD OߌK*Yj5:ֈ y>b2"ZMH٧uQNFdu8֣ʗ|_hMpYۘe.pp3[ KVH.5"m*>6mԈ܀>:BK2Tgmlc?o׭cdLZ9._ WKEE:뵰3aCdo_TDLH=kN?bD 7encfk|o¤A\bR2DriQYo?ˏ/8:!7%0+>יKub=b z}~'be͖@Xl>_~xĈ|4 n:#EDŽu57:B*yJ%Є>%A˓)bXVL2; (w]du8"v3PEBJ^ z{=M Y_-J`^B@a9?`D:7encfge\;cBB^ 7"jˎ!-LˡnxK}ŏ/zo|7encfﻈ?f4fBz{!mGFDy$w t]"͚j-fc0^[I*#encf{#w[Z )s-K,Y#uA}oGPG2rqpL BاuQZ6: 15"r~pՈ 1z( m:#R|?`D:7enc戅Va~|n$!!G`T[5B"`4n<76ZE.pp3 -5o2ƸCYi4-[ Cv=T.3d?ВA6ml431q=;carPTpӶ.sb-0o[Xencfk]c zzqFBQ 9cL yzEfz.GD>C՘Wr<&k{?XMPgrqk}󴅚s1t5PWZG@~ \6f. ,Hf`8HӸG!ĐT".pp3[#(!Ns.pp3[ h}?nm2"genc戅Vaj5:L encZ7ZmleqfǞY Bvz^|.pp3[ -}<98g۝09Bnj(XKi+ۆ V/_hF$|vy'Ymj}i!3o*.xF2>ncfs% bn3Tyu* '̓hc u6!ǍXV3O<Zέf C?cWZ ~#EQᑥ 5yIܟv(0 :~f<z;2pŽ>5"'ۘ^hǖs1NX tNut4Ӻ! uxCX`ul(8neӜncf终=*l`f{^ rн S_3ӡNs0y1<9baa54 .A1P=9 wbx(&y {Ld?ju#ZGNc\:pB݋o);h >t(^o0ۘ8z͋9J?8"J/7epml-[F" M2p38"@}9 7.728e6fjDn@I6fju>:/\ncfkD._2:g&IWo<1t9ml-wˢuۢ`_<z@}Q0[U3hNXha.1؈<Ƣ]MG~D ,X?| jDN1В1p'V uz!^F4A0eսs}ky\pB rB$p3}[N߈5Ěv`/aXn1q-nI+//Oo0ۘye|`F1=ē/' vDt5"'ۘZh#D7zzi,jdTMQ m<4"O{'V )܂yҪٲGisy~8|ϼ-B rjDN1wn oB[^v&ocTm3t)n<ԓÔECaB 2p3Eo$#!`>B`^=dž6Ca׃N?m,iOM \u[,Y5mz9멚[ֿ ){8e6fؓgߟ~/:tӚ5AEA[znfy6z9{՛I*#ﱎml/}Vx̑פܼfym&\f82_3Ȩ׏I5;Xh-l@X ֈ{:s~`D02p3[ Kxy'xWl pmԈ܀a.13_hXhv 2p35"7' 0pmZh(Z, ֈ]F#l#Ce}dLZ=ƣ`H;^5A@ }3j%7[6w|'ޫ(ncfgeLJr0 })q\&fͨEx=Vswr_!@ >q3{Ej& 5ϗ `blǰ1H*oF䑗{ow}B!FYCxi Q> l:o4"'gMRSf1y}:.pǴH"/؟ȺdM#.7]hmuDֽu֞YA;ƍ݈MF5r54ߜ؞}HPE_8>rX҂\An:4p3|WP^Ř%N L̫mc@(shD ncf{e/fab0fͨo[huop3;EII3p7X-WSK[m}7*<_v# Vǰ1%/ -  : m̼u]Ri Q> -5E,TX%o,7.2{ţʸoncfk} " mߨӞ nc^#r[(6 ncfkU| ]h_vFTs7Cz1S#rnu9zM6fjuz%4_Ji1S#rȯۘZh]FICZ8,P5a,&ÎnO-څ&I )l@A*19"v[az? XQl՘BJg-ԇϬ1FMB-Z)Y/NI6fZWhE ssh뱃+D tݢEj37xyU<nc핳0'Ce]؈e[ yi+晁\xZP#rG0SDѥ^KruUVKq3KGvy GQB$p3El͌ނNOEzK3RAN+uŎK( 6wGI6fvZaFoANolDqAO-L^Surfb {~: wnb#s߀YC_S&ܲI{]`/$Ԉncf{mGȔbn%XDs)y-qF-N15"Gg~9:)>B0Z< 2"{Ԉ\ Mju%5"7FJjuju%[#2=Wnm_^ip7xq1i,o0;.CQ#r%[ -}-»xMeE5/ DŽfSœ/'뺪bfE- r] }wH:%mϲ~ÿKȕl.A{`A:uz3u)zbxx=8l7y$_hA.^@-"ȫ Hz'^N#!g0t)n<@kVx򪇾 < x|aH [K6wK-d终"0 bk@d6QJf:P(f Kȕ}7i7 ^ҮzO30Tq uN/֯_b7Q +y 2[hG$Xy1>@Rf/rͷH|G-\Dȕl-<.9%ԈE Zh_BZhK Zh݀Zh]I szu-01){g8Zh]H;^ϱ.0bC%[Ri7^~AFlZLY/՚PRɬy/ZWЈp! [w0uf海4AXG Z/"S#r|W{ԛ~HwnY1G,G6E8_C}"jfNVHBQGXJQ}7~e%}A}:07l᫧yRO|DSN%+-A}"5C?2r .}zfRø+T&gj?x~/6Yf. w/F[$eUྎ"Il}9{r+Zh^\#R ~{<|⌅V&^I Zh݀?t%[#¿ ybw;Ս>^Wj19>_#r%[ -';"}xecH0 }bZ컮7jk=Ebn+}iZhˡ#2ܟJN0߂7@uQ8jk=EyFZ6Z fhaz^V%mOw.iЬK\;5~rr%2G*GޫZҐ0GgdF;ٱ& i+Y$9Dpw^y0uU.P\GnL'Tq7B,7,ݽm1f놁u[} (֋y~DFuYFm6q by4LON`{eW.LB y>m.&u {~ r=ff JpaT.Bk*05L%l2"RR:`Vf?5gP-f^iV%?BkS/ aв$Xf+E;PT9i`e4ElnuDyygDX?~f#2~,*B8P#r%o-sx~UG |]wм8ӝ/^'X2[hɇ\; fO"ڳyKiX>Mh0lb>v -ڟ)?ᠣRG=V5Cyb-4Vm/V嫊yhDu[l>nf{[o][G81oAU[AEI5E("Ksӳ|ԧW=#Ej !L@8 ُ*BqB<|kvZz_4tiHѫ R5:f.QY8{>hd7]ĮS\f1̻<0n*:xlߝ|zI*VE5gP#1JM6We7 UGߍ.DdC!mP\L|Zi4]%fb#:+ve^54VQcMzrp .9*5"9Ԉ\; $f -{<=z]#J+ָGF<="mWnEy/.kuf B;iK˜﫺ɏP@yqF&^L&շQ~܇9#,jW6Ng 0xUI![ -|fQΐnamr&QZ`c^Z/B+Y}agW5+q~c>"'G5sD XZȃ#^O^yf;{v qsH1H-D~qW~ͅ4(x]35͋F&3c!+- /gam@Eh;b+f@"H׳H^#a8+戥@hi8 وE_I텖.[=i[ aDYi,M~|aԆa?΋}c*`终"0ib@O@}i "[ĸꆷ_cf:"KWZΥFJ EГ&Pb"Md]Hf`K~OqO=LՅVq|]02^̡CR)Og o]"[;K"dҦ eԈ\BA3[h _9I IyyV%Z]Җ1E43Ԉ܀oƕeju -)0 jDnwiA= RBKtzgvvQ~'..#OiUixJo-MclKg6"S [ -:-z7zZ;CxhD7{1{]35ǎorH-A҂\/Hq|WL O\"M%>zf#PGg醼*aHxHzꃷHb %mA^:aQ#r%; -{`-Ā4-A@bMd䕖{0[hvv Sh"M I(o&Jf-Fd['ĸT&wVZ } ^oY9woG:hMEҦ -mq[#r_~%!l-/ac~]`$t*wIDZԈ܀"}D,ͅ֏1_hd/-~H Ȝ㨅 -38h'sf /&cxL?vfOS#r%[ -}\Tz^K"&bBYECmmQ[I7g?*1zlKbM DGɥEydgQ[I7kDds% xta!4`̾kz4L̋h,،bix`Xj=3?ɏKdt ?X#AHSnbMJVCDB1<]7b,0%)xiFX1G,U+&V{Q K4ֶ3\a@#52)In *1m=R$W!YFfw -;Xn,3Mr,$7>?Zh,yאcU=q=aZՃ%6ĦKvYEOB{ QQJ:UP4mOů_9)z"va F\X<71Ad_Yn>C7=pxōܞ%=4Cá;ŦC Y `NLWĬYNSؠŇ" AD?"ic`uJ s!gXC* 4[`S\aQalsۘ+ `k2l-+629mk761bPzo2;h&8F64dΞ-@{z>oԜrRR#r% 5 g(B S dQڈ]Pz3ԉ㼖\6wgQ#rjD ?yZhM Zh}ZhM Zh{6!:P#r%кYBdjDn@ȕBֹԈ܀{q:qrq=o=c71iV[qo(25"EIHQl[dQ&zwQ05"EIHQl="n j z?c4vFmD  E?^ QQlLQ[{(4&K/:qDNN-8y<[!n"|Gs3: (i)yaD҈86kzC<>5"f3hs)`1-h![rx[:vFAoLg)HňG.k[Eq#2"NůqůQ#R0"7şAHQlR#RԈ&m# w4 |ň|G_A@#!h%@!/>ķP#ԇ>>"3~>qbrg9C}zDo?`Ęr؇X\ꁏC1g:eDqg܈ONs∀|F3Ba/{#2\}9/P4\.rG.\]\E ]2>:"~yp"-P ̏GDϢ ?.#/6+P#(,FD] oQCO\ r"-P Xs+ 5;O^r3 |lD/8~Dxb<#~pv.ƧGD^2@|b ?qbqȡ: b^xhIR#r{0|!G8ՈD <RC| [Pr~C #ۂOЀpG >A'XHQؤF(6)MjDbFUŒ6"mPX_ۈE1X{IENDB`stella-5.1.1/docs/graphics/rominfo_2x_small.png000066400000000000000000002130001324334165500215140ustar00rootroot00000000000000PNG  IHDRx8gAMA a pHYs~tEXtSoftwarepaint.net 4.0.19ֲdIDATx^뷵WU S%|9>9IH(A  D EN*"`VY-wU-ժi}{{;>ƸǜkkW}95{=/~B!B!w=f B!B!3h4o `i4`+A  24`ۂ~0A;*lBa?aۂ|* v 0hmANà q 6A!kfkRƬoRWl  ;A \ͬZ1W;(K/0hgv >NfA墢L/!>^';heg%0ӱYR{'5_mF=ANܠAgU1L#g3IcK#A:| KC23{poMnڻ+l79 v% 9[)FfgƖFjlû| 6æ^M]2Kt,ANĠ(EmV{ڪ؆w5z YZ )e2 )aLA!CmƄSO &aа7h@䳁ɂ֫)U(Ġ[:^>`v ˜c"=c•l`Aǩ{z|,:~(iLؖYV0I^S" F* &ի/Kwq ;L_ZP_;S>eVi28r*;,Yl`sòq9>94R9QP;砓Z}3I{K1[4=5aаӬ|Аi5R j{x9j'd;>ΎXr 5βb_V4|֊эA>eEgƖZJ,-4JytRϾw4β[jYI444lƖZJ,-R=Զd;>ΎXR5eEhgLלI[jX64JytRϾw|4CY#ez`аӬy3IcK-UH;g;>Ύ4䃼ŲiJOM&k$-TW,N cq:g;>^!˲]|e-r44+4d;>94R5_lZ}8;>9Aq ˆ)ep|&Wz5gq{iq:i7R/sЉE졽fq'E|e-r44+4qv|OcO8!9m>h,ʩ,Y` )aLG  `0h1=hϏy@LLLLLLLX8Lt 4B!BAØ@!+\A Dt ^!B %,X mCn<trCӏNCt R^`Q=em2 ;=ldGZ EY!j)UH cbPH cbP1%(*F[z*ʖcUGsted?7korxK/ `QB ͮiР,%CVH/ }gQ4x7}l vJ~~>!8a,.cmp}tB\QqIcK#\79>ΎkN줸7KES=9=%{p,ҝ[:E y e<:(2h87clzqͩf38~ch 5ae /QܛvdY06( :JG=:e/CcK#诜wR,Ȧw|\spjTj*mGmj5PiA5_ʘTU9[s,@gL )X"@!LK_z UnhvG'A() )El1E9Z5Y֛"cl],,;E}_Zd/-El]r5Vz r]KsD~TT|FE9"Z/KE_M_Z`XF {4AkNTj{qv|\sL7 4%8rid@E%٩ѮYQTvj+s樼igkvU,S=Gɾw|7*m4(:JGytB,ESg洙,P|kmڻj8JS],NG~pғS٩ѮLdAڮo4 rQ(q5FNUamCxK/ `QB .n(gLRӗ8;>95ޢ>6ȕq&g{% KONeF2gkF#5Iqo4 rQ(2͊v kHN(:JG4L.S>.DlHeN]}gF\|Bv2Z )4>.:~Ŕ"6>Ύ>cÛ>nbJXj\t²@0})1hQtqfWwL5dyR9ˢIب,+5WĠĠb*Ke`UӖE֫BJ*,:fj)Cʖ-Y5z*FK Lg*17?A1r;eY+.:B~CN-DG *74;h9#| i,SDrA =:'Ll7@F2QImR1ly i,SD4($G' )ƿAxN)-N0L4Z"8E,;0I X X2L4Z"8EA2Lxtւ4)"eߠ IX X~`'& +zt"쬊sev6N-|mζiՔ*11(gKsjX Rɬz*11(X2L4lQ_|e Im=>Ύ3l\ BjLXgi,SD4($aENhO,*.(h87*W}b(ꋂ/j{chllf 䴃= +|w|l_N)  f̴ }ObIO6c*Cm}lU>mSܛvd/+X~ZfIJȲ[!'keV(XLRܒLRܒMxұ H5~N{ڮg 䴃=8s?i,SDxt`G& +4_2ӧ,2&J'7)U=L*d3;d3;d38~8H5ʾw42cL<6dAڮ{b T2FwPW2&|U5Bhgk.Sz|8LHc"RƠ`G& +}tx/-Em`9e dǝLn)d;gY/4q` XdYo_[z]q*.ElL ~X#ː-S>6}h,ʩ8H[Ri,SDra-l3$ak 55UH#RaYtL I[I[4%8r<4R j5ީ*òddA.TrQ(㚣~')fuN) u=:tqͩa9A5Ni3Y_,fv&)nfv&|بmj Y[,(RUFAN8J{%qv4βb7-A;JHc"Rƣ;0IXNל;>9 >|\sZPܛG~p²HmS[4=q8JAg'o NXzr*;4)"e vaG'qͩ+~G > /q1jCqo6{% "vMqo4 rQ(2͊Ys|:X~ZfIRceJe dòƮɔ*zhlԔ*zmL1[4"SNXi4Rh oʦ)Qcq ˢQ6kN) <:qVl;bF .MԲ*'e`-YŲ`-Y+cbPHyrAv#ELUh*+ri9a,P217 0&UNy'5R2i6xp EpHN($aE?i,SD4($aEN N)~84 ySK~sC@? ΎkN줶>6h.A>;>6/i,SDztB=$ ~#_~ OAⷽCa!'?;@80h&\0I`d8ŽfZɦw|לIm}lU>]|w| Hc"RƠAC?=YG$Q4灯2\0IXYb!Y~!>|rc qԲ5MmW{u2} Hc"R k92q&1h-40hg& +4C11(gc"KY6vJiLn,d38~L#H5ʾw42cL<6dAe Y/X4)"e߰#3~OG v  q͓}߽O /G~H@KW0ho9\0IX Tp|lKQ1&ev²eSF͟drc,M1WvFmW{#KQ10=%,=!KQ1 Hc"Rƣ 譿܉O g5?q-/M@KW0hKa8;>95+rMvR٩=LnlhJdqH86R j5ީ*òdd$el3X1h`РP$9wwsonj R>7 s& kytqv|\sjLVjAP.P*;5ɍ/qԲ5MmW{CSA!k"5 d?;ی4)"e߰# g݂ArB'|qw<q{,@gAxul U 8;>ΎkNve8BN{Y×8;>95l8JE5l%8aɩl3X~Z~3I v  ʥ7ě^#w]K~; fQpypa G' 8;>ΎkNve8BN{k`2g5fvRܛG~p²H'+fq&gHc"Rƣ K>)?OxbJJkE/  щACX8;>ˢS]myY{j~'}gF\|¢N-.:aYQH)Z fq_c@2  K~ē>|r&pypaW{QsTWĠ췝Z`RcʾwZ^QYVjA!%AT0 ELUh*+زֈjJbʤ\}GoXˑ'# AW& +4"8E,c #  OcǟW'(z4s:6IŠh#EpHNr0hPz~Cs^kn|$(z4_7\0I`kA2  S.'-àA5_ʘRve昂oˢS3'ըє*1oh`FAmWkɧHz D>}Q1eg.:~heFoSۥ~V(XbY3lFE~iY)KxN)34 Axk`Uzlqv|(NZ^ k|\sjBN(39smj8cY jLr}v(X~Z~ۙI v  <3UqQ6ohAOYeѩR<39smj]+UTƓof@"8EG'`94{`',WE8 ~G~v&)n)Fz5f.JN;>w,΁hvRܛM8;>hF;[$oNE2  Axzp$aՏN "Z# ~P^qd?;M#gS3-7Lzxf'Ž􎏳8H ePN)34 Axul 5hȎ_ؖb68>6v1; _j,9cOXj, Y|Bqi,} ӣcOfvi,SDra-GF$ `w& ֈ U}*cbPH)cnP=,3Z`RX`q4øaPx_ pNXfG&u,[,-EFv6g(X,`~MaA@i,SD4r0h y ױ1LV@i,SDrh9Ƒ/CvjS|Y%;5s,:tl'X,` Uai|꡸=qi}3$-ā[:sKgv"EpHX }Q1egi,SDra-Gf~1h-4A?_i_\(Á  }<|gaG'AS3e46R43l gG5>+57 *rlKQ#"sʰ4:}qK{G䗖V̎_t*Z>.:~heFͯ"Qei,SDxtA;o-K e{8<ΎNX.Jm^ k|\sjBN(39s5r}vlX1h`#/~?߾^4! R .\0I؅G'_4;{}X.5I{fU!%6yWv8;>ΎMgqL hU,^ohAOYeѩR<39s5r}vlX~Z?4 `QO15j ?~iaAO1ovQFvM`vS׆>ΎlY\,˦w|,xB4r;>95sQtq&gcq9b$ K TlhSg"w|]̟XM8;>.2Y0Iiw|\sjf%;w|YXO44+f7 Hc"Rƣ `Q4zHAz:6IZ a(jN revjS>*-_BJ_q^NjҹXƢbvrxr68~Ȳ$~==Nc(r`d'cOfvi,SD4r0hEYtP.x4>/laG'#Y]z5R*+5> {G,+e!ImoW3V|k@_ZR˜K/Kik6Ve}Ŭ*ᜰhIblA5߫V}eL\aA b]́4)"eht&1h-40hAx>7& +zt`pX"8EG'`94 xtBagul  pHl6| p"8EA,XACzp$G'26N`SfPHbN)F# X 0hχzqaւ4)"ehH`1h-4}yCoz$e(h ʱ O=?\0I X X,X^wۇ?/&H P@c 4~ul  N)c宗o8h˲{IJ /t`w:6INZ"8E,c # XڠO'Y}/ wcc$0h EpHY7-8G v  (wU ~Xkj9L0h;ul >:1Ƀ?[Z[:%{ 2A!OخK/KMf =,`Hc"Rƣ `Qz{텄E_KU!9=,7'>^18 -$X-X1h`3,55&4c_{eaG'2U^d YkOvO~ٙ%qͩm:t,4)"e߰#߻f݂A,Jϰ|/_s`|:6Inz-_"+dC~?Y?=dglz5fYX~Z~I v  (=Â;_WO]J  ]7& +ztB/c;z^E\O;ZZ=m`wUϾw|\s_cz9"8EG'`94 n_¿ ,&4޷omGZ-5YBJgkʚ# YU}AzlͱXR r}Q߲> ~^ے}(5k Y) D> Џ4)"e `94Ԇ?o +:6IZqK{G䗓4, W/5TKRT6L!ѥ-m r܏ڮ෗EG5^䗖5",@?X~Z~_I v  (wU _#{I5)78IAzױ1L2hKevғSqkN Y+Ύ_8/~G~pғS٩+XלNXۢWζ7Ѓ4)"e߰#ߔf݂A,]/o~ HY(ȁrlxC<& kyt",}lˬP`KONyGPSVYtjJmU,t',= eErw4 9qgѽlv_#g@X,Xo#oy>"QC ,l@96!Ax>Չ 樲@ Lz5Fێ*ld?8ai&{esS#Wfg▢ilvjf%;fvz"8EA,Xo-WĔ~ԯ2g}1lcc$ sTNQSq&gS#WzmG}xrQ4RqƲ9qͩ+3IqK4r6;5Ь(m@X~Z~SI v  (wu |z <7 I1hCC}ZaAq=~{ɩ4>.:~Ȳ repRceL!~Ŕ̈́lX6a8 &>^1; ˆQg3;=Hc"R rLbа[0hEYtP.x4>cc$ eyߘLr;FNS;7X5re5Sє),:fj)Cʖ-0l)cQ꨼ømPHe@^ł`Fv6g EpHNr0hE4G'jKx4>K{vaA@ i,SD4r0hEa?cc$ X~r#yĠa`3h Ax^ ױ1L4Z"8E,c # XE ~$5cc$i,SDxtA,JϠRa~Maւ4)"e `94U4<7YB |^cc$i,SDrh9Ƒo~vRT%;1kNV_+X4YOh=aBoXˑo3AnAC? ] D{ģ /7M>AmƼ+8TS|AHjRƘRvOjH+@S|`"8E,rdAngp _/'I1hCόƣť͎_j,)h*>c[fYA-l % $aWXm_![[ç|Im9MES{F"Qei,SDxtA,JϠŝ/+Y~z?npbZ ^2m;qd;砟vm ZQ6zk f ԄeJ%g6#EpHX (wU |~B m:6IlNxr68 *Vv:Jcqioig-[e5_lP.~V(kP*+`f|W*>;fvi,SDra-GF$ X*3|:6I |;Jcqioig-ӠVVqCK9fƗAg'oNmFoXˑo3An(dž:0h;ul >:aGr;>Ύ%ޱ8E–lY\+BN8J_!ԥOqͩfEl;fvi,SDxtA,J/9P /t`~Map >L堟vnXkjtVjSmǓNf qv|lM=E?fN)c`>4_7\0I؂G'liRǧ49f:S`N2Vhi6+2Y:@S#% Nް,:5Sє*11 f@kDlg|֊6#EpHY77ÙĠa`0 sp$aE6X~r#yĠa`0 sC2H@i,SDxtA|0h+2O40h~N)c`>4Up$G'`-Hc"RF1݂A|0hϫp$Ai,SDrh9Ƒ{oaA^&_Z;[vYI]'9 Ko/𱡦*f]4)"e `94 ױ1LV^vtp|<sߠl eA'>;5tR<3\0Iщx>AKRm|U;9qv|Y4X`"8EG'`94XvrReOY!%"KcbPHMRە}8;>XVQ1p_5EŔ"N)c`>4p$aG'KQ1XSFT|Ƕ̲[KI®4ھ/C,:Oږ෗qF" Y[z_Z(jҲۀ4)"e߰#f݂A|ˠ} `_qaAeێg}(9觽-b[,GxErqvgM^}vVVY(5FN"EpHY7跻Ġa`0wɠ?cc$'gˠbed;砟vbmXV(gw|Y(5FN"EpHNr0h ycc$lqd;砟vHآK9 :+ke5_ȩG Q:aGr;>Ύ%ޱ8E–lY\+BN8J_!EY8K{jYQ6N"EpHY7跻Ġa`0 <;\0I8twrO{K;[D|,55:+ke5_ȩe'yWv<9>6TP -5L{~6YN)v74 Ax~s?cc$l4S3U)sr0Vfd'y j4 lЬI_l'aoXr;gYqQK|ֈf"EpHNr0h y݇2hh#EpHX 4Up$G'`-Hc"RF1݂A|0hϽVӇIX X~r#yĠa`0 xxuG'i,SDxtA|0h&\0I`kA2  Ax>xI7rSR y_cc$Dp|=tBj<٩_)}X~Z~I v  _cc$wРH}ϘxTUFQ5>;ɸ)hw,@)_峡 &ʾw,@~ȶ,eAٯ9k R?f^z_TLY Y]GoXˑc# R] ]㎿t݂A|'Nb6;ťYؖbM.NveGqKwRے}h,ʩwD~i8/(Te/- Hc"Rƣ 6Kw1w?'rAx3ul e,veqi^F8gz5R*+V}8;Ⱦw|s⚣>;fvvi,SDra-GFU$ O.$Ų%"Ql' ?_ovt g򎏳Ove',b/Mlzd5>[s|sS3-7Hc"R k92r&1h-4[z<kxW]}fB/K_, ^!􎏳S{gLCl~3;4)"e<:a7oyo8rߵ̈́./^t ˗(X y4\0I8ԃq^2; | TpN 'K2X@0})"EpHX 幷|\Sr>?z-~Ġ0hX- sw0I؂G'liR'dmЬIZAN- m=BJCe@^킐WMUk㶣r "Z#f;V\tvi,SDra-GFU$ ղ+~˫nE{bщ gYPɅ ױ1LV@i,SDxtAjyڏ~^K?c ?4灇_cc$0h EpHX zcΏǟϋ?y'7 kAx{ul  EpHY7-8G v  Ƨ[~/}՝a 4l yG~$\0I`kAo4Zq$04 C'F^T^:X _}jaN) X s#/*/  a[4)"e `94>Lxtւ4)"ehH`1h-4}BHc"RF1݂A|0h/=4۠?:1N2d%%Pf3(VH/hJR˜RJ-Uxj3R,+ѥ EpHY77Ġa`0 /ΎW.?Hc"Rƣ Axv t23Uk˃`Gi كO .UfYMBj]łlzqQj~ƮFJS E?Qj~ڮ{qJ2XH}8Hc"RƠA|0h[?p$aG'=M䗖=ᨰ4jRzǝLnx_cQO5Gmڻ4*j˅(5MmWM't)*f!EpHY7wĠa`0 p$a/{O1U4 Z*Y=+(Pf3;m&YܓqQj~]ełN3;JoSۥW;Y+n_Yxl8LHc"R k92c&1h-4>3\0Iщ"ŲihVR$<]V̪LO(2qQj~]RA5fvߦ+94tKP.aB2`0 ï ױ1Lvj كrt.+f梴igvY=5ν5N줸h97,- KONeX1h`0 cc$ ;Fh>ビOrt.+f梴e&PܛM٩M#g2͊Ys|aBoXˑo3An`>4=#:6I  䣲je']}jBJOL,kw%Oz5&k@͚"p("8E,rdLbа[>y)?i `O `oyǯ?5\0IXˣjߖEg99Y9k|WYVjA!R5Q稩jDS&͆CʖK @zGbq |:ŔIp"8EG'`9￧_Z /-K'G{˚ mN)cA>;< KUaG'Hc"RF1 g4AO>/\0I`kAo4Zq$04npXw.XΝ:6INZ"8EG'`=;0\u{vaւ4)"e `;fwl+'Bx痟cc$i,SDrh9Ƒ;>8X1hD>[y~ |gul y(:m$lvbA6ek~ڮg͢j4)"e߰#ߦfX' 7 0ױ1L5hХ̜Rg1BVJ;ۦm0X3l#ՠ+5TETѥLcL8ղ7ܠ5t)d=b D,4)"e߰#3~oG `;v ~3Kul yK ȆTX6Lm6X+"zS}c_QەഗE'P,fvL>4R5–.E,@?X'N݂߹+>AgzEhg۴ &76 4%8rid]gxǞ_43Ųlz5GOPSͶЃ4)"e >6yDUg;xbs(3ul ((kFVSAŚ`lvŗxjٚߦ+qɚZ}i^@(kR薠\%AoXˑoJ3i /{m7=ByDU0h, `y^cc$!٩F;ۦmqͩf;>1Y(Д*FS,4S3- KONei,SDra-GF)$O.p$aN5ePf?;5hg۴m{k`2g5fvRܛMdM@SR)OkN44+fq&gЃ4)"e<:C'κcOx@rIAfa}zCa%٩F;ۦ򾏳( Ot(lff q^v:-e/1BHc"RƠ3O.,*~a{`аY4>Ə zf5ʊ`*2SLzmҤB̲P}eL )aL *ᜰl8&RĠehf5 )7,5R2i6xi,SDra-Gf4a0O.,*~a{`аY4>ӿvWaA@i,SDrh9ƏH>?o|=Yʭ[/yVÛYaаY4>sC?cc$ 6X睟O~ÿ7)o5y A3o:6IX X1h|C?_H* "%%o5y A3o:6INZ"8E,c ̣m4>~ĔX4w=àa0h}c:6IX X~r#y̓m`аY4^:6INZ"8EG'ï ױ1L4Z"8EA~G!gа~4l |^cc$i,SDrh9ƑΎWfS8;>XX1hAfa̛޶R/c;L|ǝ$ۦW}U1Us|לIm}ɂf'cs` Hc"R k92-n&1hmAfa+6ۣzEf*N~l^3-d;>ΎkN줶>drdAMm1"8E,rd[LA/~Yo )P Afa\:6I9Z淩~v,Z8`SHc"Rƣ9w/񊀘 Ű4l lˠA*3sJ՟Uģ Y+6X,fpEj5MmWk, KƘpeoA>igk.Sz|X'X1h}xkbJ*F`аY4>3A[_/c;:,/4RB#Ra0dLnx_ce)~QH5~pˢ(d3;fvj}RTzaKXzBJb`=Hc"R k92=m&1hSAa0h}f/{r)+qlɍM,{hgkvV\dV}{~˲S1YS+=m+E?qQj~ d?;s#EpHNl  A3|АL 6|\t²HOMlz5&kRHyew|\sjf%8aɩ̍4)"e I_xSsw2bJ* kAfa]cc$ ;FjgfAh\ӗ8;>nYV7qɚFT!4RbYלihV͚Lf`nN)6aP%>7w^ aаY4>sWcc$l5G~vjq$}e6I i,fvj}eQ6k i,SDra-GFͤ}4WyDbQ9* a0h;ul <:٬FY1LES&u)SO( Ne+cbP \pNX6O)cbP_V4 BMNXQWSL4kN)щu awaаY4>ï ױ1LV4hh#EpH9Xw1, a0h, `y&\0IXѣmN)FG0 ] nX? 6 g/ױ1L4Z"8E,c ̣4hoEH,tx34l ϼ7~,\0I X X0h8|0h, `a[4)"e G' 6 g~/ ױ1Lxtւ4)"ehH` CekAfa̽N[#EpHY7-8GiP~O_o=/ BO. A3χ& <:kA2X'tx<]o8/ BO. A5a[4)"e |i? )P Afa̛'\0IXѣmd/ Bj%wJ{Z te\R+aWBx{a4sj)UH cbPH cbP1;4)"e߰#Lf0e4l 6 g^kױ1LV:hҨDUԖBeXn-',@XUHm egQj'/ }gQ4'Yn.X~Z~3I*ohvR۫9>ΎkNlӹ i,SDxtbz59 B1l A3o:6Irev6Hd3;53}UX줸L <􎏳S3tn,G2 =0h, `ZyKS3B>0;@ʕw̃6P{W5bA6ek~E`ב"8E,rdLb  ;ul 4h|[ٱXc"=c•l\YsT6 _Hװz D>}Q1eg`;"8E,rdAl3 6 kmxt",N/}]Tv4Tv4YA _ؖY ǝԶ?,N/}]Tv4Tv4Y֨m&w Ȳy?(hh/-k}5E~iYNN) 4l 95rw|sӦVW(P)/qv4*r;>Ύ㚣6YR9/ fr}v!EpH4l eq KONyqv|\sjJh*sӦV_2|*򎏳(5ŗxr}v!EpHY7gf4l ϼ_cc$l!qv|\tғSqv|ל;>X6!9L,qv|\tғSqv|לI{o;k2,S[of i,SDra-GF?46àa0h}MzNaG'Ųlzq KONyqv|\sjJ8cLRR43Ųlzq KONyqv|\sjf'l0}2͊v!EpHNa0h}zvaXSE',>h,ʩ, Tev'oNbY6reg}E9UtRce΢4N8/LhaS6N)c & kytBYu, ,E',3Z )aL ) BvDl ˜xT/:*/Df Ա/h*11,qlX.M8GYVjA5+زֈf6N)Lb  & +4 {4)"ehz5$ 0h, `y ױ1LV|5vఒ4)"e<: W}e:6Is 1X1hAfa̫dAиWx )8B vi,SDrh9b1hmAfa=ߞ qxN)FGAl3 6 g^tX@ 6 g'w& `-Hc"RƠ A3?gw4#EpHY7-8G `aаY4>3p$Ai,SDrh9Ƒ<3_Ƨo χO6ׅ}?cc$щ6va3(xS(gj 5_Д*11(11 Ω GzPp0&Xmϣ\|ދ^co5[ݯr k='x3z+23ul =:]t&YbK|`vHFJ,몯*jS3;*ڇ5ەY9B>;>6/`"8E,rd[LbЀY 6 z_cc$0h8)e`&klzqͩzF\ʬ!Hc"R k92f&1h@, Agcc$Dљd-mٙuV?XMxjٚߦ+=:Y՗RdU@2@G 6 ڢA:*)UH55GRղ)U 17(g{U,fpǙFjPە}heeƘxTmɂ-0-54)"e  f4velGep|}9/qv|\sjf'Žq',k]9'4)"e3hk~G§_Xw`@h$caG'@fg!ޜ͎-J# לI[j`2g5fvRܛG~p²HؕS1j)E٬9>lv`"8E,rdLbЀY 6 ڊA |òd/q^)xyYtzh쪥8;>6Bujq "FMccNeǨe/1!X~Z~oI 6AfaЀY3PFU5>ՠXkTRYA.+^Vjv: ueʘR˜TLs 9aYtT|:!kKB-Bz5Բ"Kc"FQSL4k4)"e<:PA/  hA@i,SD4 ԣ? a0h@?p$aEN"8E,c # hŠa0h@?p$Ai,SDrh9Ƒ& <:kA2@G 6 ;` "8EAB=bаY4}'?p$aNw Y~#d4 )aL ^KS;oYߏ )aL )Xi,SDrZz1h@, Ag}cc$nРq'Yx#ޡ qv|\$dgQj' 28;>"8E,wt #ow[ȧs/xѷç_X/|~?RO& +ztB/c;\_ۮ9>9bhvR}EsUog Xmϣv?B[r˿>x+o= 6\0I`0Eqx=zF\%z*N)۞ASzƷl!?{>>x+?k_ p$aENelGq' cTڮ8dWV4)"e߰#ߴgf4l gul m4h YeL ~`\;Y]łl/}hvFmWcQ?X& .Sz| EpHY7ȌߩN6ãG'`|oaG'4 Y8;>/-[t[+"zS}A5j!U\ن,Ȅ-a )]YXi,SDʶ ~$l32/}ul JefFDT=5ߘ,(Rۥ~VNPE&k& &)(mE4[mf៷D~:6I6=:Qt4*,h0w@e>953YP+=eɚɂn QXi,SDra-GFE$ hŠa0h@|hR[_/b0I􎏋M{{;k2;ɂŽq',k"yKpғSE"8E,rd[LbЀY 6 ϒ1\0I Uɕqioe|& fQ,ҮɊYs|Hc"RƣAfaЀYk4zx-e^f|i쪥& &',E5l>"8EAB=bаY4}֌!|k YeLkAи:1ɃfP{5_Д*11{[.M휚)~?Ko"8El{_Eh+oxF k~/=\:6I zx7B/ }gErAvv ˽v|Hc"R= .E/zћJxO6̯ǿ L?/ױ1LV^vtѩ_<]}U1Us|\s6hYGoXˑ3Af1h, >뮗$\0I`0Eqx=zF\"[:Hc"R k92|&1h@, AgkytB/c;\?XM˥veY'07XB=bаY4}ul m4h YeL ~`\;Y]łl/}hvFmWcQ?X& Vg/*,,,4)"e  ^cc$ B/5Ύ#K~& Ȳyslڮ8FHbaz& Z/KE_M_ZCoXˑ3Af1h, >p$a-6;>.:a,h0Q)!cO7& vkS#Teɚɂ@NXi,SDra-GFEϤ .>E7-׿g}9|g}JK~2~Gw4*,h0w@e>953YP+=eɚɂ@NXi,SDʶщ| y'r;^s~7|~w. o& 4`\9xAve>w {(NXi״EE"8El{ G<'v/|l!?}+xgç_XwwOKg& 3<:J6;>.r6l0}dAl8JE5=YQ6NXi,SDra-GFE$ 0h, `^cc$h }IX䗖N{>򾏳,$SNXi4R=E?E"8E,Ġ A3=:6IŠP;QT+@ʘxT9坌֨BWYVjAT0vpNX3U5_NңP`"Z#f;V\t`QN) 4l ϼSoױ1LV:hL[N)c _ׄ& {t4)"ehH`1hmAfap$Ai,SDrh9ƑX~÷><46àa0h}WX?o]tV|'/Aͨ*jS3;*ڇKK("EpHNa0h}浟yva`ߌxg5fvR}EsUog @?X1hAfa=:6IŠ؎.:be O-[veY's?Џ4)"e߰#ߖgf4l ϼ>L2hq1Z}_ Ҕ5bA6>4Tڮ{Gc/+3ģ ~(lL]5mN){ΎNXzr;>9Բe>ΎkN줸7=evMOV͚Lf2X@ 6 g>G?cc$h }h,ʩٌj,ʩCcW-}gQ4"SNXi4RYs|\Hc"RƠ A3ױ1LV2ɏʧ|RcY_`qH2"q$le+cbPH cbP1%e1SUEꄬ-= ,5R2i6xjHc"RrxAl3 6 g>{O ױ1LV:hL[N)d1κ𤧿Of-_7<字}6 O}G_ cc$ XmϣǞس.<ȕl!\rg^yI7F?|+){?~4\0I`kA4G !BN=p$aG'=O4 '4)"e<:]} zysOi,SD4 w{/SAu} ױ1L6^:2]Ao4Z1gAĠV}W9\0I`аv:2]Ao4Z1gAĠV}~%\0Iщ_;3XBpA:ow4elJS2k\sj+l5*dkX"@ی4)"e BC a'?p$auN}}rȕqv|E9Ut²VҲFWS䗖fN)o9z$ A:Ow`KONy5F39gNjfv"EpHY7|Ыp&1h@D aՇ?6۠!m)԰ep|/Jޛ~3;ۉ4)"e<::bЀφ& }Yg7Hc"RƠ!'W-<ț SȦ~H'>/?N䠈8;>Ύh(mv"EpHY7|Ыp&1h@-/|{/0eĔHl7##zǷ` Ƣl4g8;~(N{MQg3;ۉ4)"e-G@™Ġ! hۂG'-Yܟm}/{_c)eLT@Y>kE`;"8EG'B+DṚh_\aA ѫEYXN)cЀBm>& {tbi"o;s_%;*N)F{&1h@!;ul -4zxnkV4)"ehz$ hW-o\ѡ_Ж遯6hX}>(fe|A!+D2@hQɇҧ?_,:4z3!_0B[ul 4F2 -*Usn?#G UOƫVm߳Wi_~9ݟA L"EEHY7DЎ|&IOvB~ V_?_>jW~$_g4m;?p$Ai,B/RDr! ev3A6h?s?7&|W~5n3_,B[_~ul ?:z"X^BCzM=_i?5rL ez;~+\0I`kAЋ2 -~]QgЀf }:\0IXѣ?/*:5_Д*11(11 ΩOIW0&@'X^~Cʌ{/wjo}[DŽS׸mZ<|m~}ke?$r; o2,Wrv/ }gQ4vLJXg !EEHY7DK3I:~}^'0g?-S U[|Ss=8+wy,r*_90h@۬_}S:6IŠ1X'Qtjo&;tn,Զ*jS3;;2Y`S{۬|w|l_t"EEHN mg3 IEkg>swgg99ɗ&V4m~=:6I3I2Oqxg5fvR}w2eY@ Hcz"RƠE>?o49ojo{Ł^w,r m~cc$D6;ΪXbA6ek~ڮg͢j4)"e2CM$iN(|@݉A<:QX9r/f#?VojaA.UfT~A.9ZƘt2Y_,fpEj5MmWk, KƘpeoA>igk.Sz|Xi,B/RDr! eiIOvB=Zsy9{LjC S ORU=ݳ '>G'( _;"lP ˆ)x_ce'x_ce)~QH5~pˢ(d3;fvj}RTzaKXzBJbi,B/RDxtE>?˧/i$ҿ & k]ze?+5fvL7 4%8rQ_|Qۥ~ZqɚZ})E3S,˦w|\sO5El;=Hcz"RƠE>?iACjÂm)/y=x1h@Uul qm lُcC͠bͤ6/qve;>1YS+=m+E?qQj~ d?;=Hcz"R Q(3LFA0_:"TBmpP &於xtV}>cc$0hK Re;ɂac{YtLE',(ͦw|\cQ)UH)Xiz5f[@X^~C 4G;urPYࠦ[oe/{s|<#n6i+G' V}췿cc$ $ҨTN`F^~3;Բe>Ύt)ͦw|\cQ)UH)Xiz5fe8AЋ2@hQ;1hB[o-K_RiR^ZN#W_Da0ϠL ~{Oל)x_ce;i쪥8/Դ'L:ep|lMcl6S38/;Ys|\`!H)cЀТ P' _5b?B?!6C(<7^?O)cc$Dp4βb_LESN'ycptiR2i6X쳝̲P}eL ^K ˆc)eL *^VˊfVRYA~ "Z#*u)fs""E,Pfߛt4h'>NvuK5~ R?{PoGÔA`Ѐv]_;ul  Hcz"R Q(3#I裝PsΟbq֯}:6IŠh#EEHN ԝ{tB^wb{9sj<:/& `-Hcz"RƠE>Nj5I?şbx-k_W' eVul  EEHY7DЎ|&IOvBN O"_%j?忮OX{] 4һWul  H)(ڑ$iN(|@4>{z~Kުj] Z~D84)"e<:Т P' G Ő EEm V:6IX X1h@hQ iSŢ4׭tXp$NCHc"RFˡLFz Ig}tbUZgЀ>C:6IX X~rhG>4]zܿg|{^99_ 6}{_aG' ^2de|Qی{UN2nR˜R1rZ R; R0&0&S\pNXoCRB_p.,,F5#EpHN ?T4]s%~3qV@LIENgZ˃£2vz/D{c;r:_l9j/ }gQ4"lƛi:'',~N)cЀТz˂mJ7h؎.:˱stòv{;t-AdUTqv|\sjf'Žj$llf 䴃= Kt2"8E,rd$>=hTm?:v줽m-eKP9Z淩R?+5h׷Ln,(RەvgW_`SHc"Rƣ!6}waA:*+cQsYt,Z]>wjQf38TSҨT!5bA6>4T.s`c"KMf11(FJ,(Rە}XJS*UĠٚc"=cbPHl5EŔ"X-X1h@[__ʻ;O|q3Bmw& <:qZ4bQ'9l۩F1M_l1婥N& ȲysWogkvPP\O#S>|cHmW_l10Q4{GcQNeǁF֋ҲFWS䗖X-X~Zw;49/}z2nF-л߻Aek3԰J [ˢS3b67cElfd}@S"C*ǙFjPe~lvΎkRkXX~ZG;4U# O?.q,bJJk$~7oO7,"K/֡96#N{g4qfU!%d?;5|eqͩF1kfhT̶R"sJL53N;&PEiqͩf;>wΎtyXX1h@O_<+_yXh? AYj?|Y qul >:aGqg}a&{5fŬ9tީŁbh.JZ6qͩf;>wΎ4+f7*N)v&1h@ҮaQ=_ц=Ճϣ7& >.:~ "6K1kjʰ "z?F1fVlòƮZ>Ύch.D>qv|!;v۩l5,:-5L{~6*N)v&1h@.6 k_.~bBzbÑyzWmr ױ1LytᨼG|[6Q1@UޱZ 1ޕY=Y+ȱ-qv4β\S̲P}eL )aL *ᜰ̎.MXVє*11|S(҄s2Y )e O)cnP-eCA`L=SWO B۠5 m 0{ #EpHtpV3h}̿WMk G%P;G?)T,_/Bۦ B_Ux"8E,C74U>L.Z?jE?H^KPLu7j ;|'g9A%s$e&PC_/BۦC>h13>KHc"RFˡӛI Ъ?dzj&C=ga˳Lǿڐmӌytb ʾw#EpHNçڇڇE>u`=Hlﭽ?ӳy]Oϟ-Bۦ4#EpHtTY0hp탷WKPsK^c%ˢ?k?OߋжiAиO탷WKPsHS{lAޛ,{_"mb[4)"ehH`1h@˧J` X?yPA=Ss{s 8~jmM3xt"8EG'S?8%.~h[_ ,z/3{3{e/~sQR mb[4)"e Vnu=EJ0Yߣ^y=|^=5mf4v돷Yi>0&|LB @i,SDra-GFĠ͡ڏא=E6|Yߣ^א^_ןjl/Bۦ<+CeXvζYboβ~:,"8El{89rB!r ױ1L4*òv{;ty`g̍4)"e3h@!Pֱcc$DYU373Te']|β~V~ ̊4)"e߰#B!֦>cc$qРʘxT\6Zo /1&\>wjQf38TSҨT!5EŔ"9"8E,rd!Zοp$aG'28>.:~Y/5Tv4YXꔳmfl66E~Ŕ'b_Z(jҲ0XB!:+ul e,[s|lfqͩ*ˢS3b67cElfFNX-X1h@!YG0\0I 8>hVRB@|*S#Wz5fŬ9tXebYHNX-X~Z~G!īcc$0h\͚ٶS#Wzqͩ+S3bx:Mhl@1[4;{ofV4)"e߰#B!6v:6IJ8>wjJ8;>95rw|\sjQ̚OZ(fFDl;fv`Hc"Rƣ!6ʫױ1L4d/}\tyEm+, Tep4Y4Y5ew|F5L{~6E2 !6 <1\0Iщ2&UmpDl-6SQ1[C+B0&gd Ƕ*8ˊsO)c*r6gj"8E,rd8B!֦+N&\0IXѠa{/;qN)FЫ!Bk\cc$щM_dm@2@!Yx{aAV!EpHBhuÙOױ1Lţ:(`K"8E,cB!.yU:6I¡4#EpHY7- Bh]:Kul tvi,SDxt!fp$Ai,SD4 B۬ xBaN)F[BKp$Ai,SDrh9Ɩ!Bҙǜcc$щ՜e&Y=+_TU3X̃ǪBJB  XB!ͺul lPBPTe;QA8;>C4)"e Bm֕Gnױ1LV脾]tjW.J>9;~-l8/3$ph"8E,rd*A!􄫏& vBTq^f|H>;>Í4)"e߰#W B!֦omxt\|rvv*,~q&g*>Í4)"e<:BmiG' >ΎنS#WzٱX=YeL ~q^b Dli5i,SD4{\{qO8'pֵ}噧{Yu)'\w g\~iW_p]~SO鸳;s}ڙWι.ӞxOң^y7]vMsg_{ٙO|Wؓ|ʿ>znο3oyٷpK. .x./<񆋏c?/ t 9N;E'_|i_wէ=z%GN֋o7\y~\y%\s?n=eW[/׷ˎ'tu'sq']󸓮׏鱧^yէ|c;Ǟp ){9;}^}gt)t ^؛/+;Ov;cN<'G;ҳϿ'r7?Kܫ/>Ͼ3Spqs5?p݅Ϲi?^xO:ث?s.< Ϲě.?i']u-+O+n8ګc.>N|O9zgs']xg_qWsܥg{WyϿ.S.:̣W]w^ui^qY\u%zO泞rƠ/s/~ן}Gn8葋t7s|7s|ұأWprOKk.? q%\zW_p/>+Sνs}򑫞|ɵO۟|Ƨ^tѓn:[; Ncκ⸓=So>OUۮ{Oc+no+ .Sn9ۯ8)/}Va0ϣep4T^ Ƣe28r*/NPҥÄ4)"e߰aAekSC+r8;>ΎNX6YVYל~{e@oX0I 8>ΎkN _qv4*/nY+.:qiA;Ji,SDzta0àarg5Fl/8;>.2YI8','dǓ'i,SD4($aNep|ל dA'ᜰ _أ(5ǙN) y KEXd28~(㢳ri9a*1|/12N) yh8X1ɕ5G>Ύێ)ᜰl8*YQWSL4k i,SDxt`G& +4>"X1hQIŠ}Q1eg0!EpHY7mf$D{E9EFl/(&wD~i ƢˢSC+E~iY)KaB2QIJ ^29>ΎkN ٚ8;>.:aOX\fYAg}\sjÁ4)"e va0ã>q|ל=hU,^ݘV\t<>S#WfN)  8;>95Be{gqɂN9aYt$gN) >:aGqv|\sj28>Ύ"s28>.:~cl~3;p8"8EG'va0Ϡ!;~8;, W/5Tv|\tZ.M8',>6T2J"KE?Á4)"e va0ϣ Gk R3&6Bq1w# G}4+f;V\tp EpHY7mf$hаN Hc"R($%9ؚn St[8's JTP 2>\XH.?'}u}BM"%-vp' 7blnj;IW'|+-"%-m9Ol' 79hwgl7rp I:Xec|uN8halnj;I#lc[na;I|o*V7QBz+=Չ,VOY5u_ioyy6Zi ._㗵b^%_m{ nʏ}\yA~[T5}Չѫ&PJM~OW%%6~[{ض!);VAgԟ[#&%a+{.^oYaۆtЪ^[yW'~3U5z`v?}WjgJݑ:kk_Xy]-ؽaJRɤeݑ]E^:޲d4WnҮVm+VͶ Lec4pS~ʻ_pON[int9ᓵ)Um6\{h@s_[EWC+O#< ejI]'V2=fۆtЪ^[y>>6Q󮪓&^O;US(]{ACڭHD5zry7蘮דdw` d4/d[j*63qMQ+~u~XDUdNjz=9d~BzL VJ2*J2 wj8OÚ_eۆtЪ^[yAKn()K_[JuF-u]]dw`W}BMvu]/y耮C*Vm^Ú_eۆtЪ^(ԏW'#-]1XGI^(뗵b hV ü.=']V^z7 &>cUyvcM௲mC:ShX (_~ʻszö Lec;)?Jq_NW4(\mҙBn<{܁%]&%mC:ShՍc/–;VW'@k 63 nʏ}\yp63qMQ+ p63Vx<"l9?JHo4sض!)aQBz+mHg -ܔ%. mHg -}W=ՉkrZ@J)uN3gc/*mHg xE8h(!8hO9!WSlޮjCȣ/S<&s/ yhCVz`FP&ҥ^v[^Kت:0i͍n.TQn&d}ż/UۊvmҙBn<{!ԝ,V._`OЪI2ZXeZRNjxu6ߞ(_*BVNI\Njk~n2I\B[%ˏ[yW'buPj%uhC-]ǥռ*v# Ն[^5dd}^F7Vz]_bۆtвCQD.Ry~5$Si+ֻ|P˚ԁhl\LI:=?*I4wmnjvQ+;h/Lq UÚ+&%pF}Jaf5YklېZ6vA/ۼvGIZ?~Y:0N;y~hpjYvw%,}W=Չ^^1RX֪3kQ2 Wn^1V:IWk7ض!)9~x;.#,V._OOkajM.ۇnLkD/S灑vr~vd\?ah]/$_$.>VQBz+=*fªkd4SsMt=JFU$1]O,zKMÚ63Vx<"k Si"\ãq=ߊWrnr[iIkm+rmiUzi+ևLZQVM"nMF6<4uL-XG oG Q+Iv3z:~~ղV&q9ʏ8y~{d^GlMc0G >{^(550FgVR'R~H]/g?+ԪWѭ֨ՆVNt|ޫ}y66|9N4EZ ?JHo4ywy?yx{o S#cj1wmC:ShՍc/" XěQ7?G &[tGlېZ66,?JqՃ3,ZRCr-Q]llUsnF7\]Ds.}a]ͭV, mHg -}W]{~ܪu4ԵZuiKqi5力]/SIVzZetö LU7 ܁%c !}Xd=\I\5(+F7z5zi7'']zX7mC:ShՍc/AwG G -c]/ʼ-@~ȏ}\yW'&lېZu؋wРH3V4V/wr(mJcrw@/ѼG &n+r-2VeV _.P :LKhՆjw`ܔmҙBn<{?JHo3kFV)7&CR|^jrM?=R.5&L]˶ LU7 ܁%կN zbqL[j?|vϽ(uMt=JFPQ'5L^^,[\mҙBv: Qȏ}\y51UoOiBP]Dףd.jaM>5~rO[Ô襮Zeq ٶ!)llaryT{;<}\ywf&?P]5]5ɯ_C׷/<&[tGܝmҙBn<{w4^x&iQBz+]=h0:zMt-&ݻځD/u]M讚GWCԚ[tِu5V5ywdtW5uMt=>bVܪmJɶ LU7A, yDy6HB~ʃwW:o[ռIkoNj+{G*ZiOwGFwy^+ u\JuBuڼ5Fs]ǥUU讔/SIVzZet\mҙBw4hkn%\y_ŏ}\yAC7Z}XVE]Dɺ{'޲uju5NZjkHQ2^VVX 5(q|ntZvcxb}5p5mHg -4ۋyN w}W=Չz^1PTMt]]'vp:QFQ>7&X [|MÚ63Vx<"A.v/'/mk7u;7V{AU$nޢkn1]Dףd.jﭡ&I"_OJ-7ivl1Dףd.jmPzbqL[jض!)4ףVҶF+/G IseRV;<3V5wki7ض!)AW~ʃw4ض!)aQBz+= 63]`Ώ}\yp63qMQ+ p63Vx<"l9?JHo4sض!)-G1e"(! p63~u⅃#?Jq]9lېZ6rР++3 (AǕw8m;4@艀*js %]9lg u؋t HA/SM%G e,Z/tk[&޲ujul7Fwy^K1ڝ hkmXc5Dףču<<+mC:ShՍc/AwG ՉG:LۭaJ2*uG꘮D/uFjݙɀRMZ[ 5(V5%j&pemHg xEAz֯&Wa$lϪIT4u-V)o-UH|4Uamiz9whx |ǯ|-?JHo >OT׻a[CMtZ&zveJt0ЭaMF\r1I|D-5܂mҙBn<{IegF'm+ʻuFs>63~u<ݯ>_45ߝ?_:Kғr4Q滓T_4yk-Q+;h{H/5aۆtв4{\KsFJkP[kh>*=&ը[T?Xrt> _J@5|>9)^繕#Lȵ"m(?Jq_"RmHg xERi֪IPɍz2_/V.QwhrԚzZaJV~dBtl޽[棧vZN^(AǕw pmHg xEʖ>Dn/R'j7OeI6ϧ<ӭj+%'j&Zs9ZVRU 29V^UQKX˹{-4u{B~ʃw9hmC:ShՍc/–cHwK(! p63~uIG >A8mҙB8h(AǕw}uy[OV55˲mC:ShՍc/AwG ?նK]^zϭ2):ɥGh@s_[EWC+ó7Qt@j%uL.uLZ#tR/.kmC:Sh_(AǕw4˺H6Ih``Qi@/u]/dn4_sMt=JFdMvu=Jv'޲uju5NZFݚ躪ݚQ}V5'ƶ Lec4pS~ʻ:?um.ɀt_JݺZ1k4_sM|]+'dJ2U;&sNt=JԨ;FwrW5Ič %Uռ&ƶ LU7 ܁%4$듕ޫyUsM=z&Gɮ-n1]Dףd.jmP59ݚ¹zKJҥ63Vx<"4p~ʃwW:Qĺ.ҺMe;~2W59jk꽚&%淌)1]Dףd.jﭡ&%p[QkUQvkjlېZ6W')?JqՃ|]e]X[h5a]6&rΏm2H˚襯hrרk:!4uMt/uPU G[:keۆtв1)?Jqc_WEĪve5V{޳դexRC筨m$sZj>I;k.J7eH3gc2Vm+/hWjgcQ5֡nJa3V˓:9kmC:ShՍc/AwG {A?Ǽև{bFs]Dס wvlېZ6A7G >Չ&W~tb~˼kv^>CP]Q8xwٶ!);VA9]2݁OK8y7,[˶ LU7 ܁%կN^-x豞{iG0IwtpemHg -ܔ%A|&/랍njM輮Q*ZݰJ]" ՆfI+Yt1 +jnնba]ٶ!)lnʏ}\ywyn6K]av`t&j5uhtKuy˫暌O:6J/ <63Vx<"4p~ʃw4.]ҮڭHLUwM;PÚ̍5W h+II듮d= lېZu؋pQBz+=ՉD?M2U;xVkɔeƀ&j5퀇h^s_{ŀRX阮']zX'ٶ!)lNpS~ʻ8huMt]ͻs^Mty״mxTU$1]O,zKMÚ>ɶ Lec4pS~ʻ_4uMt]]W\W]'j5@>$~i满&%0xתd= lېZu؋pQBz+]=h0)Nqi5eM~r9&痻kІ&rQk%Fs]Dס XMB]6aMdۆtЪ^[yN9v5d>yNK<OR< mK6[^eV [K1&OmC:Sh_(AǕw4ض!)lnʏ}\yW'&8hmHg xE8h(!raۆtЪ^[y._mC:Sh_(AǕw9hmC:Sh ܔ%9_mC:ShՍc/–;VA8mҙBn<{܁%]:aۆtв1:MQ+raۆtв1)?Jqc_u /ͯSVUj(=/V݁o܎mҙBn<{?JHo/KI][h}xJҥ^5פZ^ pGmHg xE8h(!~u~\դ0]2݁OaJRrdqL-޲8263 nʏ}\yKs\1e5/k\Ô襮Zeq pemHg -}W]?9]2݁׌[sMt]]ϭOmC:ShՍc/AwG 1FVu?r7&t^Qnnmy֮]5D5y_XiWs +ƶ LU7 ܁%կN秽\/[/uˇځey׌4-)_Ds2=ƶ Lec|u}W=vGt&Jj&#i2]Vu&j5@ k27\kn OO:_&mC:Sh ܔ%N$Om◩ĻXN/SE74Qi<&Fծ&[tu&aMaۆtЪ^[y't]]W\W]'j5@> Cj1UozXuض!);VՉO]D5u5{5z]QC0Ԯ&yתd= :lېZ6W')?JqՃtVn\'ir~&mhR.ջjjW]$ԵjpmHg -}W= UsЮ^ֻ#i':ITjgc6Ԋ:utԮ&U Zڍ6\mҙBn<{?JHoFlېZu؋pQBz+=Չ mҙB7G >A8mҙB8h(AǕw8mҙBn<{?JHo4ض!)aQBz+=mHg -ܔ%. mHg -}WmHg xErp~ʃw9hmC:ShՍc/–;V{.5=Ri~N~Qn5ʵF3G+/=g>~Vjhs4'nZ*܎o*VNpS~ʻ_UʍnuhCFO+~˿I+Uʓu4]Dn6)i vpW'g\֯ /Wۚ'J%p^u,ϻ#&-^,Dב%۱EJZ6VW$F~_@LP5IHt&p^u,ϻ#&-XL,DXecu[peII_G_I;PÚJmF讚$O2iu oEJZ6W'$ᤃ3T-_Xi=Z/n-ƺZ|w@KvoijX:&Fw\_kXx6Ndw-_Xi7LZae&[RW@}a9EJZ6A7$ 4Uetk׵wyh5YդHGh@s_[E7s 讚$!K; @5[Vz0ʌJR_Z]wdl7Җ\vpACH e(꺪ݚjoaJR-uMt&RMZv0U; N&]ת3tڝ&VMFa23U {EJZ6V-$ἯN$@m◩Ļ\{K S$b2%WJsvl1sjoJݸlT[j&0YQ>hj^blNpSIt]]W!5%^5%[а2:VWE5\I\S.[ywdrWmd&+3$]ڪ {EJZ6A7$Չ@]D5u5.jRQUQ躵; -n XM\k2 p%q5OIlgݑ]UQf<(uU5p/HI~#ʶ~u\ZMqY\hoaMÔ襯5jiQІ'MF6I̤57j2 ьV5%n逮ܔm,RҲ-$ԯN'v5d>yNn (4GyĺzՖ&ʻZi`Q/k@նRt&zr+OR7.jS5u+̳Uj-jP^+IK]\}BJҥ^5פZ^ _el7t.k;I8Jn''v;pT}&$]Fz]{W kk~˼tLף~{kuYS,;Xec|uNvP̜?qGj&^ՆG2/[Ô襮Zeq "%-NN焕s'>wG躪]Mt=JF0&[tGmHI~#ʶҀy6έ LԤeR-:Dk_XymQ27x|J/C+.;EJZ6W'$ԃ~$hVLިٝijX]~U GkQ28evkMITU7Fwy5zi7'']zXblnj;I8IHPTvoTnt V\]Dףdn}^'u=JFah5DU$]ڪsF]Mt=>|MÚXecu1rN.pPuk&vkmnr{mD/u]][Kt=JFah5DU$]ڪ(\ۆv5☪d= {EJZ6V-$᤯N+yJz&%vkmh~oD/u]]k瑱&%0jMҥEmjW]OǼkUy"%-vpAm.{u]/SDס M:xZ*jZr7jkI7Z)( ޲NCjjW]$Եj"%-NN <<{[r+OR7.۽&-+OF]hgc6Ԋ:tьa2 zy6Z+4k{6j[)tv#O seRV;<3V5wki7"%-״$z0bl7rp Iy_`8hXec|uN8hNA"%-Np*`6)iXoG"%- vW'G"%-vAXec4pSI_al7rp I #lc[na;I8w=R}?osJ-llZn2 zRO47E"%-vpA~ Dן񎟨uMt6)iXoĖ\v𶃆je\8>P]t@56*Vn\Dףdn>]UjQWs_[VKt^IVzZet3lcFrkNN=hǘ6lt:ݙv5Xp&%si,]( m躪ݔKU[5q|d= m,RҲm9l' }u"cj*ur>jҍPJckz̭뤮G( m躪ݔKU[5q|d= m,RҲ1:Mm' 8hyJ[U5Iځ6\7R-ޥc%0jvS.Umd[j6)i vpW'ꇖ<%r]Q]U5Iځ6\4vS׵wP]Qn 5uMt&RVMFaU zXx7Xecu[peII F?:h8ZI6)i vpW'߷2ʍR<VnY1z(-o}^eR m,RҲH[pMIy J_n_V)7&n2z^cu]]EJZ6V$Չij%V{նFG*fݫCey:elNpSI{o>&o[eq lcFl9m' o;hVfۇQ]_xzky27_iJ[{I"x4]LJ0V1 +jnնba]fHI8hশ:ស܍rZzQ2ZLzj^w\/ɥ.jm[jj^F7Vz]fHI~#m95m' 4UtRףddwr2P[zd4S-Χt&Pĺ.Z.Umč:_&lch.e;I8IpUTڊ6ٝ VJR+Z:BS̭뤮Gɡ0xvۅJݸTު(5Yk7+W')?JqO4\]@mDnM\kk(9m.դT&aM;M 8h(AǕwW:Q?J$zNNj&vkj^]-5DףPVVK_ITyתd= |6Սc/AwG ]]Dm*ڻ4u\Zݰ_&ntnl&Uװ&t0Q7 ܁%c_T^goQnI;kN.xMZ^i<Fj[k2I7]/OHlc4pS~ʻ:&qM5yFbېBF ̏[y4 ]~-6#xE8h(!^!+nUj'n) nʏ}\y* Ҷ=e06A7G >{N? m& uG GQEQ5/TT:h0GPEQuJovb5k֬Yf}I 8h ;SEQEQEQ?~:qY | 44pNsAJ _K/{AjllUyNnZ:w4.?#ּ>su]/Sz&{CVpi8hp|EQEQEQEQ8r((((I)`m!§IENDB`stella-5.1.1/docs/graphics/secret_quest.png000066400000000000000000000046711324334165500207640ustar00rootroot00000000000000PNG  IHDRTngAMA asRGB pHYs  ~tIME'EV ;IDATxOiqa^/C VbbPoטHgn8w xB^4~TuOuwTW>L7yf} Xkٳgϟ?ſg^|իׯ_̳U 6 !Z5C/fb͟s?lO~󧙿fɓk~/ JÇ?~Q5Zi6ޣ'R⿚cM p& 1_ɗf~Xjٟ>K3! f/ԦXRf~tiOW4|ƋOK}KbΏ_09?0UQ{4g;S??}m6^N~wm?LG-0a.g-o^09]ÖpC'}wwv~^m%?q)|01vq.@[=4h׃+fW 쿪~Ŀu !`9qRg3فl2C?>ҥ~c{?Rp`уg_)@ɧ%+>/*FgmMɱO Vl9D<%srspσ^Ưvﻧ!@ih[ }+?G0! !9.~qb?+~@? ~@fygktlgt/]Ϩ7,g޸ߜyg_}&~F}q!`>?Mh6[/w.ض<{}p"{"Q/W'DٯvPLξdZ4E};6by;'ǖ]BtU[mR_?=u0vۻ'(Oݻt^ xH{ o? ~@? ~@? ~@? ~@? ~@'d;=y4{CĿ}K}?Ŀs⟢w{? ~@?? ~@? ~@t~ؚvC?rv~j뾧G޳d|߈h叿 ϲثW86^m6}^Y*ȶ}KϗGfrgJ>_ 'RgpjkKV ׳A?bAmާ<2s$qښoy˿Y0n[|=%&πA1Gq? !,[_~%b`?ͬ{qfA >7^#~jaN{{{<{޽{Ν۷oߺu͛7nܸ~k׮^zʕK.]x… ϟ?wܷ3UUVV1´SίKhpD뜳Q~?ViOͿw̙3+p,;*|OG̟VtP#[1Xt,wC+i)4{Xf*_m?rm`i? -jGk~wW<(+a}\G?}m;O?t/k~Z#Zs0k75CB\±ŸJ i͟g>u> /i^r gnwf?-~yo>! ]?pڢOT__ca7u2/O_QEZKy4n(5ȯʏ:`/A %J (@PA RP̠O|y>V9z;l9p: y+yk9mgplʻug!( ezujvhsf_qW4xϔ`{EWoW,"Z}eֱ:QUznԍd2 UKG#Cb5-< 6>Qe2hC-F+ED>yMࢵ}e #Wev5y"GϕbӦVvُdderVMLzMk=[PfM#A5}/(sg6zUP_!Gz^W(=(#:FYĠ*Elnݣ=ʑ{y;N,GyJP:f~DY{љKr\מ:WZ:Ui2=,*E03["V_-%x <t:&!mA %J (g`6 ʈF\3Q8nRP"(QUAއH>bW{ܑ; #>O3cGvz6쭋V|9}v'D>4ꖖUGkCϮٻWeU<۫:W3ȪjNl{9fQ]hD9DzqEW|Ƞ\1%(jWJzhPnoӯevBS[RUeZQsKP~=)(g ZfQ^CȺyU$DKD{͌(:j_RPNU{ՕBG[RFAYy/8͘z :(#jdWm<{k#b|!(K@bfABd<ۉey¦U-AY>O ʑ%(gvjPv-*{ePN|1O|))Au%Q~ٕ^{lDݣikT}[w:_:Q"2𢎫rՏ2;MFvmϑ}"KP ʔQ\4 (̂@J%:(@PA)(@PA %J (@P%J (@PA |x<~{Pgy~=g1({ m=k7m0|ςe<'eKl-k~2ĪrK{5ϝRp/ʞK^SA)(eNPFOik"AZ{Y2+H#a*:bZ,jnD̟g+6AT9G#.H:޺>v"|kZ1-(ઃrLj2IJF~fqEt68_#~'D|fA((wXlˈ2*t2eePVNC :vJPΎw躑'N +ުS3>QSy+2bz1)#ʞqA. *g6䕋*;֟5Bi#!"_-*i䕸{sǿ:(GuP05}:?:z](xw80:k嗋Wf}WFޕUOX{>z;{ku*Uu~ve[dkA G\w (@P坷] #URW>=_?]QGݥn\&(W<_NZg=I'ٺ.uq'(u>RtU1<π~lPgd gF{陉 +\Q=[ƍԋ.è!YޑauC[n5+v{%"rqCM˯gʑ2zί ܏reaDz[-Z;uRPF/8 =wʌ{V*(#v{HP4ꠌQFoykg^Y}TAPfN̄^~BjkD}3:(O(W*a (G?N(WQ.i_GPN9mʥ=5QSתêёa*ӑպ3+WfԍZ}S>^gYӪՏ6(|SA lՙ JTPM:<%JA %J (@PA  (@PA %J (%J (@PA 韏~?yPo?G2msWFe$( Je7*~_^ԫWA (8s>WcgL٫?{y {rEЌN"A*xgY99NN~oy8<(W(WOA e^3gVP+WfeԔ{Yp=ʪ{Qxe81ujVP^=#<@P JA ԫm%RP^M*#A ((;5J%p٩׏o?g?oMuKP ʏ1%J (@P/OA! 8r{IENDB`stella-5.1.1/docs/graphics/space_invaders.png000066400000000000000000000052711324334165500212410ustar00rootroot00000000000000PNG  IHDR^9i?gAMA asRGB pHYs  ~tIME,7X ;IDATxݿ$iٞ][K6OT0Sh (wx ")` " jpqv,y|jχbi흩vջ7f  x_`L=Gݰʎdh;;,֌ 3O]tqѣ* 2$ÇID5999ZFst Pܿxrt.D0[ ݻ3!u KAFÝ;wK:qHsV`lt ׎o߾}֭cD- %&_>Qd>x#~skΙ "Smȯ5 Ƕ3 Ƕ ͛s) qO(w KC m mEP֫P{hm+چzPb6r!JVvf%Ֆ!ZۊaǏ=mC=~ Z% ۂ&>=J5% ! ڧ~Aנk55{Oe-\k5vk]1D Aנk뮡JȂH<j,_\u ew v]i&uC5|~>\p>?=T.{gv{վ_vg_jмV.0E#FJS۹=(kh  hD ,1_n!@4_}:W/}mrz_v} P@+}N/\S$?iWFC~F]It χj5/h(V~q_v}0 EP_}& c~)6_=6mQXkD @4 %?^=gB?mЪyU_j}Plнz-]»&m~>PP}D w_v}&5 㵗]_4}W}1D @4 hآS8XA<ݺ]g {hDMe O"6өO]CC_v}ʥ{[}Zx hD @4aW|e ņzU_}J%}_׼NnD/>FC~'GD?˫O ƶhuw_v}PG4,9? #{h8V"W[>P hD @4hXpҬ]` <]<;.CTk ģhT}Єg#ږZR ̳(TcB@4 hD Η G4,9]\>.@w ː%gWgr}]P[_j}&5akxeקR`zѠyVѰcB@4 hD @4 h hD @4 hD &+^_W>}}@4#u h`ș0@4 _u\q hD }l/T< hDhD @4<\~zu݃hX D VD`p  i=0EC)iLk1 Ѱ>}]?Wϣcʇat^HaB@4 }&oG g1@틺 @>3q 0,ln P`א'BB++G;3UF'ͼXkO~+K?7_˯}o}?o<+?\ܳ>{S=|=>Ơ9kЫ`5 xttt&"+jHLa5_|q<j`c%bhd EmZR˅\<[3i1rabagк֐GC*ĕ+W6wc 1jTFd"υ}Ĭ{3g\H_#)FDCwB\H Dx̵kG`+|\ʈJ;htxSkH iRU6!g- h": a;C 4HMK$w[I<fJYQ\ |%wu\}/4UevOcjz!V"ڮz" D>VMg&`')"vCe|6! `wB!SDː#c!b7/ 9E~9CYd kḋYqԬf'qT\CH [!|S4H:Vx2Oq/j^gḋC5nw[*skC t'(WtitۮjP,ͅ%[4#P{.Bsq]jH G`imK[:4;m̮\EGX6lQBo~1p#u& ~goe":lIENDB`stella-5.1.1/docs/graphics/timemachine.png000066400000000000000000000043331324334165500205340ustar00rootroot00000000000000PNG  IHDRF5*sRGBgAMA aPLTEAAAJJJfff67d pHYsodtEXtSoftwarepaint.net 4.0.21 i?IDATx^훋v6 Dmr1AJڜr{R !|L7N>i*F*F*F*F*F*F*F*F;>c?hW@ V*F*FnO YBZO0d'>(1:V5Ȗżaj(:uEk#3Qژ!FfyZC&ŎgW}>btykƟ 1ަQv#q#[^`d-ŧOm7[#ny!Z_GMa a-F&Z{#3وu -?"xlo epPM4FoŸƫi12,Fav\} @e4W{7Ǖc>XxVu)x"zT"9F)F&;9FGbhbo-T T Stella - A multi-platform Atari 2600 VCS emulator

Stella


A multi-platform Atari 2600 VCS emulator

Release 5.1.1



User's Guide


Contents




February 1999 - February 2018
The Stella Team
Stella Homepage



A Brief History of the Atari 2600


In the early 1970's, video arcade games gained commercial success for the first time. The American public was introduced to Pong, Tank, and other interactive video games which populated amusement parks, bars, and arcades. The games were successful enough to create interest for home versions, so in 1975 Atari released Home Pong and it was a smash hit. Other companies such as Magnavox and Coleco followed suit and released their own dedicated console games. Then in 1976, Fairchild Camera and Instrument introduced the Channel F system, the first cartridge based home video game system. The industry recognized that cartridge systems were the future of video gaming, and began development in that direction. In January 1977, RCA released the Studio II, another cartridge based system, although it only projected in black and white and seemed to be focused on educational titles. Then, in October 1977, Atari released the Atari VCS (Video Computer System) with an initial offering of nine games. This system, later renamed the Atari 2600, took the industry by storm and dominated the marketplace for years to come.

Because of oversupply, the Christmas season of 1977 was very rough on the video game industry, and the Atari 2600 was the only system that managed to emerge unscathed. Atari enjoyed strong sales in 1978 and a fantastic holiday season, as Atari released more games such as Outlaw, Spacewar, and Breakout. Internally however, Atari was at odds. Nolan Bushnell, the inventor of pong and founder of Atari, wound up leaving the company and purchased Pizza Time Theater, which later became the successful Chuck E. Cheese! In 1979 Atari continued their trend and released 12 more games which met with continued success. However, Atari was now facing some stiffer competition from the Mattel Intellivision and the Magnavox Odyssey2.

Atari needed a mega-hit in 1980 in order to squash the competition, and they found it in the home version of a game from Japan called Space Invaders. It was so popular that people were buying the Atari 2600 just so they could play Space Invaders at home. Following that, Atari released Adventure, which was the first video game to contain an Easter Egg - placing an object in a certain area revealed the programmer's name, Warren Robinett. 1980 was important for another reason - the creation of the first ever third party software producer, Activision. The company was formed by four Atari employees who were unsatisfied with the working conditions at the company. They released four games initially: Dragster, Fishing Derby, Checkers and Boxing. The games were very well received by the public, and revealed that the Atari 2600 was capable of better games than Atari themselves had been producing. Atari tried to prevent Activision from selling games, but they failed and Activision grossed $70 million that year.

By 1981, the video game industry was basically a horse race between the 2600 and the Intellivision. While the Intellivision was technologically superior in some respects, the 2600 continued to lead in sales. Atari released the home version of Asteroids, which was a huge success. Inspired by the success of Activision, another software development group called Imagic was formed. They would not release any games until 1982 however. Another company, Games by Apollo, was formed in Texas and released several games that year.

Coleco entered the market in 1982 with the release of the graphically superior Colecovision. To combat this new system, Atari produced the 5200, a technologically comparable system. The 2600 dropped $100 in price in order to remain competitive. Then a company called Arcadia released a peripheral called the Supercharger which played games in an audio cassette medium. This allowed for multiple loads and expanded the 2600's capabilities.

Atari released Pac-Man and E.T. that year, two incredibly hyped games which were critical flops. Although Pac-Man sold many copies, it was considered to be a poor translation of the arcade hit. However, there were many fantastic games produced for the 2600 during this period, and it was still selling strong.

Ever since the inception of Activision, Atari had been fighting to keep third parties from producing cartridges which they felt were stealing profits from them. Finally the issue was settled when Atari agreed to allow third party manufacturing in exchange for a royalty. Suddenly software companies began popping up all over, and 1982 saw releases from companies like Venturevision, Spectravision, Telesys, CBS, 20th Century Fox, US Games, M Network, Tigervision, Data Age, Imagic and Coleco. There was even a company that released a line of X-Rated games for the 2600 called Mystique. The year was financially successful for Atari, however there seemed to be a glut of software. Although there were many quality titles still produced, there was an increasing number of rushed games as manufacturers attempted to cash in on the craze.

More companies jumped on the band wagon in 1983. Zimag, Ultravision, Amiga, and others were also producing games and peripherals. It seemed as if there was just too much product to meet the demand, and as it turned out there was. By the end of the year, companies began folding. US Games, Data Age, Games by Apollo, Telesys and others all closed their doors from poor sales. A video game crash was occurring, and all companies were taking it on the chin.

1984 was a much more subdued year for the Atari 2600, and the price of the system had now dropped to $40-$50. Many were saying that the video game industry was dead. However, Atari surprised everyone by announcing the release of the 7800, and also promising more 2600 games with improved graphics and sound. Unfortunately, neither of these things happened in 1984 because Atari sold their home video game division to Jack Tramiel who believed that home computers would replace video game systems. No further mention of the 2600 or 7800 was made that year, and it appeared that they might be dead.

1985 was another very quiet year for Atari and video games in general, and only a few games were released for the 2600. Activision produced Cosmic Commuter and Ghostbusters, but with little fanfare or marketing, these games did not sell well. However, because of the huge game library and cheap price, Atari still sold over a million 2600 consoles in 1985.

There were very few plans for home video game systems by any company in 1986, since the market appeared to be dead. Then, to most people's surprise, Nintendo brought the NES to America and it was a smash hit, proving that video games still had a place in the US. Atari decided that maybe it would be a good idea to release the 7800 units it had in storage, and produce some more 2600 games. The 7800 was released with only 3 games initially available, although it was compatible with the 2600 library. They also redesigned the 2600 as the 2600 Jr., a machine with the same abilities, but a new look and marketing campaign. It was sold for less than $50.

Video games were once again selling phenomenally in 1987. Atari released several new titles, including Jr. Pac-Man, and also licensed a number of games from other companies such as Donkey Kong and Q*Bert. These new titles sold for $10-$15. Interestingly, a number of titles began appearing again from third part companies such as Epyx, Froggo, and Exus. It seemed that the 2600 was not dead yet!

In 1988, Atari rehired Nolan Bushnell and announced a number of new titles, including Secret Quest, a game written by Mr. Bushnell himself. Atari continued to manufacture these games even until 1989. However, it was apparent that the 2600, after its introduction over a decade ago, was finally at the end of its run. Although it was still produced and marketed outside of the US, the Atari 2600 finished its run in America. No other console has had such a long history or sold as many systems in the U.S.

Today, the 2600 still has a large number of fans who remember the countless games played over the years, and the years to come. There are even games being produced by hobbyists, some of them quite professionally, being released on newly burnt cartridges with labels and manuals. And the recent trend in retrogaming has brought many more video game fans to rediscover the 2600, and it continues to live on 22 years after its release!

Alexander Bilstein
February 1999



Introduction


Stella is a freely distributed multi-platform Atari 2600 VCS emulator; originally developed for Linux by Bradford W. Mott, it is now maintained by Stephen Anthony. Stella allows you to enjoy all of your favorite 2600 games once again by emulating the 2600's hardware with software. Stella is written in C++, which allows it to be ported to other operating systems and architectures. Since its original release Stella has been ported to AcornOS, AmigaOS, DOS, FreeBSD, Linux, MacOS, OpenStep, OS/2, Unix, and Windows, as well as consoles such as Sega Dreamcast, GP2X, Nintendo DS and Playstation Portable (among others).

Features

  • High speed emulation using optimized C++14 code
  • Supports high quality TIA emulation using the TIA core from 6502.ts by Christian Speckner
  • Supports high quality sound emulation using code derived from Ron Fries' TIA Sound Emulation library, including stereo sound support
  • Emulates the Atari 2600 Joystick Controllers using your computer's keyboard, joysticks or mouse
  • Emulates the Atari 2600 Keyboard Controllers using your computer's keyboard
  • Emulates the Atari 2600 Paddle Controllers using your computer's mouse, keyboard or joysticks
  • Emulates the Atari 2600 Driving Controllers using your computer's keyboard, joysticks or mouse
  • Emulates the CBS BoosterGrip Controller using your computer's keyboard, joysticks or mouse
  • Emulates the Sega Genesis Controller using your computer's keyboard, joysticks or mouse
  • Emulates CX22/CX80 style trackballs and Amiga/Atari Mouse using your computer's mouse
  • Emulates Spectravideo CompuMate system using your computer's keyboard, including mapping of CompuMate 'Backspace', 'Space' and 'Enter' functionality to to the actual keys on your keyboard
  • Emulates the Mindlink Controller using your computer's mouse
  • Support for real Atari 2600 controllers using the Stelladaptor and 2600-daptor/2600-daptor II
  • Support for the speech portion of a real AtariVox device connected to your PC using a USB adaptor
  • Supports EEPROM emulation for AtariVox and SaveKey controllers, as well as FLASH support in various cartridge schemes
  • Supports all known bankswitching schemes (let us know if there's one we missed)
  • Supports DPC+/CDF bankswitching schemes from the Harmony Cart, including partial emulation of the ARM processor
  • Supports cartridge autodetection for almost all bankswitching schemes
  • Supports Supercharger single-load and multi-load games
  • Supports ROMs stored in ZIP and GZIP format, as well as the usual raw A26/BIN/ROM formats
  • Supports property file for setting the properties associated with games
  • Supports the NTSC, PAL and SECAM television standards in 50Hz and 60Hz mode
  • Supports autodetection of display format for 50Hz vs. 60Hz modes
  • Supports several "undocumented features" of the TIA graphics chip used by some games
  • TIA emulation supports full collision checking, with ability to disable TIA sprites and collisions for each object separately
  • Full system state save/load functionality
  • Automatic save state creation ('Time Machine') which allows moving back and forth in the recorded timeline
  • Cross-platform UI including a built-in ROM launcher frontend
  • Built-in extensive debugger, including static analysis with the Distella disassembler and dynamic analysis at runtime by tracking code/graphics/data sections, and generation of DASM-compatible disassembly files
  • Emulation of CRT TV systems using Blargg filtering, including presets for several common TV outputs (composite, S-video, RGB, etc.), and ability to fully customize many attributes (contrast, brightness, saturation, gamma, etc.).
  • Built-in ROM database with information partially compiled by RomHunter


Getting Started


Requirements

The following sections outline the basic system requirements for running Stella under various operating systems.

General (required for all versions of Stella)

  • SDL version 2.0.3 or greater, latest version highly recommended
  • 15/16 bit color minimum; 24/32 bit color graphics card highly recommended
  • Enough RAM for the OS + 256MB RAM for the emulation; 512MB+ highly recommended
  • Joysticks or gamepads are highly recommended
  • Mouse or Stelladaptor/2600-daptor with real paddles required for paddle emulation
  • Some ROM images (See AtariAge for more information)

Linux/UNIX

The Linux version of Stella is designed to work on a Linux Workstation with the following:

  • Linux Kernel 3.x
  • i386 or x86_64 class machine, with 32 or 64-bit distribution
  • OpenGL capable video card
  • Other architectures (MIPS, PPC, PPC64, etc.) have been confirmed to work, but aren't as well tested as i386/x86_64
  • GNU g++ v/5 or Clang v/3.5 (with C++14 support) and the make utility are required for compiling the Stella source code

Macintosh

The Mac version of Stella is designed to work on an Apple Macintosh with the following:

  • MacOSX 10.7 (Lion) or above
  • 64-bit Intel processor
  • OpenGL capable video card
  • Xcode 8.0 is required to compile the Stella source code

Windows

The Windows version of Stella is designed to work on Windows XP_SP3(*)/Vista/7/8/10 with the following:

  • Direct3D or OpenGL capable video card
  • 64-bit port has been tested on Windows Vista and above only
  • Visual C++ 2017 Community is required to compile the Stella source code
  • (*) Note: Support for Windows XP is problematic on some systems, and will probably be discontinued in a future release

Other

Stella is extremely portable, and in its lifetime has been ported to almost every platform where the SDL library exists. It is 32/64-bit and endian clean in Linux/Unix, MacOSX and Windows. The Stella Team is interested in hearing about any problems you may encounter with diverse operating systems and CPU types.

Installation

Stella is distributed in both source and binary form. In general, you should always download and install the appropriate binary version. Compiling from source is only recommended for developers, or if the binary version doesn't work for some reason. Once you have a Stella distribution you should follow the instructions for your operating system given below.

Linux/UNIX

  • Binary DEB (stella-release-1_arch.deb)
    • Install the binary DEB with the following command:
         dpkg -i stella-release-1_arch.deb
  • Binary RPM (stella-release-1.arch.rpm)
    • Install the binary RPM with the following command:
         rpm -Uvh stella-release-1.arch.rpm
  • Building and installing from source code

Macintosh

  • Binary DMG file (Stella-release-macosx.dmg)
    • Double-click the disk image, open the 'Stella' folder, then copy the Stella.app package to your 'Applications' folder.

  • Building and installing from source code

Windows

  • Binary EXE installer (stella-release-arch.exe)
    1. Double-click on the installer and follow the onscreen instructions

  • Binary ZIP file (stella-release-windows.zip)
    1. Unzip the binary ZIP file using Winzip or Total Commander
    2. Copy the contents of either 32-bit or 64-bit directory somewhere on your system

  • Building and installing from source code

Locating Game Images (aka, ROMs)

Cartridges

Most games for the Atari 2600 came on cartridges. A cartridge usually consists of a single Read Only Memory (ROM) chip which contains the data and code for the game. Plugging a cartridge into the Atari 2600 allows the 2600's microprocessor to access the program stored on the cartridge.

In a similar way you must "plug" a copy of a cartridge into Stella when you want to play it. Having a ROM image/BIN file of the cartridge allows you to do this. A ROM image is a file, which contains the actual data and code read from the cartridge. There are several ways to obtain a ROM image of a cartridge:

  • Search around the internet and find ROM images to download (websites such as AtariAge and AtariMania/RomHunter may be useful). Many homebrewers make their ROMs available too.
  • You can purchase the Atari 2600 Action Packs by Activision and use their ROM images
  • If you're handy with a soldering iron then you can design and build a device that plugs into the printer port of a PC and read the data from the cartridge

WARNING: It is illegal to use ROM images of games that you do not actually own since these games are still copyrighted.

Supercharger Cassettes

Supercharger games were not stored on cartridges instead they were stored on cassette tapes. The Supercharger, which plugged into the Atari 2600's cartridge slot, loaded games into its 6K of Random Access Memory (RAM) using a standard audio cassette player. The Supercharger also supported multi-loading, which allowed games to be broken into several segments and loaded at different times. This was useful for large games which had distinct parts such as role playing games.

Most of the available Supercharger ROM images are stored in 8448 bytes files. However, ROM images of multi-load games are sometimes stored in a set of 8448 byte files. The names of these files have a two character sequence number in them which indicates what load they are. The sequence starts with zero, skips a few numbers and then increments by one.

Stella supports multi-load games, however, the set of ROM images must be combined into a single ROM image file. For example to create a multi-load ROM image file for Survival Island you would do the following under Unix:

   % cat survivl0.bin survivl6.bin survivl7.bin > survivl.bin
or to create it under DOS you would:
   % copy /b survivl0.bin+survivl6.bin+survivl7.bin survivl.bin

Once you have the multi-load ROM image file, survivl.bin in this case, you can play the game using it.

Supported File formats

Stella supports ROMs ending with extensions .a26, .bin, .rom, .gz, and .zip. For the last two compressed formats (GZIP and ZIP, respectively), Stella will automatically decompress the archive, and use the first ROM image it finds in it (ie, the first one ending in a valid extension).

Playing a Game

Once Stella is installed and you have some ROM images you're almost ready to start playing.

Integrated GUI

Stella contains an integrated GUI for all ports. Commandline support is also available for those who want to use it.

If you start Stella and do not specify a ROM image, it will start in 'ROM Launcher' mode:

If this is your first time starting Stella, you will be asked to select the default ROM directory to use. This is where you have all your ROMs, collected as described in the previous section. Several dialogs will be shown, similar to the following:

  

The browser should be self-explanatory. The 'Go Up' button moves to the parent folder (if it exists), and the 'Base Dir' button moves to the base directory where, by default, all Stella-related files are stored. Double-clicking an item will enter that directory. Click 'Choose' to select the location, or 'Cancel' to exit the browser. Note that if you don't select a ROM directory now, you will be prompted again the next time Stella is started.

At this point, you may want to set the locations for snapshots and other external paths. This is described in more detail in Advanced Configuration - Snapshot Settings and Advanced Configuration - Config Paths. These settings are optional, and can be left at the defaults if you won't be using snapshots in the ROM launcher.

Once you've correctly set the default ROM directory, you can start emulation by selecting a ROM and pressing 'Enter' or clicking 'Select', or double-clicking a ROM. Note that some games require you to 'Reset' the console before you start playing. In this case, you need to hit the virtual reset switch, which by default is the F2 key. Also, some games may require that you press the joystick fire button to begin, which by default is the Left Control or Space key(s). If a game uses a more complex controller, see Getting Started - Keyboard Layout for more information. To exit a game and re-enter the ROM launcher, press the 'Escape' key.

Using the 'Search' textbox in the upper-right of the ROM launcher, the listing can be narrowed down, showing only the ROMs that match the pattern you enter.

Command Menu

While playing a game, normally one would use the keyboard shortcuts for controlling the 'virtual' switches in Stella (ie, the commands associated with the function keys as described in Getting Started - Keyboard Layout). However, another alternative is available. Pressing the '\' key toggles a command menu dialog as follows:

This dialog contains a set of buttons that represent the same functionality as the function keys. You may find this useful if you cannot remember all the function key events, or you wish to use Stella without a keyboard (ie, in a standalone gaming system).

Keyboard Layout

The Atari 2600 console controls and controllers are mapped to the computer's keyboard as shown in the following tables. However, most of these events can be remapped to other keys on your keyboard or buttons on your joystick (see Advanced Configuration - Event Remapping). The tables below show the default settings.

Note: All key names are based on the US QWERTY keyboard layout.. If you use a different layout some keys may differ. You can use the following layout image as reference where to find the US keys on your keyboard.


Hotkeys

Console Controls (can be remapped)

Function Key (Standard) Key (MacOSX)
Exit emulator Control + q Cmd + q
Exit game mode/enter launcher mode Escape Escape
Enter/exit options mode Tab/Escape Tab/Escape
Enter/exit command mode Backslash (\) Backslash (\)
Enter/exit debugger Backquote (`) Backquote (`)
Select Game F1 F1
Reset Game F2 F2
Color TV F3 F3
Black/White TV F4 F4
Left Player Difficulty A F5 F5
Left Player Difficulty B F6 F6
Right Player Difficulty A F7 F7
Right Player Difficulty B F8 F8
Save state to current slot F9 F9
Change current state slot F10 F10
Load state from current slot F11 F11
Save PNG snapshot F12 F12
Pause/resume emulation Pause  

Joystick/BoosterGrip Controller (can be remapped)

Left Joystick (Joy0) Right Joystick (Joy1)
Function Key
Joystick Up Up arrow
Joystick Down Down arrow
Joystick Left Left arrow
Joystick Right Right arrow
Fire Button Space
Trigger Button 4
Booster Button 5
Function Key
Joystick Up Y
Joystick Down H
Joystick Left G
Joystick Right J
Fire Button F
Trigger Button 6
Booster Button 7

Paddle Controller digital emulation (can be remapped independently of joystick controller)

Left Paddles Right Paddles
Function Key
Paddle 0 decrease Same as 'Joy0 Left'
Paddle 0 increase Same as 'Joy0 Right'
Paddle 0 Fire Same as 'Joy0 Fire'
Paddle 1 decrease Same as 'Joy0 Up'
Paddle 1 increase Same as 'Joy0 Down'
Paddle 1 Fire Same as 'Joy0 Booster'
Function Key
Paddle 2 decrease Same as 'Joy1 Left'
Paddle 2 increase Same as 'Joy1 Right'
Paddle 2 Fire Same as 'Joy1 Fire'
Paddle 3 decrease Same as 'Joy1 Up'
Paddle 3 increase Same as 'Joy1 Down'
Paddle 3 Fire Same as 'Joy1 Booster'

Driving Controller (cannot be remapped, always associated with joystick controller)

Left Driving Right Driving
Function Key
Left Direction Same as 'Joy0 Left'
Right Direction Same as 'Joy0 Right'
Fire Button Same as 'Joy0 Fire'
Function Key
Left Direction Same as 'Joy1 Left'
Right Direction Same as 'Joy1 Right'
Fire Button Same as 'Joy1 Fire'

Sega Genesis Controller (cannot be remapped, always associated with joystick and booster-grip controllers)

Left Pad Right Pad
Function Key
Pad Up Same as 'Joy0 Up'
Pad Down Same as 'Joy0 Down'
Pad Left Same as 'Joy0 Left'
Pad Right Same as 'Joy0 Right'
Button 'B' Same as 'Joy0 Fire'
Button 'C' Same as 'Joy0 Booster'
Function Key
Pad Up Same as 'Joy1 Up'
Pad Down Same as 'Joy1 Down'
Pad Left Same as 'Joy1 Left'
Pad Right Same as 'Joy1 Right'
Button 'B' Same as 'Joy1 Fire'
Button 'C' Same as 'Joy1 Booster'

Keypad Controller (can be remapped)

Left Keypad Right Keypad
Pad Button Key
1 1
2 2
3 3
4 Q
5 W
6 E
7 A
8 S
9 D
. Z
0 X
# C
Pad Button Key
1 8
2 9
3 0
4 I
5 O
6 P
7 K
8 L
9 ;
. ,
0 .
# /

CompuMate Controller (cannot be remapped)

CompuMate Key
0 - 9 0 - 9
A - Z A - Z
Comma Comma
Period Period
Func Control (left or right)
Shift Shift (left or right)
Enter Return/Enter
Space Space
Func-Space Backspace
+ + or Shift-1
- - or Shift-2
* Shift-3
/ / or Shift-4
= = or Shift-5
? ? (Shift-/) or Shift-6
$ Shift-7
[ [ or Shift-8
] ] or Shift-9
" " (Shift-') or Shift-0

TV effects (cannot be remapped, only active in TIA mode)

Function Key (Standard) Key (MacOSX)
Disable TV effects Alt + 1 Cmd + 1
Select 'Composite' preset Alt + 2 Cmd + 2
Select 'S-video' preset Alt + 3 Cmd + 3
Select 'RGB' preset Alt + 4 Cmd + 4
Select 'Badly adjusted' preset Alt + 5 Cmd + 5
Select 'Custom' preset Alt + 6 Cmd + 6
Decrease scanline intensity Shift-Alt + 7 Shift-Cmd + 7
Increase scanline intensity Alt + 7 Cmd + 7
Disable scanline interpolation Shift-Alt + 8 Shift-Cmd + 8
Enable scanline interpolation Alt + 8 Cmd + 8
Select previous 'Custom' mode attribute (*) Shift-Alt + 9 Shift-Cmd + 9
Select next 'Custom' mode attribute (*) Alt + 9 Cmd + 9
Decrease 'Custom' selected attribute value (*) Shift-Alt + 0 Shift-Cmd + 0
Increase 'Custom' selected attribute value (*) Alt + 0 Cmd + 0
Items marked as (*) are only available in 'Custom' preset mode

Developer Keys in TIA mode (cannot be remapped)

Function Key (Standard) Key (MacOSX)
Set "Display.YStart" to next larger value Alt + PageUp Cmd + PageUp
Set "Display.YStart" to next smaller value Alt + PageDown Cmd + PageDown
Set "Display.Height" to next larger value Control + PageUp Control + PageUp
Set "Display.Height" to next smaller value Control + PageDown Control + PageDown
Toggle frame stats (scanline count/FPS/BS type etc.) Alt + L Cmd + L
Toggle TIA Player0 object Alt + z Cmd + z
Toggle TIA Player1 object Alt + x Cmd + x
Toggle TIA Missile0 object Alt + c Cmd + c
Toggle TIA Missile1 object Alt + v Cmd + v
Toggle TIA Ball object Alt + b Cmd + b
Toggle TIA Playfield object Alt + n Cmd + n
Toggle TIA Player0 collisions Shift-Alt + z Shift-Cmd + z
Toggle TIA Player1 collisions Shift-Alt + x Shift-Cmd + x
Toggle TIA Missile0 collisions Shift-Alt + c Shift-Cmd + c
Toggle TIA Missile1 collisions Shift-Alt + v Shift-Cmd + v
Toggle TIA Ball collisions Shift-Alt + b Shift-Cmd + b
Toggle TIA Playfield collisions Shift-Alt + n Shift-Cmd + n
Toggle TIA 'Fixed Debug Colors' mode Alt + Comma Cmd + Comma
Toggle all TIA objects Alt + . Cmd + .
Toggle all TIA collisions Shift-Alt + . Shift-Cmd + .
Toggle TV 'jitter' effect Alt + j Cmd + j

Other Keys (cannot be remapped, except those marked with (*) )

Function Key (Standard) Key (MacOSX)
Switch to next larger zoom level Alt + = Cmd + =
Switch to next smaller zoom level Alt + - Cmd + -
Toggle fullscreen/windowed mode Alt + Enter Cmd + Enter
Decrease volume (*) Alt + [ Cmd + [
Increase volume (*) Alt + ] Cmd + ]
Switch display format in increasing order (NTSC/PAL/SECAM etc.) Control + f Control + f
Switch display format in decreasing order (NTSC/PAL/SECAM etc.) Shift-Control + f Shift-Control + f
Save current game's properties to a separate properties file Control + s Control + s
Switch mouse between controller emulation modes (see Game Properties - Controller) Control + 0 Control + 0
Toggle grab mouse Control + g Control + g
Swap Stelladaptor/2600-daptor port ordering Control + 1 Control + 1
Reload current ROM (singlecart ROM, TIA mode)
Load next game in ROM (multicart ROM, TIA mode)
Control + r Control + r
Reload ROM listing (ROM launcher mode) Control + r Control + r
Emulate 'frying' effect (TIA mode) (*) Backspace Backspace
Go to parent directory (UI mode) (*) Backspace Backspace
Toggle 'phosphor' effect Alt + p Cmd + p
Decrease 'phosphor' blend in phosphor mode Alt + i Cmd + i
Increase 'phosphor' blend in phosphor mode Alt + o Cmd + o
Switch palette (Standard/Z26/User) Control + p Control + p
Toggle PAL color-loss effect Control + L Control + L
Save continuous PNG snapshots (per interval defined in Snapshot Settings) Alt + s Cmd + s
Save continuous PNG snapshots (every frame) Shift-Alt + s Shift-Cmd + s
Toggle 'Time Machine' mode Alt + t Cmd + t
Enter/Exit the Time Machine dialog t to enter, t/Escape/Space to exit t to enter, t/Escape/Space to exit
Rewind by one state (enters the Time Machine dialog) Alt + Left arrow Cmd + Left arrow
Rewind by 10 states (enters the Time Machine dialog) Shift-Alt + Left arrow Shift-Cmd + Left arrow
Rewind all states (enters the Time Machine dialog) Alt + Down arrow Cmd + Down arrow
Unwind by one state (enters the Time Machine dialog) Alt + Right arrow Cmd + Right arrow
Unwind by 10 states (enters the Time Machine dialog) Shift-Alt + Right arrow Shift-Cmd + Right arrow
Unwind all states (enters the Time Machine dialog) Alt + Up arrow Cmd + Up arrow

UI keys in Text Editing areas (cannot be remapped)

KeyEditor Function
HomeMove cursor to beginning of line
EndMove cursor to end of line
DeleteRemove character to right of cursor
BackspaceRemove character to left of cursor
Control-aSame function as 'Home'
Control-eSame function as 'End'
Control-dSame function as 'Delete'
Control-kRemove all characters from cursor to end of line
Control-uRemove all characters from cursor to beginning of line
Control-wRemove entire word to left of cursor
Control-LeftMove cursor to beginning of word to the left
Control-RightMove cursor to beginning of word to the right
Control-cCopy entire line to clipboard (not complete)
Control-vPaste clipboard contents (not complete)

Controller Map

Some Atari (virtual) controllers are simulated with more than one computer controller, and there are several special cases where controllers are active in certain modes only, as the table below shows. Items marked as (+ extra) indicate that the computer controller may not have enough buttons/axes etc. to fully emulate the device, so extra functionality must be mapped to other controllers.

  Computer
Virtual
Controller
Keyboard Joystick Mouse
(auto mode)
Mouse
(specific axis)
Stelladaptor/
2600-daptor
Joystick
Paddles
Booster ✓ (+ extra) ✓ (+ extra)
Genesis ✓ (+ extra)
Keyboard ✓ (+ extra) ✓ (2600-daptor II)
Driving
Trackball/Mouse ✓ (axis ignored)
CompuMate
Mindlink ✓ (axis ignored)
AtariVox N/A N/A N/A N/A N/A
SaveKey N/A N/A N/A N/A N/A


Stella's 'Time Machine'

A special feature of Stella is the 'Time Machine' mode. In this mode, Stella automatically creates savestates in regular, user-defined intervals. At any time, the user can interrupt the current emulation and navigate back and forth within the saved timeline. This can be done either by using the Time Machine hotkeys described in Hotkeys - Other Keys or by using the Time Machine dialog. This dialog is automatically entered when using one of the Time Machine hotkeys. The hotkeys continue to function within the dialog.

Time Machine dialog:

The dialog items are explained in the following two tables.

Top row (left to right)

ItemDescription
Current stateShows the currently loaded state's number
'Timeline' sliderShows the position of the current state in the recorded timeline. A state can be selected by dragging the slider with the mouse. To visualize state compression, small marks split the timeline into five, equally sized state number intervals.
Total statesShows the total number of save states in the Time Machine

Bottom row (left to right)

ItemDescription
Current timeShows the time of the currently selected status, relative to the first one
'Rewind All' buttonNavigates back to the begin of the timeline
'Rewind One' buttonNavigates back by one state
'Continue' buttonExits the dialog and continues emulation.
Navigation infoInforms about the interval of the user's last Time Machine navigation. The interval can vary if the timeline is compressed.
'Unwind One' buttonNavigates forward by one state
'Unwind All' buttonNavigates forward to the end of the timeline
Total timeShows the total time covered by the save states (aka 'Horizon')

The 'Time Machine' mode can be configured by the user. For details see Developer Options - Time Machine tab.



Advanced Configuration


The default options in Stella are meant to cater to as many situations as possible. As such, you may never need to change many of its options. However, Stella is very configurable, and if you want to change its behaviour in some way, there's likely a configuration option to do so. The remainder of this (lengthy) section details every configurable option.

Using the Command Line

In addition to the built in ROM launcher, Stella can also be used from the commandline (assuming your operating system has a commandline).

To run Stella from the commandline, use the following format:

   stella [options ...] ROM_FILENAME

Options ('0' or 'false' indicates false, '1' or 'true' indicates true, others are self-explanatory):

Argument Description
-video <direct3d|opengl|opengles2|opengles|software>
Use the given rendering backend (where applicable); default is the best available mode detected.
-vsync <1|0>
Synchronize screen updates to the vertical blank period. This can result in smoother updates, and eliminate tearing.
-fullscreen <1|0>
Enable fullscreen mode.
-center <1|0>
Centers game window (if possible).
-palette <standard|z26|user>
Set the palette to either normal Stella, the one used in the z26 emulator, or a user-defined palette.
-framerate <number>
Display the given number of frames per second. Normally, Stella will determine framerate based on number of scanlines. Setting this to 0 automatically enables auto-frame calculation (ie, framerate based on scanlines).
-timing <sleep|busy>
Determines type of wait to perform between processing frames. Sleep will release the CPU as much as possible, and is the preferred method on laptops (and other low-powered devices) and when using VSync. Busy will emulate z26 busy-wait behaviour, and use all possible CPU time, but may eliminate graphical 'tearing' in software mode.
-uimessages <1|0>
Enable or disable display of message in the UI. Note that messages indicating serious errors override this setting, and are always shown.
-sound <1|0>
Enable or disable sound generation.
-fragsize <number>
Specify the sound fragment size to use. Linux/Mac seems to work with 512, Windows usually needs 1024.
-freq <number>
Set sound sample output frequency (11025, 22050, 31400, 44100, 48000) Default is 31400. Do not change unless you experience sound issues.
-volume <number>
Set the volume (0 - 100).
-tia.zoom <zoom>
Use the specified zoom level (integer) while in TIA/emulation mode.
-tia.inter <1|0>
Use interpolation for the TIA image (results in blending/smoothing of the image).
-tia.aspectn <number>
-tia.aspectp <number>
Specify the amount (as a percentage) to scale the TIA image width in NTSC and PAL mode. Since many video modes do not use square pixels, you can reduce width until the pixels appear square. Allowable values are 80 - 120; I find 85 - 90 gives the most authentic look for NTSC, and 105 - 110 for PAL.
-tia.fsfill <1|0>
Stretch TIA image completely while in fullscreen mode (vs. an integral stretch which won't necessarily completely fill the screen).
-tia.dbgcolors <roygbp>
Assigns the colours (R)ed, (O)range, (Y)ellow, (G)reen, (B)lue and (P)urple to each graphical register P0/M0/P1/M1/PF/BL, respectively. Currently, these change be changed around to apply different colours to the respective register.
-tv.filter <0 - 5>
Blargg TV effects, 0 is disabled, next numbers in sequence represent presets for 'Composite', 'S-Video', 'RGB', 'Bad Adjust', and 'Custom' modes.
-tv.phosphor <always|byrom>
Determines how phosphor mode is enabled. If 'always', then the ROM properties entry is ignored, and phosphor mode is always turned on. Otherwise, the ROM properties determine whether phosphor mode is used for each ROM.
-tv.phosblend <0 - 100>
Enable default phosphor blending level; 0 implies no mixing, and 100 is full mixing (not recommended). Note that this doesn't actually enable phosphor mode; that is done for each ROM in the ROM properties. Higher blend values will intensify the phosphor effect. Depending on your display and personal preferences, the optimal default for you may vary. Slow LCDs (especially for office use) may only need a low blend of around 30, while fast switching gamer LCDs may need about 70 to look similar to a CRT.
-tv.scanlines <0 - 100>
Blargg TV effects scanline intensity, where 0 means completely off.
-tv.scaninter <1|0>
Blargg TV effects scanline interpolation, resulting in blending/smoothing of the scanlines.
-tv.contrast <number>
Blargg TV effects 'contrast' (only available in custom mode, range -1.0 to 1.0).
-tv.brightness <number>
Blargg TV effects 'brightness' (only available in custom mode, range -1.0 to 1.0).
-tv.hue <number>
Blargg TV effects 'hue' (only available in custom mode, range -1.0 to 1.0).
-tv.saturation <number>
Blargg TV effects 'saturation' (only available in custom mode, range -1.0 to 1.0).
-tv.gamma <number>
Blargg TV effects 'gamma' (only available in custom mode, range -1.0 to 1.0).
-tv.sharpness <number>
Blargg TV effects 'sharpness' (only available in custom mode, range -1.0 to 1.0).
-tv.resolution <number>
Blargg TV effects 'resolution' (only available in custom mode, range -1.0 to 1.0).
-tv.artifacts <number>
Blargg TV effects 'artifacts' (only available in custom mode, range -1.0 to 1.0).
-tv.fringing <number>
Blargg TV effects 'fringing' (only available in custom mode, range -1.0 to 1.0).
-tv.bleed <number>
Blargg TV effects 'bleed' (only available in custom mode, range -1.0 to 1.0).
-cheat <code>
Use the specified cheatcode (see Cheat section for description).
-loglevel <0|1|2>
Indicates level of logging to perform while the application is running. Zero completely disables logging (except for serious errors), while the remaining numbers show increasingly more detail.
-logtoconsole <1|0>
Indicates that logged output should be printed to the console/commandline as it's being collected. An internal log will still be kept, and the amount of logging is still controlled by 'loglevel'.
-joydeadzone <number>
Sets the joystick axis deadzone area for joysticks/gamepads. All values within the deadzone are treated as zero-axis values, while only those values outside are registered as valid input. Accepts a number from 0 - 29, and uses the formula 3200 + number * 1000. So the possible deadzone values range from 3200 to 32200.
-joyallow4 <1|0>
Allow all 4 directions on a joystick to be pressed simultaneously.
-usemouse <always|analog|never>
Use mouse as a controller as specified by ROM properties in specific case. Always and never are self-explanatory, analog means only for analog-type devices (paddles, trackball, etc.).
-grabmouse <1|0>
Locks the mouse cursor in the game window in emulation mode.
-cursor <0|1|2|3>
Set mouse cursor state in UI/emulation modes.
-dsense <number>
Sensitivity for emulation of paddles when using a digital device (ie, joystick digital axis or button, keyboard key, etc.). Valid range of values is from 1 to 20, with larger numbers causing faster movement.
-msense <number>
Sensitivity for emulation of paddles when using a mouse. Valid range of values is from 1 to 20, with larger numbers causing faster movement.
-tsense <number>
Sensitivity for emulation of trackball controllers when using a mouse. Valid range of values is from 1 to 20, with larger numbers causing faster movement.
-saport <lr|rl>
Determines how to enumerate the Stelladaptor/2600-daptor devices in the order they are found: 'lr' means first is left port, second is right port, 'rl' means the opposite.
-ctrlcombo <1|0>
Use control-x key combos. This is normally enabled, since the 'Quit' command is tied to 'Control-q'. However, there are times when a 2-player game is using either the 'f' or 'r' keys for movement, and pressing Control (for Fire) will perform an unwanted action associated with Control-r or Control-f.
-autoslot <1|0>
Automatically switch to the next available save state slot after saving a ROM state file.
-fastscbios <1|0>
Disable Supercharger BIOS progress loading bars.
-threads <1|0>
Enable multi-threaded video rendering (may not improve performance on all systems).
-snapsavedir <path>
The directory to save snapshot files to.
-snaploaddir <path>
The directory to load snapshot files from.
-snapname <int|rom>
When saving snapshots, use either the internal database name or the actual ROM filename.
-sssingle <1|0>
Generate single snapshot instead of many, overwriting any previous snapshots.
-ss1x <1|0>
Ignore any scaling applied to the TIA image, and save snapshot in unscaled (1x) mode.
-ssinterval <number>
Set the interval in seconds between taking snapshots in continuous snapshot mode (currently 1 - 10).
-rominfo <rom>
Display detailed information about the given ROM, and then exit Stella.
-listrominfo
Prints relevant contents of the Stella ROM database, one ROM per line, and then exit Stella. This can be used for external frontends.
-exitlauncher <1|0>
Always exit to ROM launcher when exiting a ROM (normally, an exit to launcher only happens when started with the launcher).
-launcherres <WxH>
Set the size of the ROM launcher.
-launcherfont <small|medium|large>
Set the size of the font in the ROM launcher.
-launcherexts <allfiles|allroms|LIST>
Specifies which files to show in the ROM launcher ('allfiles' is self-explanatory, 'allroms' is all files with valid rom extensions (currently: a26, bin, rom, gz, zip), 'LIST' is a ':' separated list of valid rom extensions.
-romviewer <0|1|2>
Hide ROM Info Viewer in ROM launcher mode (0), or use the given zoom level (1 or 2).
-uipalette <standard|classic|light>
Use the specified palette for UI elements.
-listdelay <delay>
Set the amount of time to wait between treating successive keypresses as a single word in list widgets (value can range from 300-1000). Use '0' to disable list-skipping completely,
-mwheel <lines>
Set the number of lines a mousewheel will scroll in the UI.
-romdir <dir>
Set the directory where the ROM launcher will start.
-statedir <dir>
Set the directory in which to access state files.
-cheatfile <file>
Set the full pathname of the cheatfile database.
-palettefile <file>
Set the full pathname of the user-defined palette file.
-propsfile <file>
Set the full pathname of the ROM properties file.
-nvramdir <dir>
Set the directory in which to access non-volatile (flash/EEPROM) files.
-cfgdir <dir>
Set the directory in which to access Distella config files.
-avoxport <name>
Set the name of the serial port where an AtariVox is connected.
-maxres <WxH>
Useful for developers, this sets the maximum size of window that can be created, allowing to simulate testing on 'smaller' systems.
-help
Prints a help message describing these options, and then exit Stella.

The following are useful to developers. Only use them if you know what you're doing! Note that in all cases, the values supplied to the arguments are not case sensitive.

Argument Description
-dis.resolve <1|0>
Try to differentiate between code vs. data sections in the disassembler. See the Debugger - ROM Disassembly Settings for more information.
-dis.gfxformat <2|16>
Sets the base to use for displaying GFX sections in the disassembler.
-dis.showaddr <1|0>
Shows/hides opcode addresses in the disassembler.
-dis.relocate <1|0>
Relocate calls out of address range in the disassembler.
-dbg.res <WxH>
Set the size of the debugger window.
-dbg.fontsize <small|medium|large|>
Set the font size in the debugger window.
-dbg.fontstyle <0|1|2|3>
How to use bold fonts in the debugger window. '0' means all normal font, '1' is bold labels only, '2' is bold non-labels only, '3' is all bold font.
-dbg.ghostreadstrap <1|0>
Debugger considers/ignores 'ghost' reads for trap addresses
-dbg.uhex <0|1>
Lower-/uppercase HEX display
-break <address>
Set a breakpoint at specified address.
-debug
Immediately jump to debugger mode when starting Stella.
-holdjoy0 <U,D,L,R,F>
Start the emulator with the left joystick direction/button held down (ie, use 'UF' for up and fire). After entering the emulation, you will have to press and release the direction again to release the event.
-holdjoy1 <U,D,L,R,F>
Start the emulator with the right joystick direction/button held down (ie, use 'UF' for up and fire). After entering the emulation, you will have to press and release the direction again to release the event.
-holdselect
Start the emulator with the Game Select switch held down. After entering the emulation, you will have to press and release 'Select' to release the event.
-holdreset
Start the emulator with the Game Reset switch held down. After entering the emulation, you will have to press and release 'Reset' to release the event.
-bs <type>
Set "Cartridge.Type" property. See the Game Properties section for valid types.
-type <type>
Same as using -bs.
-channels <Mono|Stereo>
Set "Cartridge.Sound" property.
-ld <A|B>
Set "Console.LeftDifficulty" property.
-rd <A|B>
Set "Console.RightDifficulty" property.
-tv <Color|BW>
Set "Console.TelevisionType" property.
-sp <Yes|No>
Set "Console.SwapPorts" property.
-lc <type>
Set "Controller.Left" property. See the Game Properties section for valid types.
-rc <type>
Set "Controller.Right" property. See the Game Properties section for valid types.
-bc <type>
Sets both "Controller.Left" and "Controller.Right" properties. See the Game Properties section for valid types.
-cp <Yes|No>
Set "Controller.SwapPaddles" property.
-ma <Auto|XY>
Set "Controller.MouseAxis" property. See the Game Properties section for valid types.
-format <format>
Set "Display.Format" property. See the Game Properties section for valid formats.
-ystart <number>
Set "Display.YStart" property (0 - 64).
-height <number>
Set "Display.Height" property (210 - 256).
-pp <Yes|No>
Set "Display.Phosphor" property.
-ppblend <number>
Set "Display.PPBlend" property, used for phosphor effect (0-100). Default is whatever is specified for tv.phosblend.

The following are available in two sets, one for players (prefixed by "plr.") and one for developers (prefixd by "dev."). Only use them if you know what you're doing! Note that in all cases, the values supplied to the arguments are not case sensitive.

Argument Description
-dev.settings <1|0>
Select developer (1) or player (0) set.
-<plr.|dev.>stats <1|0>
Overlay console info on the TIA image during emulation.
-<plr.|dev.>console <2600|7800>
Select console for B/W and Pause key handling and RAM initialization.
-<plr.|dev.>bankrandom <1|0>
On reset, randomize the startup bank (only for selected bankswitch types).
-<plr.|dev.>ramrandom <1|0>
On reset, either randomize all RAM content, or initialize with zero (console = 2600)/startup values (console = 7800) instead.
-<plr.|dev.>cpurandom <S,A,X,Y,P>
On reset, randomize the content of the specified CPU registers.
-<plr.|dev.>tiadriven <1|0>
Set unused TIA pins to be randomly driven high or low on a read/peek. If disabled, use the last databus value for those pins instead.
-<plr.|dev.>thumb.trapfatal <1|0>
The default of true allows the Thumb ARM emulation to throw an exception and enter the debugger on fatal errors. When disabled, such fatal errors are simply logged, and emulation continues. Do not use this unless you know exactly what you're doing, as it changes the behaviour as compared to real hardware.
-<plr.|dev.>eepromaccess <1|0>
When enabled, each read or write access to the AtariVox/SaveKey EEPROM is signalled by a message.
-<plr.|dev.>tv.jitter <1|0>
Enable TV jitter/roll effect, when there are too many or too few scanlines per frame.
-<plr.|dev.>tv.jitter_recovery <1 - 20>
When TV jitter/roll effect is enabled, determines how long to delay recovery time (recovery spread over multiple frames).
-<plr.|dev.>colorloss <1|0>
Enable/disable the PAL color-loss effect.
-<plr.|dev.>debugcolors <1|0>
Enable/disable the fixed debug colors.
-<plr.|dev.>timemachine <1|0>
Enables the Time Machine
-<plr.|dev.>tm.size <20 - 1000>
Defines the Time Machine buffer size.
-<plr.|dev.>tm.uncompressed <0 - 1000>
Defines the uncompressed Time Machine buffer size. Must be <= Time Machine buffer size.
-<plr.|dev.>tm.interval <1f|3f|10f|30f|1s|3s|10s>
Defines the interval between two save states.
-<plr.|dev.>tm.horizon <3s|10s|30s|1m|3m|10m|30m|60m>
Defines the horizon of the Time Machine.

Changing Options

All settings can be changed within the integrated Options UI while Stella is running (unless otherwise noted; some settings require an application restart). The Options menu can be accessed from the ROM launcher by clicking the Options button, or in-game by pressing the 'Tab' key.

Options Menu dialog:



Video Settings dialog:

    
ItemBrief descriptionFor more information,
see CommandLine
RendererUse specified rendering mode-video
TIA Zoom(Integral) zoom level for emulation mode -tia.zoom
TIA PalettePalette for emulation mode-palette
TIA InterInterpolation for TIA image-tia.inter
Timing (*)How to wait between frames (requires restart)-timing
NTSC AspectWidth of TIA image in NTSC mode-tia.aspectn
PAL AspectWidth of TIA image in PAL mode-tia.aspectp
FramerateFrames per second in emulation mode-framerate
FullscreenSelf-explanatory-fullscreen
Fullscreen FillCompletely fill TIA image in fullscreen-tia.fsfill
VSyncEnable vertical sync'ed updates-vsync
Fast SC/AR BIOSSkip progress loading bars for SuperCharger ROMs-fastscbios
Show UI messagesOverlay UI messages onscreen-uimessages
Center windowAttempt to center application window-center
Use multi-threadingEnable multi-threaded rendering-threads

Video Settings dialog (TV Effects):

    
ItemBrief descriptionFor more information,
see CommandLine
TV ModeDisable TV effects, or select TV preset-tv.filter
TV PhosphorEnable phosphor mode under what conditions-tv.phosphor
Phosphor (Default)Default blend level to use in phosphor mode
(needs to be manually set for your particular hardware)
-tv.phosblend
Scanline IntensitySets scanline black-level intensity-tv.scanlines
Scanline InterpolationSmooth/blend scanlines into image-tv.scaninter
Adjustable slidersSet specific attribute in 'Custom' mode-tv.contrast, tv.hue, etc.
Clone CompositeCopy 'Composite' attributes to 'Custom' sliders 
Clone S-VideoCopy 'S-Video' attributes to 'Custom' sliders 
Clone RGBCopy 'RGB' attributes to 'Custom' sliders 
Clone Bad AdjustCopy 'Bad Adjust' attributes to 'Custom' sliders 
RevertRevert attribute sliders to saved 'Custom' settings 

Audio Settings dialog:

    
ItemBrief descriptionFor more information,
see CommandLine
VolumeSelf-explanatory-volume
Sample size (*)Set size of audio buffers-fragsize
Frequency (*)Change sound output frequency-freq
Enable soundSelf-explanatory-sound

Input Settings dialog:

    
This dialog is described in further detail in Advanced Configuration - Event Remapping.

UI Settings dialog (2 tabs):

    
This tab is described in further detail in Advanced Configuration - ROM Launcher.



    
ItemBrief descriptionFor more information,
see CommandLine
Interface PalettePalette to use for UI elements (see examples)-uipalette
List quick delayTime to wait between keypresses in list-widgets-listdelay
Mouse wheel scrollNumber of lines a mouse scroll will move in list-widgets-mscroll
    

Snapshot Settings dialog:

    
ItemBrief descriptionFor more information,
see CommandLine
Save pathSpecifies where to save snapshots-snapsavedir
Load pathSpecifies where to load snapshots-snaploaddir
Save snapshots according toSpecifies how to name saved snapshots-snapname
Continuous snapshot intervalInterval (in seconds) between snapshots-ssinterval
Overwrite existing filesWhether to overwrite old snapshots-sssingle
Ignore scaling (1x mode)Save snapshot in 1x mode without scaling-ss1x

Config Paths dialog:

    
ItemBrief descriptionFor more information,
see CommandLine
ROM pathSpecifies location of ROM files
(only enabled in ROM launcher mode)
-romdir
Cheat fileSpecifies location of cheatfile database-cheatfile
Palette fileSpecifies location of user palette-palettefile
Properties file Specifies location of external stella.pro database-propsfile
State pathSpecifies location of state files-statedir
NVRAM pathSpecifies location of NVRAM (flash/EEPROM) files-nvramdir

Developer Settings dialog:

    
This tab is described in further detail in Advanced Configuration - Developer Options/Integrated Debugger.

Game Properties dialog:

    
This dialog allows you to change all ROM properties as described in Advanced Configuration - Game Properties.

Audit ROMs dialog:

    
This dialog is described in further detail in Advanced Configuration - ROM Audit Mode.

Event Remapping/Input Devices

Almost every event in Stella can be remapped to another key on the keyboard or to buttons on up to eight joysticks/gamepads (see Getting Started - Keyboard Layout for those events which can/cannot be remapped).

Note that there are currently two separate event modes in Stella; emulation mode and user-interface (UI) mode. Each mode has separate mappings, so (for example) while in emulation mode, the left arrow could mean 'joystick 0 left', while in UI mode it could mean 'move cursor left'. Emulation mode occurs whenever you're actually playing a game. UI mode occurs whenever a user interface is present (ROM launcher, debugger, settings menu, etc.). Because of these different modes, there are two separate mapping areas.

To remap an event:

  1. Enter Options Menu and click the Input Settings button.
  2. If you wish to remap emulation events, click the 'Emul. Events' tab. Otherwise, click the 'UI Events' tab for user interface events.
  3. Select event you want to remap and click the 'Map' button.
  4. Press a key or a joystick button, and that key/button will be bound to the selected event. If nothing seems to happen, either Stella can't see the input device, or the selected event doesn't support being remapped to the input device.
  5. Cancel a remap in progress by clicking 'Cancel', erase a mapping by clicking 'Erase', or reset to default mapping by clicking 'Reset'
  6. Reset to default all mappings by clicking 'Defaults'.

The following screenshots illustrate the event remapping process:

There is also a 'Combo' button in the 'Emul. Events' tab, accessible when a Combo event has been selected from the list of events on the left. Clicking 'Combo' will show a dialog similar to the following:

In this dialog, you can assign various events to the selected combo event. Note that this simply assigns multiple events to the combo; you still need to map the combo event itself to some action, as described in the 'remap an event' section above.

Device and port settings can be configured under the 'Devices & Ports' tab, shown below:

    
ItemBrief descriptionFor more information,
see CommandLine
Stelladaptor port orderSpecifies which virtual port each Stelladaptor/2600-daptor uses (See Advanced Configuration - Stelladaptor/2600-daptor Support)-saport
Use mouse as ...Allow the mouse to emulate various controllers-usemouse
Mouse cursor visibilityShow/hide cursor depending on current state-cursor
Joystick deadzone sizeDeadzone area for axes on joysticks/gamepads-joydeadzone
Digital paddle sensitivitySensitivity used when emulating a paddle using a digital device-dsense
Mouse paddle sensitivitySensitivity used when emulating a paddle using a mouse-msense
Trackball sensitivitySensitivity used when emulating a trackball device using a mouse-tsense
Allow all 4 directions ...Allow all 4 joystick directions to be pressed simultaneously-joyallow4
Grab mouse ...Keep mouse in window in emulation mode
(only when used as controller)
-grabmouse
Use Control key combosEnable using Control key in keyboard actions-ctrlcombo
Joystick DatabaseShow all joysticks that Stella knows about, with the option to remove them 
Erase EEPROMErase the whole AtariVox/SaveKey flash memory 
AVox serial portDescribed in further detail in Advanced Configuration - AtariVox/SaveKey Support -avoxport

ROM Launcher

Several options are configurable in the ROM launcher. The size of the launcher and fonts, as well as the 'ROM Info Viewer' can be changed in UI Settings - Launcher dialog, as shown below:

Most of the options are self-explanatory, except for the 'ROM Info viewer', which is described below.

ROM Info Viewer

Stella supports viewing snapshots and ROM properties of the currently selected ROM in the ROM launcher. Support is automatic, as long as your snapshot directory contains snapshots in the appropriate format. An archive of updated snapshots will be available on the Stella webpage. This archive may be updated periodically as new ROMs are found, and also for each new release of Stella. Note that the snapshots can be any size generated by Stella; they will be resized accordingly.

Currently, there are several restrictions for this feature:

  1. The ROM Info Viewer can be shown in 1x or 2x mode only.
  2. To view snapshots in 1x mode, the ROM launcher window must be sized at least 640x480. If the launcher isn't large enough, the functionality will be disabled.
  3. To view snapshots in 2x mode, the ROM launcher window must be sized at least 1000x760. If the launcher isn't large enough, an attempt will be made to use 1x mode.

The following snapshots illustrate the various font sizes and rom info zoom levels:

ROM Info Viewer in 1x mode, UI sized 800x480, small launcher font:

ROM Info Viewer in 1x mode, UI sized 1000x760, medium launcher font:

ROM Info Viewer in 2x mode, UI sized 1400x900, large launcher font:

The text box in the upper right corner can be used to narrow down the results in the ROM listing. When this box is empty, all files are shown (subject to the restrictions from the filtering option, explained below). Typing characters here will show only those files that match that pattern. For example, typing 'Activision' will show only files that contain the word 'Activision' in their name. This is very useful for quickly finding a group of related ROMs. Note that the search is not case sensitive, so you don't need to worry about capital or lower-case letters.

ROM Lauchner Context Menu

The ROM launcher also contains a context menu, selected by clicking the right mouse button anywhere in the current window. This context menu contains the following items:

  1. Power-on options: Selecting this option shows a dialog whereby ROM properties can be temporarily overridden, and joystick/console buttons can be temporarily held down. Selecting options from this dialog will cause all ROMs launched after that to use those properties you specify. Clicking Defaults will disable its functionality, and use ROM properties as defined by the ROM itself. The dialog is as follows (See Advanced Configuration - Game Properties for more information concerning ROM properties):

        
    ItemFor more information,
    see Commandline
    Bankswitch type-bs
    Left Difficulty-ld
    Right Difficulty-rd
    TV Type-tv
    Startup Mode-debug
    Left Joy items-holdjoy0
    Right Joy items-holdjoy1
    Console: Select-holdselect
    Console: Reset-holdreset

  2. Filter listing: Selecting this option shows a dialog whereby one can filter the types of files shown in the listing. The dialog is as follows:

    Currently, the choices are as follows:

    • All files - self explanatory, show all files in the ROM listing. This is the default, and emulates the behaviour of all previous versions of Stella.
    • All roms - show only files with a valid ROM extension. Currently, this means extensions .a26, .bin, .rom, .gz, .zip.
    • ROMs ending with - show only files with a ROM extension as selected from the checkboxes.

  3. Reload listing: Selecting this performs a reload of the current listing. It is an alternative to pressing the Control-r key combo.

ROM Audit Mode

Stella has the ability to rename all your ROMs according to the name specified in the properties database. This is useful if you've downloaded ROMs in DOS 8.3 naming format, and wish the filenames to be more descriptive, or the current filenames are too large to see in the launcher.

This feature is accessible from Options => Audit ROMs, and is only available while in ROM launcher mode. The dialog box for this feature is as follows:

Simply select the ROM path with the 'Audit path' button, and click the 'Audit' button. The ROMs will then be renamed according to their internal properties. When the operation is complete, the number of ROMs that were renamed (as well as ones that weren't) will be shown.

There are several items to take note of:

  • THIS OPERATION CANNOT BE UNDONE. I cannot stress this enough; if you aren't completely sure you want to rename your ROMs, don't use this function. There is no undo feature, and one won't be added.
  • Only filenames that Stella considers to be valid ROMs will be considered. Currently, this means files that end in '.a26', '.bin', '.rom', '.gz' and '.zip'. Files which don't have these extensions will be ignored.
  • If a valid ROM doesn't have a properties entry, it will be ignored.

Stelladaptor/2600-daptor Support

Stella supports real Atari 2600 joysticks, paddles, driving controllers and trackballs (CX22/CX80 'Trak-Ball', Atari and Amiga mouse) using the Stelladaptor and 2600-daptor devices.

Stella can use up to two adaptors; any extra ones are ignored. Stelladaptor devices will be automatically detected and configured. The actual controllers can be plugged/unplugged while the emulator is running, although you will need to restart the game currently being emulated.

The detection and configuration is as follows:

  • The first device found will act as the left game port on a real Atari. Depending on the device, Stella will detect it as either the left joystick, paddles 0 & 1, the left driving controller, left keypad, etc.
  • The second device found will act as the right game port on a real Atari. Depending on the device, Stella will detect it as either the right joystick, paddles 2 & 3, the right driving controller, right keypad, etc.
  • Any other devices will be ignored.
  • The assignment ordering of Stelladaptor/2600-daptor to port can be redefined with 'saport' (see description in Using the Command Line) and dynamically with the 'Control-1' key combo.

AtariVox/SaveKey Support

Stella supports a real AtariVox device for the speech/SpeakJet portion of the controller. You will need a real AtariVox device as well as some means of connecting it to your computer (some sort of serial port/USB adaptor). There should be drivers for your serial convertor, which allow your particular operating system to 'see' the device (configuring this is outside the scope of this document). Once your operating system properly detects the AtariVox, you will need to tell Stella which serial port it is connected to. This is done by using the '-avoxport' commandline argument, or by setting it in the UI under the 'Devices & Ports' tab in Advanced Configuration - Input Devices.

Note that you must use the entire name of the port as specified by your operating system. For example, in Windows this would be COM1, COM2, etc.; Linux and MacOSX tend to use names similar to '/dev/xxxxxx'. For now, only Linux/UNIX, MacOSX, and Windows are supported.

Support for the EEPROM portion of the AtariVox and SaveKey is currently emulated. That is, a file will be created on your computer simulating the EEPROM; the actual EEPROM hardware itself will not be accessed or modified. This is very useful in the testing stages of creating a new game, since writing to a real EEPROM many times will eventually wear it out.

The location of the EEPROM files are configurable through the '-nvramdir' commandline argument and within the application itself (see Advanced Configuration - Config Paths). If the path for these files hasn't been set, the default location will depend on the version of Stella, as follows:

Linux/Unix ~/.stella/nvram/atarivox_eeprom.dat
~/.stella/nvram/savekey_eeprom.dat
Macintosh ~/Library/Application Support/Stella/nvram/atarivox_eeprom.dat
~/Library/Application Support/Stella/nvram/savekey_eeprom.dat
Windows %APPDATA%\Stella\nvram\atarivox_eeprom.dat
%APPDATA%\Stella\nvram\savekey_eeprom.dat
    OR
_BASEDIR_\nvram\atarivox_eeprom.dat
_BASEDIR_\nvram\savekey_eeprom.dat
(if a file named 'basedir.txt' exists in the application directory containing the full pathname for _BASEDIR_)

Note that these EEPROM files will be created when necessary, and initialized as a real EEPROM would be (containing all $FF). The files can be manually deleted, which is very useful in testing cases where a ROM is accessing the EEPROM for the first time. You can also reset the EEPROM to a clean state.

Developer Options/Integrated Debugger

Several developer related options can be configured in the 'Developer Settings' dialog. Two sets ('Player settings', 'Developer settings') allow easy adjustment of all settings for different use cases (playing or developing games) at once.

Developer Settings dialog (Emulator)

    
ItemBrief descriptionFor more information,
see CommandLine
Player/Developer settingsSelects the active settings set-dev.settings
Frame StatisticsOverlay console info on the TIA image during emulation.-plr.stats
-dev.stats
ConsoleSelect the console type, this affects Color/B&W/Pause key emulation and zero-page RAM initialzation-plr.console
-dev.console
Random startup bankRandomize the startup bank (only for selected bankswitch types)-plr.bankrandom
-dev.bankrandom
Randomize zero-page ...When loading a ROM, randomize all RAM content instead of initializing with all zeroes (for 'Console' = 'Atari 2600' only)-plr.ramrandom
-dev.ramrandom
Randomize CPUWhen loading a ROM, randomize the content of the specified CPU registers-plr.cpurandom
-dev.cpurandom
Drive unused TIA pins ...Unused TIA pins are read random instead of the last databus values-plr.tiadriven
-dev.tiadriven
Fatal ARM emulation ... Thumb ARM emulation throws an exception and enters the debugger on fatal errors -plr.thumb.trapfatal
-dev.thumb.trapfatal
Display AtariVox...Display a message when the AtariVox/SaveKey EEPROM is read or written-plr.eepromaccess
-dev.eepromaccess

Developer Settings dialog (Video):

    
ItemBrief descriptionFor more information,
see CommandLine
Jitter/roll effectEmulate screen roll with inconsistent scanline count-plr.tv.jitter
-dev.tv.jitter
(Jitter/roll) RecoveryDetermines recovery time for screen rolling-plr.tv.jitter_recovery
-dev.tv.jitter_recovery
PAL color-lossUse PAL color-loss effect-plr.colorloss
-dev.colorloss
Debug colorsUse fixed debug colors-plr.debugcolors
-dev.debugcolors
Player 0
Missile 0
Player 1
Missile 1
Playfield
Ball
Set color for specific object in 'Debug Colors' mode (PF0, PF1 and PF2 have a slightly different luminance)

Disabled in ROM launcher mode
-tia.dbgcolors

Developer Settings dialog (Time Machine)

    
ItemBrief descriptionFor more information,
see CommandLine
Time Machine When the Time Machine is enabled, Stella will automatically buffer save states in the interval described below. The user can then navigate back and forth within the recorded timeline.
Note: This buffer is identical with the one described in Debugger - Global Buttons. It is independent from the save states manually created with F9.
-plr.timemachine
-dev.timemachine
Buffer size Defines the Time Machine buffer size. The larger the buffer, the less save states have to be compressed to reach the horizon. -plr.tm.size
-dev.tm.size
Uncompressed size (*) Defines the uncompressed Time Machine buffer size. States within this area will not be compressed and keep their initial interval. -plr.tm.uncompressed
-dev.tm.uncompressed
Interval Defines the interval between two save states when they are created. -plr.tm.interval
-dev.tm.interval
Horizon Defines the horizon of the Time Machine. A large horizon allows going back further in time. To reach the horizon, save states will be compressed (*). This means that more and more intermediate states will be removed and the interval between save states becomes larger the further they are back in time.
(*) Compresion only works if 'Uncompressed size' is smaller than 'Buffer size'.
-plr.tm.horizon
-dev.tm.horizon

Developer Settings dialog (Debugger)

    
ItemBrief descriptionFor more information,
see CommandLine
Font sizeSelf-explanatory-dbg.fontsize
Font styleSelf-explanatory-dbg.fontstyle
Debugger width/heightSelf-explanatory-dbg.res
Trap on 'ghost' readsDefines whether the debugger should consider CPU 'ghost' reads for trap adresses.-dbg.ghostreadstrap

Many more options are available for ROM developers, which are described in different sections of this manual, as follows:

  • Developer key-combo shortcuts, used to change TIA state dynamically (ie, while the emulation is still running). See Keyboard Layout - Developer Keys in TIA mode for more information.
  • Commandline options influencing emulation state. See Using the Command Line - Developer Commands for more information.
  • Viewing TIA/console information overlaid on the TIA image. This option can be enabled from the commandline or using the Alt-L key combo, and is extremely useful for viewing the current scanline count and associated frames per second, bankswitch and display formats, etc. The following shows an example of this information:

    The two lines of output describe the following:

    1. Number of scanlines in current frame, associated framerate, and resulting display format. Note that the framerate shown is the internal, virtual framerate (it's calculated from the number of scanlines). If the '*' character is present, it means the display format was auto-detected as shown. For the given example, the format was auto-detected as 'NTSC'.
    2. Cartridge information. If the '*' character is present, it means the bankswitch format was auto-detected as shown. The item in round brackets indicates ROM size. For the given example, the bankswitch type was auto-detected as 4K, and the file size was 4K (4096 bytes).

Finally, Stella contains an extensive, built-in debugger. Have a look at this page for integrated debugger documentation.

Settings File

Stella will remember when you change a setting either at the command line or while the emulation is running, and use the settings the next time you start the emulator. The settings are saved in a text file which can be edited outside of Stella. This file can contain your default options, and eliminates the need to specify them on the command line. Any options specified on the command line will override those in the settings file.

The syntax for the settings file is very straightforward. Any line starting with a ';' character is considered a comment and is ignored. Other lines must be of the form: command = value, where command is the same as that specified on the command line (without the '-' character), and value is dependent on the command.

For example, the following table illustrates how command line and settings entries are similar:

Command Line Settings File
-video opengl video = opengl
-volume 75 volume = 75
-center 1 center = 1 (or center = true)

The settings file has a special name/location depending on which version of Stella you use, which is currently not configurable:

Linux/Unix $HOME/.config/stella/stellarc
Macintosh Not applicable; settings are saved in ~/Library/Preferences/Stella-emu.plist
Windows %APPDATA%\Stella\stella.ini    OR
_BASEDIR_\stella.ini    (if a file named 'basedir.txt' exists in the application directory containing the full pathname for _BASEDIR_)

Cheatcode Manager

Stella contains support for Bob Colbert's Cheetah cheat codes, as well as an extended Stella-specific type of cheat code that works on bankswitched ROMs.

To add/remove/edit a cheat code, enter the 'Cheat Code' dialog:

Currently, there are three types of cheatcodes available, all of which must be entered in hexadecimal format:

  • Per-frame RAM cheats:
    Evaluated each frame, and apply to RAM only. Format as follows:

       4-digit code: c041
       c0 = address
       41 = data
      
  • Cheetah codes, which are explained in detail on Bob Colbert's web page, along with a list of codes for various games. Cheetah codes don't support bankswitched ROMs, so they only work for 2K or 4K ROMs. Format as follows:
       6-digit (cheetah) code: aaaddc
       aaa = address - $f000
       dd = data
       c = count - 1
      
  • Stella extended cheats are similar to Cheetah codes, except that they can be 7 or 8 digits long, with the extra digits used for the bank number:
       7-digit (stella) code: baaaddc
       b = bank (0 to $f)
       aaa = address - $f000
       dd = data
       c = count - 1
    
       8-digit (stella) code: bbaaaddc
       bb = bank (0 to $ff)
       aaa = address - $f000
       dd = data
       c = count - 1
      

There's also the concept of one shot codes. These codes work exactly the same as above, except they aren't saved. They are evaluated once and immediately discarded.

Here are a few cheat codes we've found:

Pitfall (standard Cheetah codes):
   5b0ea1 - infinite lives
   723ea1 - infinite time
   aa5??0 - set starting level, ?? = 01 to ff (d0 is kinda neat)

Battlezone (Stella extended codes):
   1236ea1 - infinite lives

Ms Pac-Man (Stella extended codes):
   108fea1 - infinite lives
  

The name of the cheat database file is configurable through the '-cheatfile' commandline argument and within the application itself (see Advanced Configuration - Config Paths). If the path for this file hasn't been set, the default filename will depend on the version of Stella, as follows:

Linux/Unix $HOME/.config/stella/stella.cht
Macintosh ~/Library/Application Support/Stella/stella.cht
Windows %APPDATA%\Stella\stella.cht    OR
_BASEDIR_\stella.cht    (if a file named 'basedir.txt' exists in the application directory containing the full pathname for _BASEDIR_)

Stella will require a restart for changes to this file to take effect.

Viewing the System Log

Stella maintains a log of its operations when the program first starts up, and while it is running. In older releases, this information was only viewable from the commandline. However, the current release allows you to see this information from within the UI. This can be selected from the main Options menu, where it is labelled "System Logs". Clicking on the button will show a window similar to the following:

    
ItemFor more information,
see Commandline
Log level-loglevel
Print to console-logtoconsole

The log levels are self-explanatory (None, Basic, Verbose). The "Print to console" option emulates the behaviour of older versions of Stella, whereby the logged output is also shown on the commandline from which Stella was launched (if it was launched in that fashion). Finally, the current contents of the system log can be saved to your home directory by clicking the "Save log to disk" button.

Game Properties

Stella uses game properties to specify the "best" emulator settings for a game. As of version 2.2 of Stella, a default database of properties are built-in, but you may modify these through the use of a stella.pro file or within the corresponding Game Properties dialogs. This file will contain all properties modified by the user. So this means that when you upgrade Stella, your personal properties settings are preserved.

Property File

A property file consists of some number of blocks. Each block in the file contains the properties for a single game. For example the general format of a property file is:

   ; Comments
   "Cartridge.MD5"      "Value"
   "Property"           "Value"
   ""

   ; Comments
   "Cartridge.MD5"      "Value"
   "Property"           "Value"
   ""

   . . .

   ; Comments
   "Cartridge.MD5"      "Value"
   "Property"           "Value"
   ""

Every block in the property file must have a unique value for the Cartridge.MD5 property.

Properties

Each block in a property file consists of a set of properties for a single game. Stella supports the properties described below:

Cartridge.MD5: Indicates the MD5 checksum of the ROM image as a string of hexadecimal digits. Stella uses this property while attempting to match a game with its block of properties. If the value of the property matches the MD5 checksum of the ROM image then Stella uses that block of properties for the game. You can use the GNU md5sum program, which is included with most Linux distributions, to calculate the MD5 checksum of a ROM image.
Cartridge.Manufacturer: Indicates the game's manufacturer.
Cartridge.ModelNo: Indicates the manufacturer's model number for the game.
Cartridge.Name: Indicates the actual name of the game. When you save snapshots, load/save state files, or use the ROM Audit Mode functionality, this is the name that will be used for the respective file(s).
Cartridge.Note: Contains any special notes about playing the game.
Cartridge.Rarity: Indicates how rare a cartridge is, based on the scale described on AtariAge.
Cartridge.Sound: Indicates if the game should use 1 or 2 channels for sound output. All original Atari 2600 machines supported 1 channel only, but some homebrew games have been written to take advantage of stereo sound mods. The value must be Mono or Stereo.
Cartridge.Type: Indicates the bank-switching type for the game. The value of this property must be either Auto or one of the following (for more information about bank-switching see Kevin Horton's 2600 bankswitching document or the documentation in each cartridges source code file). Types marked as (¹) do not currently have reliable auto-detection, those marked as (²) are not fully supported in the debugger:
 Type Description
0840 8K ECONObanking
2IN1 ¹4-32K Multicart (2 games)
4IN1 ¹8-32K Multicart (4 games)
8IN1 ¹16-64K Multicart (8 games)
16IN1 ¹32-128K Multicart (16 games)
32IN1 ¹64-128K Multicart (32 games)
64IN1 ¹64/128K Multicart
128IN1 ¹256/512K Multicart
2K 64-2048 byte Atari
3E 32K Tigervision
3E+ 3E+ (TJ modified DASH)
3F 512K Tigervision
4A50 ²64K 4A50 + ram
4K 4K Atari
4KSC CPUWIZ 4K + ram
AR Supercharger
BF CPUWIZ 256K
BFSC CPUWIZ 256K + ram
BUS Experimental
CDF Chris, Darrell, Fred
CM ¹Spectravideo CompuMate
CTY ¹²CDW - Chetiry
CV Commavid extra ram
CV+ Extended Commavid extra ram
DASH Boulder Dash 2
DF CPUWIZ 128K
DFSC CPUWIZ 128K + ram
DPC Pitfall II
DPC+Enhanced DPC
E0 8K Parker Bros
E7 16K M-network
E78K 8K M-network
EF 64K Homestar Runner
EFSC 64K Homestar Runner + ram
F0 Dynacom Megaboy
F4 32K Atari
F4SC 32K Atari + ram
F6 16K Atari
F6SC 16K Atari + ram
F8 8K Atari
F8SC 8K Atari + ram
FA CBS RAM Plus
FA2 CBS RAM Plus 24/28K
FE 8K Decathlon
MDM Menu Driven Megacart
SB 128-256k SUPERbanking
UA 8K UA Ltd.
WD Wickstead Design
X07 ¹64K AtariAge
Console.LeftDifficulty: Indicates the default difficulty setting for the left player. The value must be A or B.
Console.RightDifficulty: Indicates the default difficulty setting for the right player. The value must be A or B.
Console.TelevisionType: Indicates the default television setting for the game. The value must be Color or BW.
https://atariage.com/2600/programming/atarivox_mem_list.html
Controller.Left:
Controller.Right:
Indicates what type of controller the left and right player uses. The value must be one of the following types:
 Type Description
Joystick Atari's famous black joystick that was originally included with the system.
BoosterGrip A controller add-in that plugs directly into the joystick port and provides a pass-through for the joystick. In doing so, it provides the two independent buttons.
Paddles Standard paddle controllers for use with games such as Breakout and Warlords. One pair of controller per connector (allows for 4-player Warlords).
Paddles_IAxis Same as Paddles, except the axes are inverted.
Paddles_IDir Same as Paddles, except the direction of movement is inverted.
Paddles_IAxDr Same as Paddles, except both the axes and direction of movement is inverted.
Driving Looks like a paddle, but allows 360' movement. Only one unit per connector, unlike paddles which were sold in pairs.
Keyboard Also known as the Star Raiders controller, functionally identical to the Kid's Controller and Keyboard Controller. Game included an overlay with commands, for use with Star Raiders.
AmigaMouseCommodore Amiga computer mouse.
AtariMouse Atari ST computer mouse.
Trakball Standard Atari 2600 CX22/CX80 'Trak-Ball' controller.
AtariVoxA SpeakJet based unlimited-vocabulary speech/sound synthesizer with 32K EEPROM.
SaveKey A 32K EEPROM for saving high scores, etc. (the EEPROM portion of an AtariVox).
Genesis Sega Genesis controller, which can be used similar to a BoosterGrip, giving an extra button.
CompuMate Spectravideo CompuMate (if either left or right is set, CompuMate is used for both).
Mindlink Mindlink controller.
Console.SwapPorts: Indicates that the left and right ports should be swapped internally. This is used for ROMs like 'Raiders of the Lost Ark' where the Player 0 joystick is plugged into the right joystick port. The value must be Yes or No.
Controller.SwapPaddles: Indicates that the left and right paddles in a particular port should be swapped. This is used for ROMs like 'Demons to Diamonds' where the default paddle is paddle 1, not paddle 0. Other ROMs such as 'Tac-Scan' default to paddle 3, which can be set using both 'Controller.SwapPaddles' and 'Console.SwapPorts'. The value must be Yes or No.
Controller.MouseAxis: Indicates how the mouse should emulate virtual controllers. In 'Auto' mode, the system decides how to best use the mouse. Otherwise, XY indicates how to use the X/Y axis (ie, 02 is paddle0/paddle2). Currently, the mouse X-axis and left button are tied together, as are the Y-axis and right button. The value must be Auto or XY, as follows:
 Id Controller
0 Paddle 0
1 Paddle 1
2 Paddle 2
3 Paddle 3
4 Driving 0
5 Driving 1
6 MindLink 0
7 MindLink 1
An optional second parameter (default of 100) indicates how much of the paddle range that the mouse should emulate.
Display.Format: Indicates the television format the game was designed for. The value must be Auto, NTSC, PAL, SECAM, NTSC50, PAL60 or SECAM60.
Display.YStart: Indicates the scan-line to start displaying at. The value must be n such that 0 <= n <= 64. Setting n to zero will enable ystart autodetection, which should work fine for the vast majority of ROMs.
Display.Height: Indicates the number of scan-lines to display. The value must be n such that 210 <= n <= 256.
Display.Phosphor: Indicates whether the phosphor effect should be emulated or not. The value must be Yes or No.
Display.PPBlend: Indicates the amount of blending which will occur while using the phosphor effect. The value must be n such that 0 <= n <= 100. The default value is whatever is specified for tv.phosblend.

The name of the properties file is configurable through the '-propsfile' commandline argument and within the application itself (see Advanced Configuration - Config Paths). If the path for this file hasn't been set, the default filename will depend on the version of Stella, as follows:

Linux/Unix $HOME/.config/stella/stella.pro
Macintosh ~/Library/Application Support/Stella/stella.pro
Windows %APPDATA%\Stella\stella.pro    OR
_BASEDIR_\stella.pro    (if a file named 'basedir.txt' exists in the application directory containing the full pathname for _BASEDIR_)

Stella will require a restart for changes to this file to take effect.

Palette Support

An Atari 2600 palette consists of 128 colours, which are different for the three major television standards (NTSC, PAL, SECAM). Stella supports two built-in palettes and one user-defined palette for each format. These are set using the '-palette' option, and are described as follows:

standard The default palette from Stella 1.4 onwards.
z26 The palette from the z26 emulator.
user An external palette file, supplied by the user.

A user-defined palette has certain restrictions, further described as follows:

  • The palette file must be at least 792 bytes long. Colours are stored in 24-bit RGB, with the first byte for red, the second for green, the third for blue, for a total of 3 bytes per colour.
  • The first 384 bytes of the file (128 * 3) will be used for the NTSC palette. The next 384 bytes (128 * 3) will be for the PAL palette. The next 24 bytes (8 * 3) will be for the SECAM palette, which consists of eight distinct colours. Any extra data in the file will be ignored.
  • The PAL colour-loss effect is calculated within Stella. You do not need to specify those colours in the palette file.

The name of the palette file is configurable through the '-palettefile' commandline argument and within the application itself (see Advanced Configuration - Config Paths). If the path for this file hasn't been set, the default filename will depend on the version of Stella, as follows:

Linux/Unix $HOME/.config/stella/stella.pal
Macintosh ~/Library/Application Support/Stella/stella.pal
Windows %APPDATA%\Stella\stella.pal    OR
_BASEDIR_\stella.pal    (if a file named 'basedir.txt' exists in the application directory containing the full pathname for _BASEDIR_)

Note that to actually use the external palette, the palette file must exist and be valid, and the palette option should be set to user (in Video Settings dialog). The current ROM will have to be reloaded for changes to this file to take effect.



Acknowledgments


Bradford W. Mott started developing Stella during the fall of 1995, and Stephen Anthony has maintained the project since around 2004. Over the years, a number of people from around the world have contributed to the project. Some people have provided technical help while others have offered suggestions and praise. The Stella Team is grateful for all the help and support it has received over the years. A (likely incomplete) list of the people who have played a part in bringing Stella to you is available on the main Stella webpage Credits List. If we've missed someone, please let us know.



License and Disclaimer


GNU GENERAL PUBLIC LICENSE

Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA

Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

  • a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.

  • b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.

  • c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

  • a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

  • b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

  • c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. stella-5.1.1/src/000077500000000000000000000000001324334165500135775ustar00rootroot00000000000000stella-5.1.1/src/cheat/000077500000000000000000000000001324334165500146635ustar00rootroot00000000000000stella-5.1.1/src/cheat/BankRomCheat.cxx000066400000000000000000000044461324334165500177150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Console.hxx" #include "Cart.hxx" #include "OSystem.hxx" #include "BankRomCheat.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BankRomCheat::BankRomCheat(OSystem& os, const string& name, const string& code) : Cheat(os, name, code) { if(myCode.length() == 7) myCode = "0" + code; bank = unhex(myCode.substr(0, 2)); address = 0xf000 + unhex(myCode.substr(2, 3)); value = unhex(myCode.substr(5, 2)); count = unhex(myCode.substr(7, 1)) + 1; // Back up original data; we need this if the cheat is ever disabled for(int i = 0; i < count; ++i) savedRom[i] = myOSystem.console().cartridge().peek(address + i); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool BankRomCheat::enable() { evaluate(); return myEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool BankRomCheat::disable() { int oldBank = myOSystem.console().cartridge().getBank(); myOSystem.console().cartridge().bank(bank); for(int i = 0; i < count; ++i) myOSystem.console().cartridge().patch(address + i, savedRom[i]); myOSystem.console().cartridge().bank(oldBank); return myEnabled = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BankRomCheat::evaluate() { if(!myEnabled) { int oldBank = myOSystem.console().cartridge().getBank(); myOSystem.console().cartridge().bank(bank); for(int i = 0; i < count; ++i) myOSystem.console().cartridge().patch(address + i, value); myOSystem.console().cartridge().bank(oldBank); myEnabled = true; } } stella-5.1.1/src/cheat/BankRomCheat.hxx000066400000000000000000000026551324334165500177220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef BANK_ROM_CHEAT_HXX #define BANK_ROM_CHEAT_HXX #include "Cheat.hxx" class BankRomCheat : public Cheat { public: BankRomCheat(OSystem& os, const string& name, const string& code); virtual ~BankRomCheat() = default; bool enable() override; bool disable() override; void evaluate() override; private: uInt8 savedRom[16]; uInt16 address; uInt8 value; uInt8 count; int bank; private: // Following constructors and assignment operators not supported BankRomCheat() = delete; BankRomCheat(const BankRomCheat&) = delete; BankRomCheat(BankRomCheat&&) = delete; BankRomCheat& operator=(const BankRomCheat&) = delete; BankRomCheat& operator=(BankRomCheat&&) = delete; }; #endif stella-5.1.1/src/cheat/Cheat.hxx000066400000000000000000000036521324334165500164460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CHEAT_HXX #define CHEAT_HXX class OSystem; #include "bspf.hxx" class Cheat { public: Cheat(OSystem& osystem, const string& name, const string& code) : myOSystem(osystem), myName(name == "" ? code : name), myCode(code), myEnabled(false) { } virtual ~Cheat() = default; bool enabled() const { return myEnabled; } const string& name() const { return myName; } const string& code() const { return myCode; } virtual bool enable() = 0; virtual bool disable() = 0; virtual void evaluate() = 0; protected: static uInt16 unhex(const string& hex) { int ret = 0; for(char c: hex) { ret *= 16; if(c >= '0' && c <= '9') ret += c - '0'; else if(c >= 'A' && c <= 'F') ret += c - 'A' + 10; else ret += c - 'a' + 10; } return ret; } protected: OSystem& myOSystem; string myName; string myCode; bool myEnabled; private: // Following constructors and assignment operators not supported Cheat() = delete; Cheat(const Cheat&) = delete; Cheat(Cheat&&) = delete; Cheat& operator=(const Cheat&) = delete; Cheat& operator=(Cheat&&) = delete; }; #endif stella-5.1.1/src/cheat/CheatCodeDialog.cxx000066400000000000000000000177561324334165500203660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Cheat.hxx" #include "CheatManager.hxx" #include "CheckListWidget.hxx" #include "DialogContainer.hxx" #include "Dialog.hxx" #include "Font.hxx" #include "InputTextDialog.hxx" #include "OSystem.hxx" #include "Props.hxx" #include "Widget.hxx" #include "CheatCodeDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font) : Dialog(osystem, parent) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos; WidgetArray wid; ButtonWidget* b; // Set real dimensions _w = 46 * fontWidth + 10; _h = 11 * (lineHeight + 4) + 10; // List of cheats, with checkboxes to enable/disable xpos = 10; ypos = 10; myCheatList = new CheckListWidget(this, font, xpos, ypos, _w - buttonWidth - 25, _h - 2*buttonHeight - 10); myCheatList->setEditable(false); wid.push_back(myCheatList); xpos += myCheatList->getWidth() + 5; ypos = 15; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Add" + ELLIPSIS, kAddCheatCmd); wid.push_back(b); ypos += lineHeight + 10; myEditButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Edit" + ELLIPSIS, kEditCheatCmd); wid.push_back(myEditButton); ypos += lineHeight + 10; myRemoveButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Remove", kRemCheatCmd); wid.push_back(myRemoveButton); ypos += lineHeight + 10; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "One shot" + ELLIPSIS, kAddOneShotCmd); wid.push_back(b); // Inputbox which will pop up when adding/editing a cheat StringList labels; labels.push_back("Name "); labels.push_back("Code (hex) "); myCheatInput = make_unique(this, font, labels); myCheatInput->setTarget(this); // Add filtering for each textfield EditableWidget::TextFilter f0 = [](char c) { return isprint(c) && c != '\"' && c != ':'; }; myCheatInput->setTextFilter(f0, 0); EditableWidget::TextFilter f1 = [](char c) { return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9'); }; myCheatInput->setTextFilter(f1, 1); addToFocusList(wid); // Add OK and Cancel buttons wid.clear(); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheatCodeDialog::~CheatCodeDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatCodeDialog::loadConfig() { // Load items from CheatManager // Note that the items are always in the same order/number as given in // the CheatManager, so the arrays will be one-to-one StringList l; BoolArray b; const CheatList& list = instance().cheat().list(); for(const auto& c: list) { l.push_back(c->name()); b.push_back(bool(c->enabled())); } myCheatList->setList(l, b); // Redraw the list, auto-selecting the first item if possible myCheatList->setSelected(l.size() > 0 ? 0 : -1); bool enabled = (list.size() > 0); myEditButton->setEnabled(enabled); myRemoveButton->setEnabled(enabled); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatCodeDialog::saveConfig() { // Inspect checkboxes for enable/disable codes const CheatList& list = instance().cheat().list(); for(uInt32 i = 0; i < myCheatList->getList().size(); ++i) { if(myCheatList->getState(i)) list[i]->enable(); else list[i]->disable(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatCodeDialog::addCheat() { myCheatInput->show(); // Center input dialog over entire screen myCheatInput->setText("", 0); myCheatInput->setText("", 1); myCheatInput->setTitle(""); myCheatInput->setFocus(0); myCheatInput->setEmitSignal(kCheatAdded); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatCodeDialog::editCheat() { int idx = myCheatList->getSelected(); if(idx < 0) return; const CheatList& list = instance().cheat().list(); const string& name = list[idx]->name(); const string& code = list[idx]->code(); myCheatInput->show(); // Center input dialog over entire screen myCheatInput->setText(name, 0); myCheatInput->setText(code, 1); myCheatInput->setTitle(""); myCheatInput->setFocus(1); myCheatInput->setEmitSignal(kCheatEdited); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatCodeDialog::removeCheat() { instance().cheat().remove(myCheatList->getSelected()); loadConfig(); // reload the cheat list } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatCodeDialog::addOneShotCheat() { myCheatInput->show(); // Center input dialog over entire screen myCheatInput->setText("One-shot cheat", 0); myCheatInput->setText("", 1); myCheatInput->setTitle(""); myCheatInput->setFocus(1); myCheatInput->setEmitSignal(kOneShotCheatAdded); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kCloseCmd: close(); break; case ListWidget::kDoubleClickedCmd: editCheat(); break; case kAddCheatCmd: addCheat(); break; case kEditCheatCmd: editCheat(); break; case kCheatAdded: { const string& name = myCheatInput->getResult(0); const string& code = myCheatInput->getResult(1); if(instance().cheat().isValidCode(code)) { myCheatInput->close(); instance().cheat().add(name, code); loadConfig(); // show changes onscreen } else myCheatInput->setTitle("Invalid code"); break; } case kCheatEdited: { const string& name = myCheatInput->getResult(0); const string& code = myCheatInput->getResult(1); bool enable = myCheatList->getSelectedState(); int idx = myCheatList->getSelected(); if(instance().cheat().isValidCode(code)) { myCheatInput->close(); instance().cheat().add(name, code, enable, idx); loadConfig(); // show changes onscreen } else myCheatInput->setTitle("Invalid code"); break; } case kRemCheatCmd: removeCheat(); break; case kAddOneShotCmd: addOneShotCheat(); break; case kOneShotCheatAdded: { const string& name = myCheatInput->getResult(0); const string& code = myCheatInput->getResult(1); if(instance().cheat().isValidCode(code)) { myCheatInput->close(); instance().cheat().addOneShot(name, code); } else myCheatInput->setTitle("Invalid code"); break; } default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/cheat/CheatCodeDialog.hxx000066400000000000000000000042521324334165500203560ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CHEAT_CODE_DIALOG_HXX #define CHEAT_CODE_DIALOG_HXX class DialogContainer; class CommandSender; class Widget; class ButtonWidget; class StaticTextWidget; class CheckListWidget; class EditTextWidget; class OptionsDialog; class InputTextDialog; class OSystem; #include "Dialog.hxx" class CheatCodeDialog : public Dialog { public: CheatCodeDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); virtual ~CheatCodeDialog(); protected: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void loadConfig() override; void saveConfig() override; private: void addCheat(); void editCheat(); void removeCheat(); void addOneShotCheat(); private: CheckListWidget* myCheatList; unique_ptr myCheatInput; ButtonWidget* myEditButton; ButtonWidget* myRemoveButton; enum { kAddCheatCmd = 'CHTa', kEditCheatCmd = 'CHTe', kAddOneShotCmd = 'CHTo', kCheatAdded = 'CHad', kCheatEdited = 'CHed', kOneShotCheatAdded = 'CHoa', kRemCheatCmd = 'CHTr' }; private: // Following constructors and assignment operators not supported CheatCodeDialog() = delete; CheatCodeDialog(const CheatCodeDialog&) = delete; CheatCodeDialog(CheatCodeDialog&&) = delete; CheatCodeDialog& operator=(const CheatCodeDialog&) = delete; CheatCodeDialog& operator=(CheatCodeDialog&&) = delete; }; #endif stella-5.1.1/src/cheat/CheatManager.cxx000066400000000000000000000215611324334165500177330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Console.hxx" #include "Cheat.hxx" #include "Settings.hxx" #include "CheetahCheat.hxx" #include "BankRomCheat.hxx" #include "RamCheat.hxx" #include "Vec.hxx" #include "CheatManager.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheatManager::CheatManager(OSystem& osystem) : myOSystem(osystem), myListIsDirty(false) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CheatManager::add(const string& name, const string& code, bool enable, int idx) { shared_ptr cheat = createCheat(name, code); if(!cheat) return false; // Delete duplicate entries for(uInt32 i = 0; i < myCheatList.size(); i++) { if(myCheatList[i]->name() == name || myCheatList[i]->code() == code) { Vec::removeAt(myCheatList, i); break; } } // Add the cheat to the main cheat list if(idx == -1) myCheatList.push_back(cheat); else Vec::insertAt(myCheatList, idx, cheat); // And enable/disable it (the cheat knows how to enable or disable itself) if(enable) cheat->enable(); else cheat->disable(); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::remove(int idx) { if(uInt32(idx) < myCheatList.size()) { // This will also remove it from the per-frame list (if applicable) myCheatList[idx]->disable(); // Then remove it from the cheatlist entirely Vec::removeAt(myCheatList, idx); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::addPerFrame(const string& name, const string& code, bool enable) { // The actual cheat will always be in the main list; we look there first shared_ptr cheat; for(auto& c: myCheatList) { if(c->name() == name || c->code() == code) { cheat = c; break; } } // Make sure there are no duplicates bool found = false; uInt32 i; for(i = 0; i < myPerFrameList.size(); i++) { if(myPerFrameList[i]->code() == cheat->code()) { found = true; break; } } if(enable) { if(!found) myPerFrameList.push_back(cheat); } else { if(found) Vec::removeAt(myPerFrameList, i); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::addOneShot(const string& name, const string& code) { // Evaluate this cheat once, and then immediately discard it shared_ptr cheat = createCheat(name, code); if(cheat) cheat->evaluate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - shared_ptr CheatManager::createCheat(const string& name, const string& code) const { if(!isValidCode(code)) return nullptr; // Create new cheat based on string length switch(code.size()) { case 4: return make_shared(myOSystem, name, code); case 6: return make_shared(myOSystem, name, code); case 7: return make_shared(myOSystem, name, code); case 8: return make_shared(myOSystem, name, code); default: return nullptr; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::parse(const string& cheats) { StringList s; string::size_type lastPos = cheats.find_first_not_of(",", 0); string::size_type pos = cheats.find_first_of(",", lastPos); string cheat, name, code; // Split string by comma, getting each cheat while(string::npos != pos || string::npos != lastPos) { // Get the next cheat cheat = cheats.substr(lastPos, pos - lastPos); // Split cheat by colon, separating each part string::size_type lastColonPos = cheat.find_first_not_of(":", 0); string::size_type colonPos = cheat.find_first_of(":", lastColonPos); while(string::npos != colonPos || string::npos != lastColonPos) { s.push_back(cheat.substr(lastColonPos, colonPos - lastColonPos)); lastColonPos = cheat.find_first_not_of(":", colonPos); colonPos = cheat.find_first_of(":", lastColonPos); } // Account for variable number of items specified for cheat switch(s.size()) { case 1: name = s[0]; code = name; add(name, code, true); break; case 2: name = s[0]; code = s[1]; add(name, code, true); break; case 3: name = s[0]; code = s[1]; add(name, code, s[2] == "1"); break; } s.clear(); lastPos = cheats.find_first_not_of(",", pos); pos = cheats.find_first_of(",", lastPos); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::enable(const string& code, bool enable) { for(const auto& cheat: myCheatList) { if(cheat->code() == code) { if(enable) cheat->enable(); else cheat->disable(); break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::loadCheatDatabase() { const string& cheatfile = myOSystem.cheatFile(); ifstream in(cheatfile); if(!in) return; string line, md5, cheat; string::size_type one, two, three, four; // Loop reading cheats while(getline(in, line)) { if(line.length() == 0) continue; one = line.find("\"", 0); two = line.find("\"", one + 1); three = line.find("\"", two + 1); four = line.find("\"", three + 1); // Invalid line if it doesn't contain 4 quotes if((one == string::npos) || (two == string::npos) || (three == string::npos) || (four == string::npos)) break; // Otherwise get the ms5sum and associated cheats md5 = line.substr(one + 1, two - one - 1); cheat = line.substr(three + 1, four - three - 1); myCheatMap.emplace(md5, cheat); } myListIsDirty = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::saveCheatDatabase() { if(!myListIsDirty) return; const string& cheatfile = myOSystem.cheatFile(); ofstream out(cheatfile); if(!out) return; for(const auto& iter: myCheatMap) out << "\"" << iter.first << "\" " << "\"" << iter.second << "\"" << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::loadCheats(const string& md5sum) { myPerFrameList.clear(); myCheatList.clear(); myCurrentCheat = ""; // Set up any cheatcodes that was on the command line // (and remove the key from the settings, so they won't get set again) const string& cheats = myOSystem.settings().getString("cheat"); if(cheats != "") myOSystem.settings().setValue("cheat", ""); const auto& iter = myCheatMap.find(md5sum); if(iter == myCheatMap.end() && cheats == "") return; // Remember the cheats for this ROM myCurrentCheat = iter->second; // Parse the cheat list, constructing cheats and adding them to the manager parse(iter->second + cheats); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheatManager::saveCheats(const string& md5sum) { ostringstream cheats; for(uInt32 i = 0; i < myCheatList.size(); i++) { cheats << myCheatList[i]->name() << ":" << myCheatList[i]->code() << ":" << myCheatList[i]->enabled(); if(i+1 < myCheatList.size()) cheats << ","; } bool changed = cheats.str() != myCurrentCheat; // Only update the list if absolutely necessary if(changed) { auto iter = myCheatMap.find(md5sum); // Erase old entry and add a new one only if it's changed if(iter != myCheatMap.end()) myCheatMap.erase(iter); // Add new entry only if there are any cheats defined if(cheats.str() != "") myCheatMap.emplace(md5sum, cheats.str()); } // Update the dirty flag myListIsDirty = myListIsDirty || changed; myPerFrameList.clear(); myCheatList.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CheatManager::isValidCode(const string& code) const { for(char c: code) if(!isxdigit(c)) return false; uInt32 length = uInt32(code.length()); return (length == 4 || length == 6 || length == 7 || length == 8); } stella-5.1.1/src/cheat/CheatManager.hxx000066400000000000000000000114101324334165500177300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CHEAT_MANAGER_HXX #define CHEAT_MANAGER_HXX #include class Cheat; class OSystem; #include "bspf.hxx" using CheatList = vector>; /** This class provides an interface for performing all cheat operations in Stella. It is accessible from the OSystem interface, and contains the list of all cheats currently in use. @author Stephen Anthony */ class CheatManager { public: CheatManager(OSystem& osystem); /** Adds the specified cheat to an internal list. @param name Name of the cheat (not absolutely required) @param code The actual cheatcode (in hex) @param enable Whether to enable this cheat right away @param idx Index at which to insert the cheat @return Whether the cheat was created and enabled. */ bool add(const string& name, const string& code, bool enable = true, int idx = -1); /** Remove the cheat at 'idx' from the cheat list(s). @param idx Location in myCheatList of the cheat to remove */ void remove(int idx); /** Adds the specified cheat to the internal per-frame list. This method doesn't create a new cheat; it just adds/removes an already created cheat to the per-frame list. @param name Name of the cheat @param code The actual cheatcode @param enable Add or remove the cheat to the per-frame list */ void addPerFrame(const string& name, const string& code, bool enable); /** Creates and enables a one-shot cheat. One-shot cheats are the same as normal cheats, except they are only enabled once, and they're not saved at all. @param name Name of the cheat (not absolutely required) @param code The actual cheatcode (in hex) */ void addOneShot(const string& name, const string& code); /** Enable/disabled the cheat specified by the given code. @param code The actual cheatcode to search for @param enable Enable/disable the cheat */ void enable(const string& code, bool enable); /** Returns the game cheatlist. */ const CheatList& list() { return myCheatList; } /** Returns the per-frame cheatlist (needed to evaluate cheats each frame) */ const CheatList& perFrame() { return myPerFrameList; } /** Load all cheats (for all ROMs) from disk to internal database. */ void loadCheatDatabase(); /** Save all cheats (for all ROMs) in internal database to disk. */ void saveCheatDatabase(); /** Load cheats for ROM with given MD5sum to cheatlist(s). */ void loadCheats(const string& md5sum); /** Saves cheats for ROM with given MD5sum to cheat map. */ void saveCheats(const string& md5sum); /** Checks if a code is valid. */ bool isValidCode(const string& code) const; private: /** Create a cheat defined by the given code. @param name Name of the cheat (not absolutely required) @param code The actual cheatcode (in hex) @return The cheat (if was created), else nullptr. */ shared_ptr createCheat(const string& name, const string& code) const; /** Parses a list of cheats and adds/enables each one. @param cheats Comma-separated list of cheats (without any names) */ void parse(const string& cheats); private: OSystem& myOSystem; CheatList myCheatList; CheatList myPerFrameList; std::map myCheatMap; string myCheatFile; // This is set each time a new cheat/ROM is loaded, for later // comparison to see if the cheatcode list has actually been modified string myCurrentCheat; // Indicates that the list has been modified, and should be saved to disk bool myListIsDirty; private: // Following constructors and assignment operators not supported CheatManager() = delete; CheatManager(const CheatManager&) = delete; CheatManager(CheatManager&&) = delete; CheatManager& operator=(const CheatManager&) = delete; CheatManager& operator=(CheatManager&&) = delete; }; #endif stella-5.1.1/src/cheat/CheetahCheat.cxx000066400000000000000000000036121324334165500177170ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Console.hxx" #include "Cart.hxx" #include "OSystem.hxx" #include "CheetahCheat.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheetahCheat::CheetahCheat(OSystem& os, const string& name, const string& code) : Cheat(os, name, code) { address = 0xf000 + unhex(code.substr(0, 3)); value = unhex(code.substr(3, 2)); count = unhex(code.substr(5, 1)) + 1; // Back up original data; we need this if the cheat is ever disabled for(int i = 0; i < count; ++i) savedRom[i] = myOSystem.console().cartridge().peek(address + i); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CheetahCheat::enable() { evaluate(); return myEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CheetahCheat::disable() { for(int i = 0; i < count; ++i) myOSystem.console().cartridge().patch(address + i, savedRom[i]); return myEnabled = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheetahCheat::evaluate() { if(!myEnabled) { for(int i = 0; i < count; ++i) myOSystem.console().cartridge().patch(address + i, value); myEnabled = true; } } stella-5.1.1/src/cheat/CheetahCheat.hxx000066400000000000000000000026321324334165500177250ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CHEETAH_CHEAT_HXX #define CHEETAH_CHEAT_HXX #include "Cheat.hxx" class CheetahCheat : public Cheat { public: CheetahCheat(OSystem& os, const string& name, const string& code); virtual ~CheetahCheat() = default; bool enable() override; bool disable() override; void evaluate() override; private: uInt8 savedRom[16]; uInt16 address; uInt8 value; uInt8 count; private: // Following constructors and assignment operators not supported CheetahCheat() = delete; CheetahCheat(const CheetahCheat&) = delete; CheetahCheat(CheetahCheat&&) = delete; CheetahCheat& operator=(const CheetahCheat&) = delete; CheetahCheat& operator=(CheetahCheat&&) = delete; }; #endif stella-5.1.1/src/cheat/RamCheat.cxx000066400000000000000000000033051324334165500170740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Console.hxx" #include "System.hxx" #include "OSystem.hxx" #include "CheatManager.hxx" #include "RamCheat.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RamCheat::RamCheat(OSystem& os, const string& name, const string& code) : Cheat(os, name, code) { address = uInt16(unhex(myCode.substr(0, 2))); value = uInt8(unhex(myCode.substr(2, 2))); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RamCheat::enable() { if(!myEnabled) { myEnabled = true; myOSystem.cheat().addPerFrame(name(), code(), myEnabled); } return myEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RamCheat::disable() { if(myEnabled) { myEnabled = false; myOSystem.cheat().addPerFrame(name(), code(), myEnabled); } return myEnabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamCheat::evaluate() { myOSystem.console().system().poke(address, value); } stella-5.1.1/src/cheat/RamCheat.hxx000066400000000000000000000024671324334165500171110ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef RAM_CHEAT_HXX #define RAM_CHEAT_HXX #include "Cheat.hxx" class RamCheat : public Cheat { public: RamCheat(OSystem& os, const string& name, const string& code); virtual ~RamCheat() = default; bool enable() override; bool disable() override; void evaluate() override; private: uInt16 address; uInt8 value; private: // Following constructors and assignment operators not supported RamCheat() = delete; RamCheat(const RamCheat&) = delete; RamCheat(RamCheat&&) = delete; RamCheat& operator=(const RamCheat&) = delete; RamCheat& operator=(RamCheat&&) = delete; }; #endif stella-5.1.1/src/cheat/module.mk000066400000000000000000000004041324334165500164770ustar00rootroot00000000000000MODULE := src/cheat MODULE_OBJS := \ src/cheat/CheatCodeDialog.o \ src/cheat/CheatManager.o \ src/cheat/CheetahCheat.o \ src/cheat/BankRomCheat.o \ src/cheat/RamCheat.o MODULE_DIRS += \ src/cheat # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/common/000077500000000000000000000000001324334165500150675ustar00rootroot00000000000000stella-5.1.1/src/common/Base.cxx000066400000000000000000000074021324334165500164700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Base.hxx" namespace Common { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Base::setHexUppercase(bool enable) { if(enable) { myHexflags |= std::ios_base::uppercase; myFmt = Base::myUpperFmt; } else { myHexflags &= ~std::ios_base::uppercase; myFmt = Base::myLowerFmt; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Base::toString(int value, Common::Base::Format outputBase) { static char vToS_buf[32]; if(outputBase == Base::F_DEFAULT) outputBase = myDefaultBase; // Note: generates warnings about 'nonliteral' format switch(outputBase) { case Base::F_2: // base 2: 8 or 16 bits (depending on value) case Base::F_2_8: // base 2: 1 byte (8 bits) wide case Base::F_2_16: // base 2: 2 bytes (16 bits) wide { int places = (outputBase == Base::F_2_8 || (outputBase == Base::F_2 && value < 0x100)) ? 8 : 16; vToS_buf[places] = '\0'; int bit = 1; while(--places >= 0) { if(value & bit) vToS_buf[places] = '1'; else vToS_buf[places] = '0'; bit <<= 1; } break; } case Base::F_10: // base 10: 3 or 5 bytes (depending on value) if(value < 0x100) std::snprintf(vToS_buf, 4, "%3d", value); else std::snprintf(vToS_buf, 6, "%5d", value); break; case Base::F_10_2: // base 10: 2 digits std::snprintf(vToS_buf, 3, "%02d", value); break; case Base::F_16_1: // base 16: 1 byte wide std::snprintf(vToS_buf, 2, myFmt[0], value); break; case Base::F_16_2: // base 16: 2 bytes wide std::snprintf(vToS_buf, 3, myFmt[1], value); break; case Base::F_16_2_2: std::snprintf(vToS_buf, 6, "%02X.%02X", value >> 8, value & 0xff ); break; case Base::F_16_3_2: std::snprintf(vToS_buf, 7, "%03X.%02X", value >> 8, value & 0xff ); break; case Base::F_16_4: // base 16: 4 bytes wide std::snprintf(vToS_buf, 5, myFmt[2], value); break; case Base::F_16_8: // base 16: 8 bytes wide std::snprintf(vToS_buf, 9, myFmt[3], value); break; case Base::F_16: // base 16: 2, 4, 8 bytes (depending on value) default: if(value < 0x100) std::snprintf(vToS_buf, 3, myFmt[1], value); else if(value < 0x10000) std::snprintf(vToS_buf, 5, myFmt[2], value); else std::snprintf(vToS_buf, 9, myFmt[3], value); break; } return string(vToS_buf); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Base::Format Base::myDefaultBase = Base::F_16; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - std::ios_base::fmtflags Base::myHexflags = std::ios_base::hex; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* const Base::myLowerFmt[4] = { "%1x", "%02x", "%04x", "%08x" }; const char* const Base::myUpperFmt[4] = { "%1X", "%02X", "%04X", "%08X" }; const char* const* Base::myFmt = Base::myLowerFmt; } // Namespace Common stella-5.1.1/src/common/Base.hxx000066400000000000000000000075371324334165500165060ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef BASE_HXX #define BASE_HXX #include #include #include "bspf.hxx" namespace Common { /** This class implements several functions for converting integer data into strings in multiple bases, with different formats (# of characters, upper/lower-case, etc). @author Stephen Anthony */ class Base { public: // The base to use for conversion from integers to strings // Note that the actual number of places will be determined by // the magnitude of the value itself in the general case enum Format { F_16, // base 16: 2, 4, 8 bytes (depending on value) F_16_1, // base 16: 1 byte wide F_16_2, // base 16: 2 bytes wide F_16_2_2, // base 16: fractional value shown as xx.xx F_16_3_2, // base 16: fractional value shown as xxx.xx F_16_4, // base 16: 4 bytes wide F_16_8, // base 16: 8 bytes wide F_10, // base 10: 3 or 5 bytes (depending on value) F_10_2, // base 10: 2 digits F_2, // base 2: 8 or 16 bits (depending on value) F_2_8, // base 2: 1 byte (8 bits) wide F_2_16, // base 2: 2 bytes (16 bits) wide F_DEFAULT }; public: /** Get/set the number base when parsing numeric values */ static void setFormat(Base::Format base) { myDefaultBase = base; } static Base::Format format() { return myDefaultBase; } /** Get/set HEX output to be upper/lower case */ static void setHexUppercase(bool enable); static bool hexUppercase() { return myHexflags & std::ios_base::uppercase; } /** Output HEX digits in 0.5/1/2/4 byte format */ static inline std::ostream& HEX1(std::ostream& os) { os.flags(myHexflags); return os << std::setw(1); } static inline std::ostream& HEX2(std::ostream& os) { os.flags(myHexflags); return os << std::setw(2) << std::setfill('0'); } static inline std::ostream& HEX3(std::ostream& os) { os.flags(myHexflags); return os << std::setw(3) << std::setfill('0'); } static inline std::ostream& HEX4(std::ostream& os) { os.flags(myHexflags); return os << std::setw(4) << std::setfill('0'); } static inline std::ostream& HEX8(std::ostream& os) { os.flags(myHexflags); return os << std::setw(8) << std::setfill('0'); } /** Convert integer to a string in the given base format */ static string toString(int value, Common::Base::Format outputBase = Common::Base::F_DEFAULT); private: // Default format to use when none is specified static Format myDefaultBase; // Upper or lower case for HEX digits static std::ios_base::fmtflags myHexflags; // Format specifiers to use for sprintf (eventually we may convert // to C++ streams static ostringstream buf; static const char* const myLowerFmt[4]; static const char* const myUpperFmt[4]; static const char* const* myFmt; private: // Following constructors and assignment operators not supported Base() = delete; Base(const Base&) = delete; Base(Base&&) = delete; Base& operator=(const Base&) = delete; Base& operator=(Base&&) = delete; }; } // Namespace Common #endif stella-5.1.1/src/common/EventHandlerSDL2.cxx000066400000000000000000000156461324334165500206330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "EventHandlerSDL2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandlerSDL2::EventHandlerSDL2(OSystem& osystem) : EventHandler(osystem) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandlerSDL2::enableTextEvents(bool enable) { if(enable) SDL_StartTextInput(); else SDL_StopTextInput(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandlerSDL2::pollEvent() { while(SDL_PollEvent(&myEvent)) { switch(myEvent.type) { // keyboard events case SDL_KEYUP: case SDL_KEYDOWN: { if(!myEvent.key.repeat) handleKeyEvent(StellaKey(myEvent.key.keysym.scancode), StellaMod(myEvent.key.keysym.mod), myEvent.key.type == SDL_KEYDOWN); break; } case SDL_TEXTINPUT: { handleTextEvent(*(myEvent.text.text)); break; } case SDL_MOUSEMOTION: { handleMouseMotionEvent(myEvent.motion.x, myEvent.motion.y, myEvent.motion.xrel, myEvent.motion.yrel); break; } case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: { switch(myEvent.button.button) { case SDL_BUTTON_LEFT: handleMouseButtonEvent(MouseButton::LEFT, myEvent.button.type == SDL_MOUSEBUTTONDOWN, myEvent.button.x, myEvent.button.y); break; case SDL_BUTTON_RIGHT: handleMouseButtonEvent(MouseButton::RIGHT, myEvent.button.type == SDL_MOUSEBUTTONDOWN, myEvent.button.x, myEvent.button.y); break; } break; } case SDL_MOUSEWHEEL: { int x, y; SDL_GetMouseState(&x, &y); // we need mouse position too if(myEvent.wheel.y < 0) handleMouseButtonEvent(MouseButton::WHEELDOWN, true, x, y); else if(myEvent.wheel.y > 0) handleMouseButtonEvent(MouseButton::WHEELUP, true, x, y); break; } #ifdef JOYSTICK_SUPPORT case SDL_JOYBUTTONUP: case SDL_JOYBUTTONDOWN: { handleJoyEvent(myEvent.jbutton.which, myEvent.jbutton.button, myEvent.jbutton.state == SDL_PRESSED ? 1 : 0); break; } case SDL_JOYAXISMOTION: { handleJoyAxisEvent(myEvent.jaxis.which, myEvent.jaxis.axis, myEvent.jaxis.value); break; } case SDL_JOYHATMOTION: { int v = myEvent.jhat.value, value = 0; if(v & SDL_HAT_CENTERED) value = EVENT_HATCENTER_M; else { if(v & SDL_HAT_UP) value |= EVENT_HATUP_M; if(v & SDL_HAT_DOWN) value |= EVENT_HATDOWN_M; if(v & SDL_HAT_LEFT) value |= EVENT_HATLEFT_M; if(v & SDL_HAT_RIGHT) value |= EVENT_HATRIGHT_M; } handleJoyHatEvent(myEvent.jhat.which, myEvent.jhat.hat, value); break; // SDL_JOYHATMOTION } case SDL_JOYDEVICEADDED: { addJoystick(new JoystickSDL2(myEvent.jdevice.which)); break; // SDL_JOYDEVICEADDED } case SDL_JOYDEVICEREMOVED: { removeJoystick(myEvent.jdevice.which); break; // SDL_JOYDEVICEREMOVED } #endif case SDL_QUIT: { handleEvent(Event::Quit, 1); break; // SDL_QUIT } case SDL_WINDOWEVENT: switch(myEvent.window.event) { case SDL_WINDOWEVENT_SHOWN: handleSystemEvent(SystemEvent::WINDOW_SHOWN); break; case SDL_WINDOWEVENT_HIDDEN: handleSystemEvent(SystemEvent::WINDOW_HIDDEN); break; case SDL_WINDOWEVENT_EXPOSED: handleSystemEvent(SystemEvent::WINDOW_EXPOSED); break; case SDL_WINDOWEVENT_MOVED: handleSystemEvent(SystemEvent::WINDOW_MOVED, myEvent.window.data1, myEvent.window.data1); break; case SDL_WINDOWEVENT_RESIZED: handleSystemEvent(SystemEvent::WINDOW_RESIZED, myEvent.window.data1, myEvent.window.data1); break; case SDL_WINDOWEVENT_MINIMIZED: handleSystemEvent(SystemEvent::WINDOW_MINIMIZED); break; case SDL_WINDOWEVENT_MAXIMIZED: handleSystemEvent(SystemEvent::WINDOW_MAXIMIZED); break; case SDL_WINDOWEVENT_RESTORED: handleSystemEvent(SystemEvent::WINDOW_RESTORED); break; case SDL_WINDOWEVENT_ENTER: handleSystemEvent(SystemEvent::WINDOW_ENTER); break; case SDL_WINDOWEVENT_LEAVE: handleSystemEvent(SystemEvent::WINDOW_LEAVE); break; case SDL_WINDOWEVENT_FOCUS_GAINED: handleSystemEvent(SystemEvent::WINDOW_FOCUS_GAINED); break; case SDL_WINDOWEVENT_FOCUS_LOST: handleSystemEvent(SystemEvent::WINDOW_FOCUS_LOST); break; } break; // SDL_WINDOWEVENT } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandlerSDL2::JoystickSDL2::JoystickSDL2(int idx) : myStick(nullptr) { myStick = SDL_JoystickOpen(idx); if(myStick) { // In Windows, all XBox controllers using the XInput API seem to name // the controller as "XInput Controller". This would be fine, except // it also appends " #x", where x seems to vary. Obviously this wreaks // havoc with the idea that a joystick will always have the same name. // So we truncate the number. const char* sdlname = SDL_JoystickName(myStick); const string& desc = BSPF::startsWithIgnoreCase(sdlname, "XInput Controller") ? "XInput Controller" : sdlname; initialize(SDL_JoystickInstanceID(myStick), desc, SDL_JoystickNumAxes(myStick), SDL_JoystickNumButtons(myStick), SDL_JoystickNumHats(myStick), SDL_JoystickNumBalls(myStick)); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandlerSDL2::JoystickSDL2::~JoystickSDL2() { if(myStick) SDL_JoystickClose(myStick); } stella-5.1.1/src/common/EventHandlerSDL2.hxx000066400000000000000000000045021324334165500206250ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef EVENTHANDLER_SDL2_HXX #define EVENTHANDLER_SDL2_HXX #include "SDL_lib.hxx" #include "EventHandler.hxx" /** This class handles event collection from the point of view of the specific backend toolkit (SDL2). It converts from SDL2-specific events into events that the Stella core can understand. @author Stephen Anthony */ class EventHandlerSDL2 : public EventHandler { public: /** Create a new SDL2 event handler object */ EventHandlerSDL2(OSystem& osystem); virtual ~EventHandlerSDL2() = default; private: /** Enable/disable text events (distinct from single-key events). */ void enableTextEvents(bool enable) override; /** Returns the human-readable name for a StellaKey. */ const char* const nameForKey(StellaKey key) const override { return SDL_GetScancodeName(SDL_Scancode(key)); } /** Collects and dispatches any pending SDL2 events. */ void pollEvent() override; private: SDL_Event myEvent; // A thin wrapper around a basic StellaJoystick, holding the pointer to // the underlying SDL stick. class JoystickSDL2 : public StellaJoystick { public: JoystickSDL2(int idx); virtual ~JoystickSDL2(); private: SDL_Joystick* myStick; }; private: // Following constructors and assignment operators not supported EventHandlerSDL2() = delete; EventHandlerSDL2(const EventHandlerSDL2&) = delete; EventHandlerSDL2(EventHandlerSDL2&&) = delete; EventHandlerSDL2& operator=(const EventHandlerSDL2&) = delete; EventHandlerSDL2& operator=(EventHandlerSDL2&&) = delete; }; #endif stella-5.1.1/src/common/FBSurfaceSDL2.cxx000066400000000000000000000165551324334165500200540ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "FBSurfaceSDL2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceSDL2::FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height, const uInt32* data) : myFB(buffer), mySurface(nullptr), myTexture(nullptr), mySurfaceIsDirty(true), myIsVisible(true), myTexAccess(SDL_TEXTUREACCESS_STREAMING), myInterpolate(false), myBlendEnabled(false), myBlendAlpha(255), myStaticData(nullptr) { createSurface(width, height, data); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurfaceSDL2::~FBSurfaceSDL2() { if(mySurface) SDL_FreeSurface(mySurface); free(); if(myStaticData) { delete[] myStaticData; myStaticData = nullptr; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color) { // Fill the rectangle SDL_Rect tmp; tmp.x = x; tmp.y = y; tmp.w = w; tmp.h = h; SDL_FillRect(mySurface, &tmp, myPalette[color]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FBSurfaceSDL2::width() const { return mySurface->w; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FBSurfaceSDL2::height() const { return mySurface->h; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const GUI::Rect& FBSurfaceSDL2::srcRect() const { return mySrcGUIR; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const GUI::Rect& FBSurfaceSDL2::dstRect() const { return myDstGUIR; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setSrcPos(uInt32 x, uInt32 y) { mySrcR.x = x; mySrcR.y = y; mySrcGUIR.moveTo(x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setSrcSize(uInt32 w, uInt32 h) { mySrcR.w = w; mySrcR.h = h; mySrcGUIR.setWidth(w); mySrcGUIR.setHeight(h); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setDstPos(uInt32 x, uInt32 y) { myDstR.x = x; myDstR.y = y; myDstGUIR.moveTo(x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setDstSize(uInt32 w, uInt32 h) { myDstR.w = w; myDstR.h = h; myDstGUIR.setWidth(w); myDstGUIR.setHeight(h); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::setVisible(bool visible) { myIsVisible = visible; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::translateCoords(Int32& x, Int32& y) const { x -= myDstR.x; x /= myDstR.w / mySrcR.w; y -= myDstR.y; y /= myDstR.h / mySrcR.h; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FBSurfaceSDL2::render() { if(mySurfaceIsDirty && myIsVisible) { //cerr << "src: x=" << mySrcR.x << ", y=" << mySrcR.y << ", w=" << mySrcR.w << ", h=" << mySrcR.h << endl; //cerr << "dst: x=" << myDstR.x << ", y=" << myDstR.y << ", w=" << myDstR.w << ", h=" << myDstR.h << endl; //cerr << "render()\n"; if(myTexAccess == SDL_TEXTUREACCESS_STREAMING) SDL_UpdateTexture(myTexture, &mySrcR, mySurface->pixels, mySurface->pitch); SDL_RenderCopy(myFB.myRenderer, myTexture, &mySrcR, &myDstR); mySurfaceIsDirty = false; // Let postFrameUpdate() know that a change has been made return myFB.myDirtyFlag = true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::invalidate() { SDL_FillRect(mySurface, nullptr, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::free() { if(myTexture) { SDL_DestroyTexture(myTexture); myTexture = nullptr; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::reload() { // Re-create texture; the underlying SDL_Surface is fine as-is SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, myInterpolate ? "1" : "0"); myTexture = SDL_CreateTexture(myFB.myRenderer, myFB.myPixelFormat->format, myTexAccess, mySurface->w, mySurface->h); // If the data is static, we only upload it once if(myTexAccess == SDL_TEXTUREACCESS_STATIC) SDL_UpdateTexture(myTexture, nullptr, myStaticData, myStaticPitch); // Blending enabled? if(myBlendEnabled) { SDL_SetTextureBlendMode(myTexture, SDL_BLENDMODE_BLEND); SDL_SetTextureAlphaMod(myTexture, myBlendAlpha); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::resize(uInt32 width, uInt32 height) { // We will only resize when necessary, and not using static textures if((myTexAccess == SDL_TEXTUREACCESS_STATIC) || (mySurface && int(width) <= mySurface->w && int(height) <= mySurface->h)) return; // don't need to resize at all if(mySurface) SDL_FreeSurface(mySurface); free(); createSurface(width, height, nullptr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::createSurface(uInt32 width, uInt32 height, const uInt32* data) { // Create a surface in the same format as the parent GL class const SDL_PixelFormat* pf = myFB.myPixelFormat; mySurface = SDL_CreateRGBSurface(0, width, height, pf->BitsPerPixel, pf->Rmask, pf->Gmask, pf->Bmask, pf->Amask); // We start out with the src and dst rectangles containing the same // dimensions, indicating no scaling or re-positioning setSrcPos(0, 0); setDstPos(0, 0); setSrcSize(width, height); setDstSize(width, height); //////////////////////////////////////////////////// // These *must* be set for the parent class myPixels = reinterpret_cast(mySurface->pixels); myPitch = mySurface->pitch / pf->BytesPerPixel; //////////////////////////////////////////////////// if(data) { myTexAccess = SDL_TEXTUREACCESS_STATIC; myStaticPitch = mySurface->w * 4; // we need pitch in 'bytes' myStaticData = new uInt32[mySurface->w * mySurface->h]; SDL_memcpy(myStaticData, data, mySurface->w * mySurface->h * 4); } applyAttributes(false); // To generate texture reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurfaceSDL2::applyAttributes(bool immediate) { myInterpolate = myAttributes.smoothing; myBlendEnabled = myAttributes.blending; myBlendAlpha = uInt8(myAttributes.blendalpha * 2.55); if(immediate) { // Re-create the texture with the new settings free(); reload(); } } stella-5.1.1/src/common/FBSurfaceSDL2.hxx000066400000000000000000000063061324334165500200520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FBSURFACE_SDL2_HXX #define FBSURFACE_SDL2_HXX #include "bspf.hxx" #include "FBSurface.hxx" #include "FrameBufferSDL2.hxx" /** An FBSurface suitable for the SDL2 Render2D API, making use of hardware acceleration behind the scenes. @author Stephen Anthony */ class FBSurfaceSDL2 : public FBSurface { public: FBSurfaceSDL2(FrameBufferSDL2& buffer, uInt32 width, uInt32 height, const uInt32* data); virtual ~FBSurfaceSDL2(); // Most of the surface drawing primitives are implemented in FBSurface; // the ones implemented here use SDL-specific code for extra performance // void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color) override; // With hardware surfaces, it's faster to just update the entire surface void setDirty() override { mySurfaceIsDirty = true; } uInt32 width() const override; uInt32 height() const override; const GUI::Rect& srcRect() const override; const GUI::Rect& dstRect() const override; void setSrcPos(uInt32 x, uInt32 y) override; void setSrcSize(uInt32 w, uInt32 h) override; void setDstPos(uInt32 x, uInt32 y) override; void setDstSize(uInt32 w, uInt32 h) override; void setVisible(bool visible) override; void translateCoords(Int32& x, Int32& y) const override; bool render() override; void invalidate() override; void free() override; void reload() override; void resize(uInt32 width, uInt32 height) override; protected: void applyAttributes(bool immediate) override; private: void createSurface(uInt32 width, uInt32 height, const uInt32* data); // Following constructors and assignment operators not supported FBSurfaceSDL2() = delete; FBSurfaceSDL2(const FBSurfaceSDL2&) = delete; FBSurfaceSDL2(FBSurfaceSDL2&&) = delete; FBSurfaceSDL2& operator=(const FBSurfaceSDL2&) = delete; FBSurfaceSDL2& operator=(FBSurfaceSDL2&&) = delete; private: FrameBufferSDL2& myFB; SDL_Surface* mySurface; SDL_Texture* myTexture; SDL_Rect mySrcR, myDstR; bool mySurfaceIsDirty; bool myIsVisible; SDL_TextureAccess myTexAccess; // Is pixel data constant or can it change? bool myInterpolate; // Scaling is smoothed or blocky bool myBlendEnabled; // Blending is enabled uInt8 myBlendAlpha; // Alpha to use in blending mode uInt32* myStaticData; // The data to use when the buffer contents are static uInt32 myStaticPitch; // The number of bytes in a row of static data GUI::Rect mySrcGUIR, myDstGUIR; }; #endif stella-5.1.1/src/common/FSNodeFactory.hxx000066400000000000000000000040771324334165500202760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FSNODE_FACTORY_HXX #define FSNODE_FACTORY_HXX class AbstractFSNode; #if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX) #include "FSNodePOSIX.hxx" #elif defined(BSPF_WINDOWS) #include "FSNodeWINDOWS.hxx" #else #error Unsupported platform in FSNodeFactory! #endif #include "FSNodeZIP.hxx" /** This class deals with creating the different FSNode implementations. I think you can see why this mess was put into a factory class :) @author Stephen Anthony */ class FilesystemNodeFactory { public: enum Type { SYSTEM, ZIP }; public: static AbstractFSNode* create(const string& path, Type type) { switch(type) { case SYSTEM: #if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX) return new FilesystemNodePOSIX(path); #elif defined(BSPF_WINDOWS) return new FilesystemNodeWINDOWS(path); #endif break; case ZIP: return new FilesystemNodeZIP(path); break; } return nullptr; } private: // Following constructors and assignment operators not supported FilesystemNodeFactory() = delete; FilesystemNodeFactory(const FilesystemNodeFactory&) = delete; FilesystemNodeFactory(FilesystemNodeFactory&&) = delete; FilesystemNodeFactory& operator=(const FilesystemNodeFactory&) = delete; FilesystemNodeFactory& operator=(FilesystemNodeFactory&&) = delete; }; #endif stella-5.1.1/src/common/FSNodeZIP.cxx000066400000000000000000000140751324334165500173230ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "OSystem.hxx" #include "FSNodeFactory.hxx" #include "FSNodeZIP.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeZIP::FilesystemNodeZIP() : _error(ZIPERR_NOT_A_FILE), _numFiles(0), _isDirectory(false), _isFile(false) { // We need a name, else the node is invalid _realNode = shared_ptr(nullptr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeZIP::FilesystemNodeZIP(const string& p) : _error(ZIPERR_NONE), _numFiles(0), _isDirectory(false), _isFile(false) { // Is this a valid file? auto isFile = [](const string& file) { return BSPF::endsWithIgnoreCase(file, ".a26") || BSPF::endsWithIgnoreCase(file, ".bin") || BSPF::endsWithIgnoreCase(file, ".rom"); }; // Extract ZIP file and virtual file (if specified) size_t pos = BSPF::findIgnoreCase(p, ".zip"); if(pos == string::npos) return; _zipFile = p.substr(0, pos+4); // Open file at least once to initialize the virtual file count ZipHandler& zip = open(_zipFile); _numFiles = zip.romFiles(); if(_numFiles == 0) { _error = ZIPERR_NO_ROMS; return; } // We always need a virtual file/path // Either one is given, or we use the first one if(pos+5 < p.length()) { _virtualPath = p.substr(pos+5); _isFile = isFile(_virtualPath); _isDirectory = !_isFile; } else if(_numFiles == 1) { bool found = false; while(zip.hasNext() && !found) { const string& file = zip.next(); if(isFile(file)) { _virtualPath = file; _isFile = true; found = true; } } if(!found) return; } else _isDirectory = true; AbstractFSNode* tmp = FilesystemNodeFactory::create(_zipFile, FilesystemNodeFactory::SYSTEM); _realNode = shared_ptr(tmp); setFlags(_zipFile, _virtualPath, _realNode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeZIP::FilesystemNodeZIP( const string& zipfile, const string& virtualpath, shared_ptr realnode, bool isdir) : _error(ZIPERR_NONE), _numFiles(0), _isDirectory(isdir), _isFile(!isdir) { setFlags(zipfile, virtualpath, realnode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FilesystemNodeZIP::setFlags(const string& zipfile, const string& virtualpath, shared_ptr realnode) { _zipFile = zipfile; _virtualPath = virtualpath; _realNode = realnode; _path = _realNode->getPath(); _shortPath = _realNode->getShortPath(); // Is a file component present? if(_virtualPath.size() != 0) { _path += ("/" + _virtualPath); _shortPath += ("/" + _virtualPath); _name = lastPathComponent(_path); } _error = ZIPERR_NONE; if(!_realNode->isFile()) _error = ZIPERR_NOT_A_FILE; if(!_realNode->isReadable()) _error = ZIPERR_NOT_READABLE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode, bool hidden) const { // Files within ZIP archives don't contain children if(!isDirectory() || _error != ZIPERR_NONE) return false; std::set dirs; ZipHandler& zip = open(_zipFile); while(zip.hasNext()) { // Only consider entries that start with '_virtualPath' const string& next = zip.next(); if(BSPF::startsWithIgnoreCase(next, _virtualPath)) { // First strip off the leading directory const string& curr = next.substr(_virtualPath == "" ? 0 : _virtualPath.size()+1); // Only add sub-directory entries once auto pos = curr.find_first_of("/\\"); if(pos != string::npos) dirs.emplace(curr.substr(0, pos)); else myList.emplace_back(new FilesystemNodeZIP(_zipFile, next, _realNode, false)); } } for(const auto& dir: dirs) { // Prepend previous path const string& vpath = _virtualPath != "" ? _virtualPath + "/" + dir : dir; myList.emplace_back(new FilesystemNodeZIP(_zipFile, vpath, _realNode, true)); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FilesystemNodeZIP::read(BytePtr& image) const { switch(_error) { case ZIPERR_NONE: break; case ZIPERR_NOT_A_FILE: throw runtime_error("ZIP file contains errors/not found"); case ZIPERR_NOT_READABLE: throw runtime_error("ZIP file not readable"); case ZIPERR_NO_ROMS: throw runtime_error("ZIP file doesn't contain any ROMs"); } ZipHandler& zip = open(_zipFile); bool found = false; while(zip.hasNext() && !found) found = zip.next() == _virtualPath; return found ? zip.decompress(image) : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AbstractFSNode* FilesystemNodeZIP::getParent() const { if(_virtualPath == "") return _realNode ? _realNode->getParent() : nullptr; const char* start = _path.c_str(); const char* end = lastPathComponent(_path); return new FilesystemNodeZIP(string(start, end - start - 1)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unique_ptr FilesystemNodeZIP::myZipHandler = make_unique(); stella-5.1.1/src/common/FSNodeZIP.hxx000066400000000000000000000076561324334165500173370ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FS_NODE_ZIP_HXX #define FS_NODE_ZIP_HXX #include "ZipHandler.hxx" #include "FSNode.hxx" /* * Implementation of the Stella file system API based on ZIP archives. * ZIP archives are treated as directories if the contain more than one ROM * file, as a file if they contain a single ROM file, and as neither if the * archive is empty. Hence, if a ZIP archive isn't a directory *or* a file, * it is invalid. * * Parts of this class are documented in the base interface class, AbstractFSNode. */ class FilesystemNodeZIP : public AbstractFSNode { public: /** * Creates a FilesystemNodeZIP with the root node as path. */ FilesystemNodeZIP(); /** * Creates a FilesystemNodeZIP for a given path. * * @param path String with the path the new node should point to. */ FilesystemNodeZIP(const string& path); bool exists() const { return _realNode && _realNode->exists(); } const string& getName() const { return _name; } const string& getPath() const { return _path; } string getShortPath() const { return _shortPath; } bool isDirectory() const { return _isDirectory; } bool isFile() const { return _isFile; } bool isReadable() const { return _realNode && _realNode->isReadable(); } bool isWritable() const { return false; } ////////////////////////////////////////////////////////// // For now, ZIP files cannot be modified in any way bool makeDir() { return false; } bool rename(const string& newfile) { return false; } ////////////////////////////////////////////////////////// bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const; AbstractFSNode* getParent() const; uInt32 read(BytePtr& image) const; private: FilesystemNodeZIP(const string& zipfile, const string& virtualpath, shared_ptr realnode, bool isdir); void setFlags(const string& zipfile, const string& virtualpath, shared_ptr realnode); friend ostream& operator<<(ostream& os, const FilesystemNodeZIP& node) { os << "_zipFile: " << node._zipFile << endl << "_virtualPath: " << node._virtualPath << endl << "_path: " << node._path << endl << "_shortPath: " << node._shortPath << endl; return os; } private: /* Error types */ enum zip_error { ZIPERR_NONE = 0, ZIPERR_NOT_A_FILE, ZIPERR_NOT_READABLE, ZIPERR_NO_ROMS }; shared_ptr _realNode; string _zipFile, _virtualPath; string _name, _path, _shortPath; zip_error _error; uInt32 _numFiles; bool _isDirectory, _isFile; // ZipHandler static reference variable responsible for accessing ZIP files static unique_ptr myZipHandler; inline static ZipHandler& open(const string& file) { myZipHandler->open(file); return *myZipHandler; } // Get last component of path static const char* lastPathComponent(const string& str) { if(str.empty()) return ""; const char* start = str.c_str(); const char* cur = start + str.size() - 2; while (cur >= start && !(*cur == '/' || *cur == '\\')) --cur; return cur + 1; } }; #endif stella-5.1.1/src/common/FrameBufferSDL2.cxx000066400000000000000000000244561324334165500204370ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "SDL_lib.hxx" #include "bspf.hxx" #include "Console.hxx" #include "Font.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "FBSurfaceSDL2.hxx" #include "FrameBufferSDL2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBufferSDL2::FrameBufferSDL2(OSystem& osystem) : FrameBuffer(osystem), myWindow(nullptr), myRenderer(nullptr), myDirtyFlag(true) { // Initialize SDL2 context if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_JOYSTICK) < 0) { ostringstream buf; buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl; myOSystem.logMessage(buf.str(), 0); throw runtime_error("FATAL ERROR"); } myOSystem.logMessage("FrameBufferSDL2::FrameBufferSDL2 SDL_Init()", 2); // We need a pixel format for palette value calculations // It's done this way (vs directly accessing a FBSurfaceSDL2 object) // since the structure may be needed before any FBSurface's have // been created myPixelFormat = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBufferSDL2::~FrameBufferSDL2() { SDL_FreeFormat(myPixelFormat); if(myRenderer) { SDL_DestroyRenderer(myRenderer); myRenderer = nullptr; } if(myWindow) { SDL_SetWindowFullscreen(myWindow, 0); // on some systems, a crash occurs // when destroying fullscreen window SDL_DestroyWindow(myWindow); myWindow = nullptr; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::queryHardware(vector& displays, VariantList& renderers) { // First get the maximum windowed desktop resolution SDL_DisplayMode display; int maxDisplays = SDL_GetNumVideoDisplays(); for(int i = 0; i < maxDisplays; ++i) { SDL_GetDesktopDisplayMode(i, &display); displays.emplace_back(display.w, display.h); } struct RenderName { string sdlName; string stellaName; }; // Create name map for all currently known SDL renderers const int NUM_RENDERERS = 5; static const RenderName RENDERER_NAMES[NUM_RENDERERS] = { { "direct3d", "Direct3D" }, { "opengl", "OpenGL" }, { "opengles", "OpenGLES" }, { "opengles2", "OpenGLES2" }, { "software", "Software" } }; int numDrivers = SDL_GetNumRenderDrivers(); for(int i = 0; i < numDrivers; ++i) { SDL_RendererInfo info; if(SDL_GetRenderDriverInfo(i, &info) == 0) { // Map SDL names into nicer Stella names (if available) bool found = false; for(int j = 0; j < NUM_RENDERERS; ++j) { if(RENDERER_NAMES[j].sdlName == info.name) { VarList::push_back(renderers, RENDERER_NAMES[j].stellaName, info.name); found = true; break; } } if(!found) VarList::push_back(renderers, info.name, info.name); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int32 FrameBufferSDL2::getCurrentDisplayIndex() { return SDL_GetWindowDisplayIndex(myWindow); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::setVideoMode(const string& title, const VideoMode& mode) { // If not initialized by this point, then immediately fail if(SDL_WasInit(SDL_INIT_VIDEO) == 0) return false; // Always recreate renderer (some systems need this) if(myRenderer) { // Always clear the (double-buffered) renderer surface SDL_RenderClear(myRenderer); SDL_RenderPresent(myRenderer); SDL_RenderClear(myRenderer); SDL_DestroyRenderer(myRenderer); myRenderer = nullptr; } Int32 displayIndex = mode.fsIndex; if(displayIndex == -1) { // windowed mode if (myWindow) { // Show it on same screen as the previous window displayIndex = SDL_GetWindowDisplayIndex(myWindow); } if(displayIndex < 0) { // fallback to the first screen displayIndex = 0; } } uInt32 pos = myOSystem.settings().getBool("center") ? SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex) : SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex); uInt32 flags = mode.fsIndex != -1 ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; // OSX seems to have issues with destroying the window, and wants to keep // the same handle // Problem is, doing so on other platforms results in flickering when // toggling fullscreen windowed mode // So we have a special case for OSX #ifndef BSPF_MAC_OSX // Don't re-create the window if its size hasn't changed, as it's not // necessary, and causes flashing in fullscreen mode if(myWindow) { int w, h; SDL_GetWindowSize(myWindow, &w, &h); if(uInt32(w) != mode.screen.w || uInt32(h) != mode.screen.h) { SDL_DestroyWindow(myWindow); myWindow = nullptr; } } if(myWindow) { // Even though window size stayed the same, the title may have changed SDL_SetWindowTitle(myWindow, title.c_str()); } #else // OSX wants to *never* re-create the window // This sometimes results in the window being resized *after* it's displayed, // but at least the code works and doesn't crash if(myWindow) { SDL_SetWindowFullscreen(myWindow, flags); SDL_SetWindowSize(myWindow, mode.screen.w, mode.screen.h); SDL_SetWindowPosition(myWindow, pos, pos); SDL_SetWindowTitle(myWindow, title.c_str()); } #endif else { myWindow = SDL_CreateWindow(title.c_str(), pos, pos, mode.screen.w, mode.screen.h, flags); if(myWindow == nullptr) { string msg = "ERROR: Unable to open SDL window: " + string(SDL_GetError()); myOSystem.logMessage(msg, 0); return false; } setWindowIcon(); } uInt32 renderFlags = SDL_RENDERER_ACCELERATED; if(myOSystem.settings().getBool("vsync")) // V'synced blits option renderFlags |= SDL_RENDERER_PRESENTVSYNC; const string& video = myOSystem.settings().getString("video"); // Render hint if(video != "") SDL_SetHint(SDL_HINT_RENDER_DRIVER, video.c_str()); myRenderer = SDL_CreateRenderer(myWindow, -1, renderFlags); if(myRenderer == nullptr) { string msg = "ERROR: Unable to create SDL renderer: " + string(SDL_GetError()); myOSystem.logMessage(msg, 0); return false; } SDL_RendererInfo renderinfo; if(SDL_GetRendererInfo(myRenderer, &renderinfo) >= 0) myOSystem.settings().setValue("video", renderinfo.name); return true; } void FrameBufferSDL2::setTitle(const string& title) { myScreenTitle = title; if(myWindow) SDL_SetWindowTitle(myWindow, title.c_str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FrameBufferSDL2::about() const { ostringstream out; out << "Video system: " << SDL_GetCurrentVideoDriver() << endl; SDL_RendererInfo info; if(SDL_GetRendererInfo(myRenderer, &info) >= 0) { out << " Renderer: " << info.name << endl; if(info.max_texture_width > 0 && info.max_texture_height > 0) out << " Max texture: " << info.max_texture_width << "x" << info.max_texture_height << endl; out << " Flags: " << ((info.flags & SDL_RENDERER_PRESENTVSYNC) ? "+" : "-") << "vsync, " << ((info.flags & SDL_RENDERER_ACCELERATED) ? "+" : "-") << "accel" << endl; } return out.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::invalidate() { myDirtyFlag = true; SDL_RenderClear(myRenderer); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::showCursor(bool show) { SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::grabMouse(bool grab) { SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBufferSDL2::fullScreen() const { #ifdef WINDOWED_SUPPORT return SDL_GetWindowFlags(myWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP; #else return true; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::postFrameUpdate() { if(myDirtyFlag) { // Now show all changes made to the renderer SDL_RenderPresent(myRenderer); myDirtyFlag = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::setWindowIcon() { #ifndef BSPF_MAC_OSX // Currently not needed for OSX #include "stella_icon.hxx" // The Stella icon SDL_Surface* surface = SDL_CreateRGBSurfaceFrom(stella_icon, 32, 32, 32, 32 * 4, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000); SDL_SetWindowIcon(myWindow, surface); SDL_FreeSurface(surface); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unique_ptr FrameBufferSDL2::createSurface(uInt32 w, uInt32 h, const uInt32* data) const { return make_unique(const_cast(*this), w, h, data); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::readPixels(uInt8* pixels, uInt32 pitch, const GUI::Rect& rect) const { SDL_Rect r; r.x = rect.x(); r.y = rect.y(); r.w = rect.width(); r.h = rect.height(); SDL_RenderReadPixels(myRenderer, &r, 0, pixels, pitch); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBufferSDL2::clear() { invalidate(); postFrameUpdate(); } stella-5.1.1/src/common/FrameBufferSDL2.hxx000066400000000000000000000136541324334165500204420ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FRAMEBUFFER_SDL2_HXX #define FRAMEBUFFER_SDL2_HXX #include "SDL_lib.hxx" class OSystem; class FBSurfaceSDL2; #include "bspf.hxx" #include "FrameBuffer.hxx" /** This class implements a standard SDL2 2D, hardware accelerated framebuffer. Behind the scenes, it may be using Direct3D, OpenGL(ES), etc. @author Stephen Anthony */ class FrameBufferSDL2 : public FrameBuffer { friend class FBSurfaceSDL2; public: /** Creates a new SDL2 framebuffer */ FrameBufferSDL2(OSystem& osystem); virtual ~FrameBufferSDL2(); ////////////////////////////////////////////////////////////////////// // The following are derived from public methods in FrameBuffer.hxx ////////////////////////////////////////////////////////////////////// /** Updates window title. @param title The title of the application / window */ void setTitle(const string& title) override; /** Shows or hides the cursor based on the given boolean value. */ void showCursor(bool show) override; /** Answers if the display is currently in fullscreen mode. */ bool fullScreen() const override; /** This method is called to retrieve the R/G/B data from the given pixel. @param pixel The pixel containing R/G/B data @param r The red component of the color @param g The green component of the color @param b The blue component of the color */ inline void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const override { SDL_GetRGB(pixel, myPixelFormat, r, g, b); } /** This method is called to map a given R/G/B triple to the screen palette. @param r The red component of the color. @param g The green component of the color. @param b The blue component of the color. */ inline uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const override { return SDL_MapRGB(myPixelFormat, r, g, b); } /** This method is called to get a copy of the specified ARGB data from the viewable FrameBuffer area. Note that this isn't the same as any internal surfaces that may be in use; it should return the actual data as it is currently seen onscreen. @param buffer A copy of the pixel data in ARGB8888 format @param pitch The pitch (in bytes) for the pixel data @param rect The bounding rectangle for the buffer */ void readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const override; /** Clear the frame buffer */ void clear() override; protected: ////////////////////////////////////////////////////////////////////// // The following are derived from protected methods in FrameBuffer.hxx ////////////////////////////////////////////////////////////////////// /** This method is called to query and initialize the video hardware for desktop and fullscreen resolution information. */ void queryHardware(vector& displays, VariantList& renderers) override; /** This method is called to query the video hardware for the index of the display the current window is displayed on @return the current display index or a negative value if no window is displayed */ Int32 getCurrentDisplayIndex() override; /** This method is called to change to the given video mode. @param title The title for the created window @param mode The video mode to use @return False on any errors, else true */ bool setVideoMode(const string& title, const VideoMode& mode) override; /** This method is called to invalidate the contents of the entire framebuffer (ie, mark the current content as invalid, and erase it on the next drawing pass). */ void invalidate() override; /** This method is called to create a surface with the given attributes. @param w The requested width of the new surface. @param h The requested height of the new surface. @param data If non-null, use the given data values as a static surface */ unique_ptr createSurface(uInt32 w, uInt32 h, const uInt32* data) const override; /** Grabs or ungrabs the mouse based on the given boolean value. */ void grabMouse(bool grab) override; /** Set the icon for the main SDL window. */ void setWindowIcon() override; /** This method is called to provide information about the FrameBuffer. */ string about() const override; /** This method is called after any drawing is done (per-frame). */ void postFrameUpdate() override; private: // The SDL video buffer SDL_Window* myWindow; SDL_Renderer* myRenderer; // Used by mapRGB (when palettes are created) SDL_PixelFormat* myPixelFormat; // Indicates that the renderer has been modified, and should be redrawn bool myDirtyFlag; private: // Following constructors and assignment operators not supported FrameBufferSDL2() = delete; FrameBufferSDL2(const FrameBufferSDL2&) = delete; FrameBufferSDL2(FrameBufferSDL2&&) = delete; FrameBufferSDL2& operator=(const FrameBufferSDL2&) = delete; FrameBufferSDL2& operator=(FrameBufferSDL2&&) = delete; }; #endif stella-5.1.1/src/common/LinkedObjectPool.hxx000066400000000000000000000201671324334165500210150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef LINKED_OBJECT_POOL_HXX #define LINKED_OBJECT_POOL_HXX #include #include "bspf.hxx" /** A fixed-size object-pool based doubly-linked list that makes use of multiple STL lists, to reduce frequent (de)allocations. This structure can be used as either a stack or queue, but also allows for removal at any location in the list. There are two internal lists; one stores active nodes, and the other stores pool nodes that have been 'deleted' from the active list (note that no actual deletion takes place; nodes are simply moved from one list to another). Similarly, when a new node is added to the active list, it is simply moved from the pool list to the active list. In all cases, the variable 'myCurrent' is updated to point to the current node. NOTE: You must always call 'currentIsValid()' before calling 'current()', to make sure that the return value is a valid reference. In the case of methods which wrap the C++ 'splice()' method, the semantics of splice are followed wrt invalid/out-of-range/etc iterators. See the applicable C++ STL documentation for such behaviour. @author Stephen Anthony */ namespace Common { template class LinkedObjectPool { public: using iter = typename std::list::iterator; using const_iter = typename std::list::const_iterator; /* Create a pool of size CAPACITY; the active list starts out empty. */ LinkedObjectPool() : myCurrent(myList.end()), myCapacity(0) { resize(CAPACITY); } /** Return node data that the 'current' iterator points to. Note that this returns a valid value only in the case where the list is non-empty (at least one node has been added to the active list). Make sure to call 'currentIsValid()' before accessing this method. */ T& current() const { return *myCurrent; } /** Returns current's position in the list SLOW, but only required for messages */ uInt32 currentIdx() const { if(empty()) return 0; iter it = myCurrent; uInt32 idx = 1; while(it-- != myList.begin()) idx++; return idx; } /** Does the 'current' iterator point to a valid node in the active list? This must be called before 'current()' is called. */ bool currentIsValid() const { return myCurrent != myList.end(); } /** Advance 'current' iterator to previous position in the active list. If we go past the beginning, it is reset to one past the end (indicates nullptr). */ void moveToPrevious() { if(currentIsValid()) myCurrent = myCurrent == myList.begin() ? myList.end() : std::prev(myCurrent, 1); } /** Advance 'current' iterator to next position in the active list. If we go past the last node, it will point to one past the end (indicates nullptr). */ void moveToNext() { if(currentIsValid()) myCurrent = std::next(myCurrent, 1); } /** Return an iterator to the first node in the active list. */ const_iter first() const { return myList.begin(); } /** Return an iterator to the last node in the active list. */ const_iter last() const { return std::prev(myList.end(), 1); } /** Return an iterator to the previous node of 'i' in the active list. */ const_iter previous(const_iter i) const { return std::prev(i, 1); } /** Return an iterator to the next node to 'current' in the active list. */ const_iter next(const_iter i) const { return std::next(i, 1); } /** Canonical iterators from C++ STL. */ const_iter cbegin() const { return myList.cbegin(); } const_iter cend() const { return myList.cend(); } /** Answer whether 'current' is at the specified iterator. */ bool atFirst() const { return myCurrent == first(); } bool atLast() const { return myCurrent == last(); } /** Add a new node at the beginning of the active list, and update 'current' to point to that node. */ void addFirst() { myList.splice(myList.begin(), myPool, myPool.begin()); myCurrent = myList.begin(); } /** Add a new node at the end of the active list, and update 'current' to point to that node. */ void addLast() { myList.splice(myList.end(), myPool, myPool.begin()); myCurrent = std::prev(myList.end(), 1); } /** Remove the first node of the active list, updating 'current' if it happens to be the one removed. */ void removeFirst() { const_iter i = myList.cbegin(); myPool.splice(myPool.end(), myList, i); if(myCurrent == i) // did we just invalidate 'current' moveToNext(); // if so, move to the next node } /** Remove the last node of the active list, updating 'current' if it happens to be the one removed. */ void removeLast() { const_iter i = std::prev(myList.end(), 1); myPool.splice(myPool.end(), myList, i); if(myCurrent == i) // did we just invalidate 'current' moveToPrevious(); // if so, move to the previous node } /** Remove a single element from the active list at position of the iterator. */ void remove(const_iter i) { myPool.splice(myPool.end(), myList, i); } /** Remove a single element from the active list by index, offset from the beginning of the list. (ie, '0' means first element, '1' is second, and so on). */ void remove(uInt32 index) { myPool.splice(myPool.end(), myList, std::next(myList.begin(), index)); } /** Remove range of elements from the beginning of the active list to the 'current' node. */ void removeToFirst() { myPool.splice(myPool.end(), myList, myList.begin(), myCurrent); } /** Remove range of elements from the node after 'current' to the end of the active list. */ void removeToLast() { myPool.splice(myPool.end(), myList, std::next(myCurrent, 1), myList.end()); } /** Resize the pool to specified size, invalidating the list in the process (ie, the list essentially becomes empty again). */ void resize(uInt32 capacity) { if(myCapacity != capacity) // only resize when necessary { myList.clear(); myPool.clear(); myCurrent = myList.end(); myCapacity = capacity; for(uInt32 i = 0; i < myCapacity; ++i) myPool.emplace_back(T()); } } /** Erase entire contents of active list. */ void clear() { myPool.splice(myPool.end(), myList, myList.begin(), myList.end()); myCurrent = myList.end(); } uInt32 capacity() const { return myCapacity; } uInt32 size() const { return uInt32(myList.size()); } bool empty() const { return size() == 0; } bool full() const { return size() >= capacity(); } private: std::list myList, myPool; // Current position in the active list (end() indicates an invalid position) iter myCurrent; // Total capacity of the pool uInt32 myCapacity; private: // Following constructors and assignment operators not supported LinkedObjectPool(const LinkedObjectPool&) = delete; LinkedObjectPool(LinkedObjectPool&&) = delete; LinkedObjectPool& operator=(const LinkedObjectPool&) = delete; LinkedObjectPool& operator=(LinkedObjectPool&&) = delete; }; } // Namespace Common #endif stella-5.1.1/src/common/MediaFactory.hxx000066400000000000000000000073721324334165500202000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef MEDIA_FACTORY_HXX #define MEDIA_FACTORY_HXX #include "bspf.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "SerialPort.hxx" #if defined(BSPF_UNIX) #include "SerialPortUNIX.hxx" #include "SettingsUNIX.hxx" #include "OSystemUNIX.hxx" #elif defined(BSPF_WINDOWS) #include "SerialPortWINDOWS.hxx" #include "SettingsWINDOWS.hxx" #include "OSystemWINDOWS.hxx" #elif defined(BSPF_MAC_OSX) #include "SerialPortMACOSX.hxx" #include "SettingsMACOSX.hxx" #include "OSystemMACOSX.hxx" extern "C" { int stellaMain(int argc, char* argv[]); } #else #error Unsupported platform! #endif #include "FrameBufferSDL2.hxx" #include "EventHandlerSDL2.hxx" #ifdef SOUND_SUPPORT #include "SoundSDL2.hxx" #else #include "SoundNull.hxx" #endif /** This class deals with the different framebuffer/sound/event implementations for the various ports of Stella, and always returns a valid object based on the specific port and restrictions on that port. As of SDL2, this code is greatly simplified. However, it remains here in case we ever have multiple backend implementations again (should not be necessary since SDL2 covers this nicely). @author Stephen Anthony */ class MediaFactory { public: static unique_ptr createOSystem() { #if defined(BSPF_UNIX) return make_unique(); #elif defined(BSPF_WINDOWS) return make_unique(); #elif defined(BSPF_MAC_OSX) return make_unique(); #else #error Unsupported platform for OSystem! #endif } static unique_ptr createSettings(OSystem& osystem) { #if defined(BSPF_UNIX) return make_unique(osystem); #elif defined(BSPF_WINDOWS) return make_unique(osystem); #elif defined(BSPF_MAC_OSX) return make_unique(osystem); #else #error Unsupported platform for Settings! #endif } static unique_ptr createSerialPort() { #if defined(BSPF_UNIX) return make_unique(); #elif defined(BSPF_WINDOWS) return make_unique(); #elif defined(BSPF_MAC_OSX) return make_unique(); #else return make_unique(); #endif } static unique_ptr createVideo(OSystem& osystem) { return make_unique(osystem); } static unique_ptr createAudio(OSystem& osystem) { #ifdef SOUND_SUPPORT return make_unique(osystem); #else return make_unique(osystem); #endif } static unique_ptr createEventHandler(OSystem& osystem) { return make_unique(osystem); } private: // Following constructors and assignment operators not supported MediaFactory() = delete; MediaFactory(const MediaFactory&) = delete; MediaFactory(MediaFactory&&) = delete; MediaFactory& operator=(const MediaFactory&) = delete; MediaFactory& operator=(MediaFactory&&) = delete; }; #endif stella-5.1.1/src/common/MouseControl.cxx000066400000000000000000000166401324334165500202530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Console.hxx" #include "Control.hxx" #include "Paddles.hxx" #include "Props.hxx" #include "MouseControl.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MouseControl::MouseControl(Console& console, const string& mode) : myProps(console.properties()), myLeftController(console.leftController()), myRightController(console.rightController()), myCurrentModeNum(0) { istringstream m_axis(mode); string m_mode; m_axis >> m_mode; if(BSPF::equalsIgnoreCase(m_mode, "none")) { myModeList.push_back(MouseMode("Mouse input is disabled")); return; } else if(!BSPF::equalsIgnoreCase(m_mode, "auto") && m_mode.length() == 2 && m_mode[0] >= '0' && m_mode[0] <= '8' && m_mode[1] >= '0' && m_mode[1] <= '8') { Axis xaxis = Axis(int(m_mode[0]) - '0'); Axis yaxis = Axis(int(m_mode[1]) - '0'); ostringstream msg; msg << "Mouse X-axis is "; Controller::Type xtype = Controller::Joystick, ytype = Controller::Joystick; int xid = -1, yid = -1; switch(xaxis) { case NoControl: msg << "not used"; break; case Paddle0: xtype = Controller::Paddles; xid = 0; msg << "Paddle 0"; break; case Paddle1: xtype = Controller::Paddles; xid = 1; msg << "Paddle 1"; break; case Paddle2: xtype = Controller::Paddles; xid = 2; msg << "Paddle 2"; break; case Paddle3: xtype = Controller::Paddles; xid = 3; msg << "Paddle 3"; break; case Driving0: xtype = Controller::Driving; xid = 0; msg << "Driving 0"; break; case Driving1: xtype = Controller::Driving; xid = 1; msg << "Driving 1"; break; case MindLink0: xtype = Controller::MindLink; xid = 0; msg << "MindLink 0"; break; case MindLink1: xtype = Controller::MindLink; xid = 1; msg << "MindLink 1"; break; } msg << ", Y-axis is "; switch(yaxis) { case NoControl: msg << "not used"; break; case Paddle0: ytype = Controller::Paddles; yid = 0; msg << "Paddle 0"; break; case Paddle1: ytype = Controller::Paddles; yid = 1; msg << "Paddle 1"; break; case Paddle2: ytype = Controller::Paddles; yid = 2; msg << "Paddle 2"; break; case Paddle3: ytype = Controller::Paddles; yid = 3; msg << "Paddle 3"; break; case Driving0: ytype = Controller::Driving; yid = 0; msg << "Driving 0"; break; case Driving1: ytype = Controller::Driving; yid = 1; msg << "Driving 1"; break; case MindLink0: ytype = Controller::MindLink; yid = 0; msg << "MindLink 0"; break; case MindLink1: ytype = Controller::MindLink; yid = 1; msg << "MindLink 1"; break; } myModeList.push_back(MouseMode(xtype, xid, ytype, yid, msg.str())); } // Now consider the possible modes for the mouse based on the left // and right controllers bool noswap = BSPF::equalsIgnoreCase(myProps.get(Console_SwapPorts), "NO"); if(noswap) { addLeftControllerModes(noswap); addRightControllerModes(noswap); } else { addRightControllerModes(noswap); addLeftControllerModes(noswap); } // Set range information (currently only for paddles, but may be used // for other controllers in the future) int m_range = 100; if(!(m_axis >> m_range)) m_range = 100; Paddles::setPaddleRange(m_range); // If the mouse isn't used at all, we still need one item in the list if(myModeList.size() == 0) myModeList.push_back(MouseMode("Mouse not used for current controllers")); #if 0 for(const auto& m: myModeList) cerr << m << endl; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& MouseControl::next() { const MouseMode& mode = myModeList[myCurrentModeNum]; myCurrentModeNum = (myCurrentModeNum + 1) % myModeList.size(); myLeftController.setMouseControl(mode.xtype, mode.xid, mode.ytype, mode.yid); myRightController.setMouseControl(mode.xtype, mode.xid, mode.ytype, mode.yid); return mode.message; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MouseControl::addLeftControllerModes(bool noswap) { if(controllerSupportsMouse(myLeftController)) { if(myLeftController.type() == Controller::Paddles) { if(noswap) addPaddleModes(0, 1, 0, 1); else addPaddleModes(2, 3, 0, 1); } else { ostringstream msg; msg << "Mouse is left " << myLeftController.name() << " controller"; Controller::Type type = myLeftController.type(); int id = noswap ? 0 : 1; myModeList.push_back(MouseMode(type, id, type, id, msg.str())); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MouseControl::addRightControllerModes(bool noswap) { if(controllerSupportsMouse(myRightController)) { if(myRightController.type() == Controller::Paddles) { if(noswap) addPaddleModes(2, 3, 2, 3); else addPaddleModes(0, 1, 2, 3); } else { ostringstream msg; msg << "Mouse is right " << myRightController.name() << " controller"; Controller::Type type = myRightController.type(); int id = noswap ? 1 : 0; myModeList.push_back(MouseMode(type, id, type, id, msg.str())); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MouseControl::addPaddleModes(int lport, int rport, int lname, int rname) { Controller::Type type = Controller::Paddles; ostringstream msg; msg << "Mouse is Paddle " << lname << " controller"; MouseMode mode0(type, lport, type, lport, msg.str()); msg.str(""); msg << "Mouse is Paddle " << rname << " controller"; MouseMode mode1(type, rport, type, rport, msg.str()); if(BSPF::equalsIgnoreCase(myProps.get(Controller_SwapPaddles), "NO")) { myModeList.push_back(mode0); myModeList.push_back(mode1); } else { myModeList.push_back(mode1); myModeList.push_back(mode0); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool MouseControl::controllerSupportsMouse(Controller& controller) { // Test whether the controller uses the mouse at all // We can pass in dummy values here, since the controllers will be // initialized by a call to next() once the system is up and running return controller.setMouseControl( Controller::Joystick, -1, Controller::Joystick, -1); } stella-5.1.1/src/common/MouseControl.hxx000066400000000000000000000065361324334165500202630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef MOUSE_CONTROL_HXX #define MOUSE_CONTROL_HXX class Console; class Controller; class Properties; #include "bspf.hxx" /** The mouse can control various virtual 'controllers' in many different ways. In 'auto' mode, the entire mouse (both axes and buttons) are used as one controller. In per-ROM axis mode, each axis/button may control separate controllers. As well, we'd like to switch dynamically between each of these modes at runtime. This class encapsulates all required info to implement this functionality. @author Stephen Anthony */ class MouseControl { public: /** Enumeration of mouse axis control types */ enum Axis { Paddle0 = 0, Paddle1, Paddle2, Paddle3, Driving0, Driving1, MindLink0, MindLink1, NoControl }; public: /** Create a new MouseControl object @param console The console in use by the system @param mode Contains information about how to use the mouse axes/buttons */ MouseControl(Console& console, const string& mode); /** Cycle through each available mouse control mode @return A message explaining the current mouse mode */ const string& next(); private: void addLeftControllerModes(bool noswap); void addRightControllerModes(bool noswap); void addPaddleModes(int lport, int rport, int lname, int rname); bool controllerSupportsMouse(Controller& controller); private: const Properties& myProps; Controller& myLeftController; Controller& myRightController; struct MouseMode { Controller::Type xtype, ytype; int xid, yid; string message; MouseMode(const string& msg = "") : xtype(Controller::Joystick), ytype(Controller::Joystick), xid(-1), yid(-1), message(msg) { } MouseMode(Controller::Type xt, int xi, Controller::Type yt, int yi, const string& msg) : xtype(xt), ytype(yt), xid(xi), yid(yi), message(msg) { } friend ostream& operator<<(ostream& os, const MouseMode& mm) { os << "xtype=" << mm.xtype << ", xid=" << mm.xid << ", ytype=" << mm.ytype << ", yid=" << mm.yid << ", msg=" << mm.message; return os; } }; int myCurrentModeNum; vector myModeList; private: // Following constructors and assignment operators not supported MouseControl() = delete; MouseControl(const MouseControl&) = delete; MouseControl(MouseControl&&) = delete; MouseControl& operator=(const MouseControl&) = delete; MouseControl& operator=(MouseControl&&) = delete; }; #endif stella-5.1.1/src/common/PNGLibrary.cxx000066400000000000000000000261541324334165500175740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Props.hxx" #include "PNGLibrary.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PNGLibrary::PNGLibrary(const FrameBuffer& fb) : myFB(fb) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::loadImage(const string& filename, FBSurface& surface) { #define loadImageERROR(s) { err_message = s; goto done; } png_structp png_ptr = nullptr; png_infop info_ptr = nullptr; png_uint_32 iwidth, iheight; int bit_depth, color_type, interlace_type; const char* err_message = nullptr; ifstream in(filename, std::ios_base::binary); if(!in.is_open()) loadImageERROR("No image found"); // Create the PNG loading context structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, png_user_error, png_user_warn); if(png_ptr == nullptr) loadImageERROR("Couldn't allocate memory for PNG file"); // Allocate/initialize the memory for image information. REQUIRED. info_ptr = png_create_info_struct(png_ptr); if(info_ptr == nullptr) loadImageERROR("Couldn't create image information for PNG file"); // Set up the input control png_set_read_fn(png_ptr, &in, png_read_data); // Read PNG header info png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &iwidth, &iheight, &bit_depth, &color_type, &interlace_type, nullptr, nullptr); // Tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); // Extract multiple pixels with bit depths of 1, 2, and 4 from a single // byte into separate bytes (useful for paletted and grayscale images). png_set_packing(png_ptr); // Only normal RBG(A) images are supported (without the alpha channel) if(color_type == PNG_COLOR_TYPE_RGBA) { png_set_strip_alpha(png_ptr); } else if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { loadImageERROR("Greyscale PNG images not supported"); } else if(color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } else if(color_type != PNG_COLOR_TYPE_RGB) { loadImageERROR("Unknown format in PNG image"); } // Create/initialize storage area for the current image if(!allocateStorage(iwidth, iheight)) loadImageERROR("Not enough memory to read PNG file"); // The PNG read function expects an array of rows, not a single 1-D array for(uInt32 irow = 0, offset = 0; irow < ReadInfo.height; ++irow, offset += ReadInfo.pitch) ReadInfo.row_pointers[irow] = png_bytep(ReadInfo.buffer.get() + offset); // Read the entire image in one go png_read_image(png_ptr, ReadInfo.row_pointers.get()); // We're finished reading png_read_end(png_ptr, info_ptr); // Load image into the surface, setting the correct dimensions loadImagetoSurface(surface); // Cleanup done: if(png_ptr) png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : nullptr, nullptr); if(err_message) throw runtime_error(err_message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::saveImage(const string& filename, const VariantList& comments) { ofstream out(filename, std::ios_base::binary); if(!out.is_open()) throw runtime_error("ERROR: Couldn't create snapshot file"); const GUI::Rect& rect = myFB.imageRect(); png_uint_32 width = rect.width(), height = rect.height(); // Get framebuffer pixel data (we get ABGR format) unique_ptr buffer = make_unique(width * height * 4); myFB.readPixels(buffer.get(), width*4, rect); // Set up pointers into "buffer" byte array unique_ptr rows = make_unique(height); for(png_uint_32 k = 0; k < height; ++k) rows[k] = png_bytep(buffer.get() + k*width*4); // And save the image saveImage(out, rows, width, height, comments); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::saveImage(const string& filename, const FBSurface& surface, const GUI::Rect& rect, const VariantList& comments) { ofstream out(filename, std::ios_base::binary); if(!out.is_open()) throw runtime_error("ERROR: Couldn't create snapshot file"); // Do we want the entire surface or just a section? png_uint_32 width = rect.width(), height = rect.height(); if(rect.empty()) { width = surface.width(); height = surface.height(); } // Get the surface pixel data (we get ABGR format) unique_ptr buffer = make_unique(width * height * 4); surface.readPixels(buffer.get(), width, rect); // Set up pointers into "buffer" byte array unique_ptr rows = make_unique(height); for(png_uint_32 k = 0; k < height; ++k) rows[k] = png_bytep(buffer.get() + k*width*4); // And save the image saveImage(out, rows, width, height, comments); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::saveImage(ofstream& out, const unique_ptr& rows, png_uint_32 width, png_uint_32 height, const VariantList& comments) { #define saveImageERROR(s) { err_message = s; goto done; } png_structp png_ptr = nullptr; png_infop info_ptr = nullptr; const char* err_message = nullptr; // Create the PNG saving context structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, png_user_error, png_user_warn); if(png_ptr == nullptr) saveImageERROR("Couldn't allocate memory for PNG file"); // Allocate/initialize the memory for image information. REQUIRED. info_ptr = png_create_info_struct(png_ptr); if(info_ptr == nullptr) saveImageERROR("Couldn't create image information for PNG file"); // Set up the output control png_set_write_fn(png_ptr, &out, png_write_data, png_io_flush); // Write PNG header info png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); // Write comments writeComments(png_ptr, info_ptr, comments); // Write the file header information. REQUIRED png_write_info(png_ptr, info_ptr); // Pack pixels into bytes png_set_packing(png_ptr); // Swap location of alpha bytes from ARGB to RGBA png_set_swap_alpha(png_ptr); // Pack ARGB into RGB png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); // Flip BGR pixels to RGB png_set_bgr(png_ptr); // Write the entire image in one go png_write_image(png_ptr, rows.get()); // We're finished writing png_write_end(png_ptr, info_ptr); // Cleanup done: if(png_ptr) png_destroy_write_struct(&png_ptr, &info_ptr); if(err_message) throw runtime_error(err_message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PNGLibrary::allocateStorage(png_uint_32 w, png_uint_32 h) { // Create space for the entire image (3 bytes per pixel in RGB format) uInt32 req_buffer_size = w * h * 3; if(req_buffer_size > ReadInfo.buffer_size) { ReadInfo.buffer = make_unique(req_buffer_size); if(ReadInfo.buffer == nullptr) return false; ReadInfo.buffer_size = req_buffer_size; } uInt32 req_row_size = h; if(req_row_size > ReadInfo.row_size) { ReadInfo.row_pointers = make_unique(req_row_size); if(ReadInfo.row_pointers == nullptr) return false; ReadInfo.row_size = req_row_size; } ReadInfo.width = w; ReadInfo.height = h; ReadInfo.pitch = w * 3; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::loadImagetoSurface(FBSurface& surface) { // First determine if we need to resize the surface uInt32 iw = ReadInfo.width, ih = ReadInfo.height; if(iw > surface.width() || ih > surface.height()) surface.resize(iw, ih); // The source dimensions are set here; the destination dimensions are // set by whoever owns the surface surface.setSrcPos(0, 0); surface.setSrcSize(iw, ih); // Convert RGB triples into pixels and store in the surface uInt32 *s_buf, s_pitch; surface.basePtr(s_buf, s_pitch); uInt8* i_buf = ReadInfo.buffer.get(); uInt32 i_pitch = ReadInfo.pitch; for(uInt32 irow = 0; irow < ih; ++irow, i_buf += i_pitch, s_buf += s_pitch) { uInt8* i_ptr = i_buf; uInt32* s_ptr = s_buf; for(uInt32 icol = 0; icol < ReadInfo.width; ++icol, i_ptr += 3) *s_ptr++ = myFB.mapRGB(*i_ptr, *(i_ptr+1), *(i_ptr+2)); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::writeComments(png_structp png_ptr, png_infop info_ptr, const VariantList& comments) { uInt32 numComments = uInt32(comments.size()); if(numComments == 0) return; unique_ptr text_ptr = make_unique(numComments); for(uInt32 i = 0; i < numComments; ++i) { text_ptr[i].key = const_cast(comments[i].first.c_str()); text_ptr[i].text = const_cast(comments[i].second.toCString()); text_ptr[i].compression = PNG_TEXT_COMPRESSION_NONE; text_ptr[i].text_length = 0; } png_set_text(png_ptr, info_ptr, text_ptr.get(), numComments); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_read_data(png_structp ctx, png_bytep area, png_size_t size) { (static_cast(png_get_io_ptr(ctx)))->read( reinterpret_cast(area), size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_write_data(png_structp ctx, png_bytep area, png_size_t size) { (static_cast(png_get_io_ptr(ctx)))->write( reinterpret_cast(area), size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_io_flush(png_structp ctx) { (static_cast(png_get_io_ptr(ctx)))->flush(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_user_warn(png_structp ctx, png_const_charp str) { throw runtime_error(string("PNGLibrary warning: ") + str); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PNGLibrary::png_user_error(png_structp ctx, png_const_charp str) { throw runtime_error(string("PNGLibrary error: ") + str); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PNGLibrary::ReadInfoType PNGLibrary::ReadInfo = { nullptr, nullptr, 0, 0, 0, 0, 0 }; stella-5.1.1/src/common/PNGLibrary.hxx000066400000000000000000000125431324334165500175760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PNGLIBRARY_HXX #define PNGLIBRARY_HXX #include class FrameBuffer; class FBSurface; class Properties; #include "bspf.hxx" /** This class implements a thin wrapper around the libpng library, and abstracts all the irrelevant details other loading and saving an actual image. @author Stephen Anthony */ class PNGLibrary { public: PNGLibrary(const FrameBuffer& fb); /** Read a PNG image from the specified file into a FBSurface structure, scaling the image to the surface bounds. @param filename The filename to load the PNG image @param surface The FBSurface into which to place the PNG data @post On success, the FBSurface containing image data, otherwise a runtime_error is thrown containing a more detailed error message. */ void loadImage(const string& filename, FBSurface& surface); /** Save the current FrameBuffer image to a PNG file. Note that in most cases this will be a TIA image, but it could actually be used for *any* mode. @param filename The filename to save the PNG image @param comments The text comments to add to the PNG image @post On success, the PNG file has been saved to 'filename', otherwise a runtime_error is thrown containing a more detailed error message. */ void saveImage(const string& filename, const VariantList& comments = EmptyVarList); /** Save the given surface to a PNG file. @param filename The filename to save the PNG image @param surface The surface data for the PNG image @param rect The area of the surface to use @param comments The text comments to add to the PNG image @post On success, the PNG file has been saved to 'filename', otherwise a runtime_error is thrown containing a more detailed error message. */ void saveImage(const string& filename, const FBSurface& surface, const GUI::Rect& rect = GUI::EmptyRect, const VariantList& comments = EmptyVarList); private: const FrameBuffer& myFB; // The following data remains between invocations of allocateStorage, // and is only changed when absolutely necessary. struct ReadInfoType { BytePtr buffer; unique_ptr row_pointers; png_uint_32 width, height, pitch; uInt32 buffer_size, row_size; }; static ReadInfoType ReadInfo; /** Allocate memory for PNG read operations. This is used to provide a basic memory manager, so that we don't constantly allocate and deallocate memory for each image loaded. The method fills the 'ReadInfo' struct with valid memory locations dependent on the given dimensions. If memory has been previously allocated and it can accommodate the given dimensions, it is used directly. @param iwidth The width of the PNG image @param iheight The height of the PNG image */ bool allocateStorage(png_uint_32 iwidth, png_uint_32 iheight); /** The actual method which saves a PNG image. @param out The output stream for writing PNG data @param rows Pointer into PNG RGB data for each row @param width The width of the PNG image @param height The height of the PNG image @param comments The text comments to add to the PNG image */ void saveImage(ofstream& out, const unique_ptr& rows, png_uint_32 width, png_uint_32 height, const VariantList& comments); /** Load the PNG data from 'ReadInfo' into the FBSurface. The surface is resized as necessary to accommodate the data. @param surface The FBSurface into which to place the PNG data */ void loadImagetoSurface(FBSurface& surface); /** Write PNG tEXt chunks to the image. */ void writeComments(png_structp png_ptr, png_infop info_ptr, const VariantList& comments); /** PNG library callback functions */ static void png_read_data(png_structp ctx, png_bytep area, png_size_t size); static void png_write_data(png_structp ctx, png_bytep area, png_size_t size); static void png_io_flush(png_structp ctx); [[noreturn]] static void png_user_warn(png_structp ctx, png_const_charp str); [[noreturn]] static void png_user_error(png_structp ctx, png_const_charp str); private: // Following constructors and assignment operators not supported PNGLibrary(const PNGLibrary&) = delete; PNGLibrary(PNGLibrary&&) = delete; PNGLibrary& operator=(const PNGLibrary&) = delete; PNGLibrary& operator=(PNGLibrary&&) = delete; }; #endif stella-5.1.1/src/common/RewindManager.cxx000066400000000000000000000244341324334165500203450ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "OSystem.hxx" #include "Serializer.hxx" #include "StateManager.hxx" #include "TIA.hxx" #include "EventHandler.hxx" #include "RewindManager.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RewindManager::RewindManager(OSystem& system, StateManager& statemgr) : myOSystem(system), myStateManager(statemgr) { setup(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RewindManager::setup() { myLastTimeMachineAdd = false; string prefix = myOSystem.settings().getBool("dev.settings") ? "dev." : "plr."; mySize = myOSystem.settings().getInt(prefix + "tm.size"); if(mySize != myStateList.capacity()) resize(mySize); myUncompressed = myOSystem.settings().getInt(prefix + "tm.uncompressed"); myInterval = INTERVAL_CYCLES[0]; for(int i = 0; i < NUM_INTERVALS; ++i) if(INT_SETTINGS[i] == myOSystem.settings().getString(prefix + "tm.interval")) myInterval = INTERVAL_CYCLES[i]; myHorizon = HORIZON_CYCLES[NUM_HORIZONS-1]; for(int i = 0; i < NUM_HORIZONS; ++i) if(HOR_SETTINGS[i] == myOSystem.settings().getString(prefix + "tm.horizon")) myHorizon = HORIZON_CYCLES[i]; // calc interval growth factor for compression // this factor defines the backward horizon const double MAX_FACTOR = 1E8; double minFactor = 0, maxFactor = MAX_FACTOR; myFactor = 1; while(myUncompressed < mySize) { double interval = myInterval; double cycleSum = interval * (myUncompressed + 1); // calculate nextCycles factor myFactor = (minFactor + maxFactor) / 2; // horizon not reachable? if(myFactor == MAX_FACTOR) break; // sum up interval cycles (first state is not compressed) for(uInt32 i = myUncompressed + 1; i < mySize; ++i) { interval *= myFactor; cycleSum += interval; } double diff = cycleSum - myHorizon; // exit loop if result is close enough if(std::abs(diff) < myHorizon * 1E-5) break; // define new boundary if(cycleSum < myHorizon) minFactor = myFactor; else maxFactor = myFactor; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RewindManager::addState(const string& message, bool timeMachine) { // only check for Time Machine states, ignore for debugger if(timeMachine && myStateList.currentIsValid()) { // check if the current state has the right interval from the last state RewindState& lastState = myStateList.current(); uInt32 interval = myInterval; // adjust frame timed intervals to actual scanlines (vs 262) if(interval >= 76 * 262 && interval <= 76 * 262 * 30) { const uInt32 scanlines = std::max(myOSystem.console().tia().scanlinesLastFrame(), 240u); interval = interval * scanlines / 262; } if(myOSystem.console().tia().cycles() - lastState.cycles < interval) return false; } // Remove all future states myStateList.removeToLast(); // Make sure we never run out of space if(myStateList.full()) compressStates(); // Add new state at the end of the list (queue adds at end) // This updates the 'current' iterator inside the list myStateList.addLast(); RewindState& state = myStateList.current(); Serializer& s = state.data; s.rewind(); // rewind Serializer internal buffers if(myStateManager.saveState(s) && myOSystem.console().tia().saveDisplay(s)) { state.message = message; state.cycles = myOSystem.console().tia().cycles(); myLastTimeMachineAdd = timeMachine; return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 RewindManager::rewindStates(uInt32 numStates) { uInt64 startCycles = myOSystem.console().tia().cycles(); uInt32 i; string message; for(i = 0; i < numStates; ++i) { if(!atFirst()) { if(!myLastTimeMachineAdd) // Set internal current iterator to previous state (back in time), // since we will now process this state... myStateList.moveToPrevious(); else // ...except when the last state was added automatically, // because that already happened one interval before myLastTimeMachineAdd = false; RewindState& state = myStateList.current(); Serializer& s = state.data; s.rewind(); // rewind Serializer internal buffers } else break; } if(i) // Load the current state and get the message string for the rewind message = loadState(startCycles, i); else message = "Rewind not possible"; if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE) myOSystem.frameBuffer().showMessage(message); return i; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 RewindManager::unwindStates(uInt32 numStates) { uInt64 startCycles = myOSystem.console().tia().cycles(); uInt32 i; string message; for(i = 0; i < numStates; ++i) { if(!atLast()) { // Set internal current iterator to nextCycles state (forward in time), // since we will now process this state myStateList.moveToNext(); RewindState& state = myStateList.current(); Serializer& s = state.data; s.rewind(); // rewind Serializer internal buffers } else break; } if(i) // Load the current state and get the message string for the unwind message = loadState(startCycles, i); else message = "Unwind not possible"; if(myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE) myOSystem.frameBuffer().showMessage(message); return i; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 RewindManager::windStates(uInt32 numStates, bool unwind) { if(unwind) return unwindStates(numStates); else return rewindStates(numStates); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RewindManager::compressStates() { double expectedCycles = myInterval * myFactor * (1 + myFactor); double maxError = 1.5; uInt32 idx = myStateList.size() - 2; // in case maxError is <= 1.5 remove first state by default: Common::LinkedObjectPool::const_iter removeIter = myStateList.first(); /*if(myUncompressed < mySize) // if compression is enabled, the first but one state is removed by default: removeIter++;*/ // iterate from last but one to first but one for(auto it = myStateList.previous(myStateList.last()); it != myStateList.first(); --it) { if(idx < mySize - myUncompressed) { expectedCycles *= myFactor; uInt64 prevCycles = myStateList.previous(it)->cycles; uInt64 nextCycles = myStateList.next(it)->cycles; double error = expectedCycles / (nextCycles - prevCycles); if(error > maxError) { maxError = error; removeIter = it; } } --idx; } myStateList.remove(removeIter); // remove } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RewindManager::loadState(Int64 startCycles, uInt32 numStates) { RewindState& state = myStateList.current(); Serializer& s = state.data; myStateManager.loadState(s); myOSystem.console().tia().loadDisplay(s); Int64 diff = startCycles - state.cycles; stringstream message; message << (diff >= 0 ? "Rewind" : "Unwind") << " " << getUnitString(diff); message << " [" << myStateList.currentIdx() << "/" << myStateList.size() << "]"; // add optional message if(numStates == 1 && !state.message.empty()) message << " (" << state.message << ")"; return message.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RewindManager::getUnitString(Int64 cycles) { const Int32 scanlines = std::max(myOSystem.console().tia().scanlinesLastFrame(), 240u); const bool isNTSC = scanlines <= 287; const Int32 NTSC_FREQ = 1193182; // ~76*262*60 const Int32 PAL_FREQ = 1182298; // ~76*312*50 const Int32 freq = isNTSC ? NTSC_FREQ : PAL_FREQ; // = cycles/second const Int32 NUM_UNITS = 5; const string UNIT_NAMES[NUM_UNITS] = { "cycle", "scanline", "frame", "second", "minute" }; const Int64 UNIT_CYCLES[NUM_UNITS + 1] = { 1, 76, 76 * scanlines, freq, freq * 60, Int64(1) << 62 }; stringstream result; Int32 i; cycles = std::abs(cycles); for(i = 0; i < NUM_UNITS - 1; ++i) { // use the lower unit up to twice the nextCycles unit, except for an exact match of the nextCycles unit // TODO: does the latter make sense, e.g. for ROMs with changing scanlines? if(cycles == 0 || (cycles < UNIT_CYCLES[i + 1] * 2 && cycles % UNIT_CYCLES[i + 1] != 0)) break; } result << cycles / UNIT_CYCLES[i] << " " << UNIT_NAMES[i]; if(cycles / UNIT_CYCLES[i] != 1) result << "s"; return result.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt64 RewindManager::getFirstCycles() const { return !myStateList.empty() ? myStateList.first()->cycles : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt64 RewindManager::getCurrentCycles() const { if(myStateList.currentIsValid()) return myStateList.current().cycles; else return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt64 RewindManager::getLastCycles() const { return !myStateList.empty() ? myStateList.last()->cycles : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - IntArray RewindManager::cyclesList() const { IntArray arr; uInt64 firstCycle = getFirstCycles(); for(auto it = myStateList.cbegin(); it != myStateList.cend(); ++it) arr.push_back(uInt32(it->cycles - firstCycle)); return arr; } stella-5.1.1/src/common/RewindManager.hxx000066400000000000000000000142371324334165500203520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef REWIND_MANAGER_HXX #define REWIND_MANAGER_HXX class OSystem; class StateManager; #include "LinkedObjectPool.hxx" #include "bspf.hxx" /** This class is used to save (and later 'replay') system save states. In this implementation, we assume states are added at the end of the list. Rewinding involves moving the internal iterator backwards in time (towards the beginning of the list). Unwinding involves moving the internal iterator forwards in time (towards the end of the list). Any time a new state is added, all states from the current iterator position to the end of the list (aka, all future states) are removed, and the internal iterator moves to the insertion point of the data (the end of the list). If the list is full, states are either removed at the beginning (compression off) or at selective positions (compression on). @author Stephen Anthony */ class RewindManager { public: RewindManager(OSystem& system, StateManager& statemgr); public: static constexpr int NUM_INTERVALS = 7; // cycle values for the intervals const uInt32 INTERVAL_CYCLES[NUM_INTERVALS] = { 76 * 262, 76 * 262 * 3, 76 * 262 * 10, 76 * 262 * 30, 76 * 262 * 60, 76 * 262 * 60 * 3, 76 * 262 * 60 * 10 }; // settings values for the intervals const string INT_SETTINGS[NUM_INTERVALS] = { "1f", "3f", "10f", "30f", "1s", "3s", "10s" }; static constexpr int NUM_HORIZONS = 8; // cycle values for the horzions const uInt64 HORIZON_CYCLES[NUM_HORIZONS] = { 76 * 262 * 60 * 3, 76 * 262 * 60 * 10, 76 * 262 * 60 * 30, 76 * 262 * 60 * 60, 76 * 262 * 60 * 60 * 3, 76 * 262 * 60 * 60 * 10, uInt64(76) * 262 * 60 * 60 * 30, uInt64(76) * 262 * 60 * 60 * 60 }; // settings values for the horzions const string HOR_SETTINGS[NUM_HORIZONS] = { "3s", "10s", "30s", "1m", "3m", "10m", "30m", "60m" }; /** Initializes state list and calculates compression factor. */ void setup(); /** Add a new state file with the given message; this message will be displayed when the state is replayed. @param message Message to display when replaying this state */ bool addState(const string& message, bool timeMachine = false); /** Rewind numStates levels of the state list, and display the message associated with that state. @param numStates Number of states to rewind @return Number of states to rewinded */ uInt32 rewindStates(uInt32 numStates = 1); /** Unwind numStates levels of the state list, and display the message associated with that state. @param numStates Number of states to unwind @return Number of states to unwinded */ uInt32 unwindStates(uInt32 numStates = 1); /** Rewind/unwind numStates levels of the state list, and display the message associated with that state. @param numStates Number of states to wind @param unwind unwind or rewind @return Number of states to winded */ uInt32 windStates(uInt32 numStates, bool unwind); bool atFirst() const { return myStateList.atFirst(); } bool atLast() const { return myStateList.atLast(); } void resize(uInt32 size) { myStateList.resize(size); } void clear() { myStateList.clear(); } /** Convert the cycles into a unit string. */ string getUnitString(Int64 cycles); uInt32 getCurrentIdx() { return myStateList.currentIdx(); } uInt32 getLastIdx() { return myStateList.size(); } uInt64 getFirstCycles() const; uInt64 getCurrentCycles() const; uInt64 getLastCycles() const; /** Get a collection of cycle timestamps, offset from the first one in the list. This also determines the number of states in the list. */ IntArray cyclesList() const; private: OSystem& myOSystem; StateManager& myStateManager; uInt32 mySize; uInt32 myUncompressed; uInt32 myInterval; uInt64 myHorizon; double myFactor; bool myLastTimeMachineAdd; struct RewindState { Serializer data; // actual save state string message; // describes save state origin uInt64 cycles; // cycles since emulation started // We do nothing on object instantiation or copy // The goal of LinkedObjectPool is to not do any allocations at all RewindState() { } RewindState(const RewindState&) { } // Output object info; used for debugging only friend ostream& operator<<(ostream& os, const RewindState& s) { return os << "msg: " << s.message << " cycle: " << s.cycles; } }; // The linked-list to store states (internally it takes care of reducing // frequent (de)-allocations) Common::LinkedObjectPool myStateList; /** Remove a save state from the list */ void compressStates(); /** Load the current state and get the message string for the rewind/unwind @return The message */ string loadState(Int64 startCycles, uInt32 numStates); private: // Following constructors and assignment operators not supported RewindManager() = delete; RewindManager(const RewindManager&) = delete; RewindManager(RewindManager&&) = delete; RewindManager& operator=(const RewindManager&) = delete; RewindManager& operator=(RewindManager&&) = delete; }; #endif stella-5.1.1/src/common/SDL_lib.hxx000066400000000000000000000026641324334165500171000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SDL_LIB_HXX #define SDL_LIB_HXX /* * We can't control the quality of code from outside projects, so for now * just disable warnings for it. */ #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdocumentation" #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" #pragma clang diagnostic ignored "-Wimplicit-fallthrough" #pragma clang diagnostic ignored "-Wreserved-id-macro" #include #pragma clang diagnostic pop #else #include #endif /* * Seems to be needed for ppc64le, doesn't hurt other archs * Note that this is a problem in SDL2, which includes * https://bugzilla.redhat.com/show_bug.cgi?id=1419452 */ #undef vector #undef pixel #undef bool #endif stella-5.1.1/src/common/SoundNull.hxx000066400000000000000000000114341324334165500175460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SOUND_NULL_HXX #define SOUND_NULL_HXX #include "bspf.hxx" #include "Sound.hxx" #include "OSystem.hxx" /** This class implements a Null sound object, where-by sound generation is completely disabled. @author Stephen Anthony */ class SoundNull : public Sound { public: /** Create a new sound object. The init method must be invoked before using the object. */ SoundNull(OSystem& osystem) : Sound(osystem) { myOSystem.logMessage("Sound disabled.\n", 1); } /** Destructor */ virtual ~SoundNull() = default; public: /** Enables/disables the sound subsystem. @param state True or false, to enable or disable the sound system */ void setEnabled(bool state) override { } /** Sets the number of channels (mono or stereo sound). @param channels The number of channels */ void setChannels(uInt32 channels) override { } /** Sets the display framerate. Sound generation for NTSC and PAL games depends on the framerate, so we need to set it here. @param framerate The base framerate depending on NTSC or PAL ROM */ void setFrameRate(float framerate) override { } /** Initializes the sound device. This must be called before any calls are made to derived methods. */ void open() override { } /** Should be called to close the sound device. Once called the sound device can be started again using the initialize method. */ void close() override { } /** Set the mute state of the sound object. While muted no sound is played. @param state Mutes sound if true, unmute if false */ void mute(bool state) override { } /** Reset the sound device. */ void reset() override { } /** Sets the sound register to a given value. @param addr The register address @param value The value to save into the register @param cycle The system cycle at which the register is being updated */ void set(uInt16 addr, uInt8 value, uInt64 cycle) override { } /** Sets the volume of the sound device to the specified level. The volume is given as a percentage from 0 to 100. Values outside this range indicate that the volume shouldn't be changed at all. @param percent The new volume percentage level for the sound device */ void setVolume(Int32 percent) override { } /** Adjusts the volume of the sound device based on the given direction. @param direction Increase or decrease the current volume by a predefined amount based on the direction (1 = increase, -1 =decrease) */ void adjustVolume(Int8 direction) override { } public: /** Saves the current state of this device to the given Serializer. @param out The serializer device to save to. @return The result of the save. True on success, false on failure. */ bool save(Serializer& out) const override { out.putString("TIASound"); for(int i = 0; i < 6; ++i) out.putByte(0); // myLastRegisterSetCycle out.putInt(0); return true; } /** Loads the current state of this device from the given Serializer. @param in The Serializer device to load from. @return The result of the load. True on success, false on failure. */ bool load(Serializer& in) override { if(in.getString() != "TIASound") return false; // Read sound registers and discard for(int i = 0; i < 6; ++i) in.getByte(); // myLastRegisterSetCycle in.getInt(); return true; } /** Get a descriptor for this console class (used in error checking). @return The name of the object */ string name() const override { return "TIASound"; } private: // Following constructors and assignment operators not supported SoundNull() = delete; SoundNull(const SoundNull&) = delete; SoundNull(SoundNull&&) = delete; SoundNull& operator=(const SoundNull&) = delete; SoundNull& operator=(SoundNull&&) = delete; }; #endif stella-5.1.1/src/common/SoundSDL2.cxx000066400000000000000000000356511324334165500173420ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifdef SOUND_SUPPORT #include #include #include #include "SDL_lib.hxx" #include "TIASnd.hxx" #include "TIAConstants.hxx" #include "FrameBuffer.hxx" #include "Settings.hxx" #include "System.hxx" #include "OSystem.hxx" #include "Console.hxx" #include "SoundSDL2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL2::SoundSDL2(OSystem& osystem) : Sound(osystem), myIsEnabled(false), myIsInitializedFlag(false), myLastRegisterSetCycle(0), myNumChannels(0), myFragmentSizeLogBase2(0), myFragmentSizeLogDiv1(0), myFragmentSizeLogDiv2(0), myIsMuted(true), myVolume(100) { myOSystem.logMessage("SoundSDL2::SoundSDL2 started ...", 2); // The sound system is opened only once per program run, to eliminate // issues with opening and closing it multiple times // This fixes a bug most prevalent with ATI video cards in Windows, // whereby sound stopped working after the first video change SDL_AudioSpec desired; desired.freq = myOSystem.settings().getInt("freq"); desired.format = AUDIO_S16SYS; desired.channels = 2; desired.samples = myOSystem.settings().getInt("fragsize"); desired.callback = callback; desired.userdata = static_cast(this); ostringstream buf; if(SDL_OpenAudio(&desired, &myHardwareSpec) < 0) { buf << "WARNING: Couldn't open SDL audio system! " << endl << " " << SDL_GetError() << endl; myOSystem.logMessage(buf.str(), 0); return; } // Make sure the sample buffer isn't to big (if it is the sound code // will not work so we'll need to disable the audio support) if((float(myHardwareSpec.samples) / float(myHardwareSpec.freq)) >= 0.25) { buf << "WARNING: Sound device doesn't support realtime audio! Make " << "sure a sound" << endl << " server isn't running. Audio is disabled." << endl; myOSystem.logMessage(buf.str(), 0); SDL_CloseAudio(); return; } // Pre-compute fragment-related variables as much as possible myFragmentSizeLogBase2 = log(myHardwareSpec.samples) / log(2.0); myFragmentSizeLogDiv1 = myFragmentSizeLogBase2 / 60.0; myFragmentSizeLogDiv2 = (myFragmentSizeLogBase2 - 1) / 60.0; myIsInitializedFlag = true; SDL_PauseAudio(1); myOSystem.logMessage("SoundSDL2::SoundSDL2 initialized", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL2::~SoundSDL2() { // Close the SDL audio system if it's initialized if(myIsInitializedFlag) { SDL_CloseAudio(); myIsEnabled = myIsInitializedFlag = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::setEnabled(bool state) { myOSystem.settings().setValue("sound", state); myOSystem.logMessage(state ? "SoundSDL2::setEnabled(true)" : "SoundSDL2::setEnabled(false)", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::open() { myOSystem.logMessage("SoundSDL2::open started ...", 2); myIsEnabled = false; mute(true); if(!myIsInitializedFlag || !myOSystem.settings().getBool("sound")) { myOSystem.logMessage("Sound disabled\n", 1); return; } // Now initialize the TIASound object which will actually generate sound myTIASound.outputFrequency(myHardwareSpec.freq); const string& chanResult = myTIASound.channels(myHardwareSpec.channels, myNumChannels == 2); // Adjust volume to that defined in settings myVolume = myOSystem.settings().getInt("volume"); setVolume(myVolume); // Show some info ostringstream buf; buf << "Sound enabled:" << endl << " Volume: " << myVolume << endl << " Frag size: " << uInt32(myHardwareSpec.samples) << endl << " Frequency: " << uInt32(myHardwareSpec.freq) << endl << " Channels: " << uInt32(myHardwareSpec.channels) << " (" << chanResult << ")" << endl << endl; myOSystem.logMessage(buf.str(), 1); // And start the SDL sound subsystem ... myIsEnabled = true; mute(false); myOSystem.logMessage("SoundSDL2::open finished", 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::close() { if(myIsInitializedFlag) { myIsEnabled = false; SDL_PauseAudio(1); myLastRegisterSetCycle = 0; myTIASound.reset(); myRegWriteQueue.clear(); myOSystem.logMessage("SoundSDL2::close", 2); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::mute(bool state) { if(myIsInitializedFlag) { myIsMuted = state; SDL_PauseAudio(myIsMuted ? 1 : 0); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::reset() { if(myIsInitializedFlag) { SDL_PauseAudio(1); myLastRegisterSetCycle = 0; myTIASound.reset(); myRegWriteQueue.clear(); mute(myIsMuted); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::setVolume(Int32 percent) { if(myIsInitializedFlag && (percent >= 0) && (percent <= 100)) { myOSystem.settings().setValue("volume", percent); SDL_LockAudio(); myVolume = percent; myTIASound.volume(percent); SDL_UnlockAudio(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::adjustVolume(Int8 direction) { ostringstream strval; string message; Int32 percent = myVolume; if(direction == -1) percent -= 2; else if(direction == 1) percent += 2; if((percent < 0) || (percent > 100)) return; setVolume(percent); // Now show an onscreen message strval << percent; message = "Volume set to "; message += strval.str(); myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::setChannels(uInt32 channels) { if(channels == 1 || channels == 2) myNumChannels = channels; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::setFrameRate(float framerate) { // Recalculate since frame rate has changed // FIXME - should we clear out the queue or adjust the values in it? myFragmentSizeLogDiv1 = myFragmentSizeLogBase2 / framerate; myFragmentSizeLogDiv2 = (myFragmentSizeLogBase2 - 1) / framerate; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::set(uInt16 addr, uInt8 value, uInt64 cycle) { SDL_LockAudio(); // First, calculate how many seconds would have past since the last // register write on a real 2600 double delta = double(cycle - myLastRegisterSetCycle) / 1193191.66666667; // Now, adjust the time based on the frame rate the user has selected. For // the sound to "scale" correctly, we have to know the games real frame // rate (e.g., 50 or 60) and the currently emulated frame rate. We use these // values to "scale" the time before the register change occurs. myRegWriteQueue.enqueue(addr, value, delta); // Update last cycle counter to the current cycle myLastRegisterSetCycle = cycle; SDL_UnlockAudio(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::processFragment(Int16* stream, uInt32 length) { uInt32 channels = myHardwareSpec.channels; length = length / channels; // If there are excessive items on the queue then we'll remove some if(myRegWriteQueue.duration() > myFragmentSizeLogDiv1) { double removed = 0.0; while(removed < myFragmentSizeLogDiv2) { RegWrite& info = myRegWriteQueue.front(); removed += info.delta; myTIASound.set(info.addr, info.value); myRegWriteQueue.dequeue(); } } double position = 0.0; double remaining = length; while(remaining > 0.0) { if(myRegWriteQueue.size() == 0) { // There are no more pending TIA sound register updates so we'll // use the current settings to finish filling the sound fragment myTIASound.process(stream + (uInt32(position) * channels), length - uInt32(position)); // Since we had to fill the fragment we'll reset the cycle counter // to zero. NOTE: This isn't 100% correct, however, it'll do for // now. We should really remember the overrun and remove it from // the delta of the next write. myLastRegisterSetCycle = 0; break; } else { // There are pending TIA sound register updates so we need to // update the sound buffer to the point of the next register update RegWrite& info = myRegWriteQueue.front(); // How long will the remaining samples in the fragment take to play double duration = remaining / myHardwareSpec.freq; // Does the register update occur before the end of the fragment? if(info.delta <= duration) { // If the register update time hasn't already passed then // process samples upto the point where it should occur if(info.delta > 0.0) { // Process the fragment upto the next TIA register write. We // round the count passed to process up if needed. double samples = (myHardwareSpec.freq * info.delta); myTIASound.process(stream + (uInt32(position) * channels), uInt32(samples) + uInt32(position + samples) - (uInt32(position) + uInt32(samples))); position += samples; remaining -= samples; } myTIASound.set(info.addr, info.value); myRegWriteQueue.dequeue(); } else { // The next register update occurs in the next fragment so finish // this fragment with the current TIA settings and reduce the register // update delay by the corresponding amount of time myTIASound.process(stream + (uInt32(position) * channels), length - uInt32(position)); info.delta -= duration; break; } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::callback(void* udata, uInt8* stream, int len) { SoundSDL2* sound = static_cast(udata); if(sound->myIsEnabled) { // The callback is requesting 8-bit (unsigned) data, but the TIA sound // emulator deals in 16-bit (signed) data // So, we need to convert the pointer and half the length sound->processFragment(reinterpret_cast(stream), uInt32(len) >> 1); } else SDL_memset(stream, 0, len); // Write 'silence' } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SoundSDL2::save(Serializer& out) const { try { out.putString(name()); // Only get the TIA sound registers if sound is enabled if(myIsInitializedFlag) { out.putByte(myTIASound.get(TIARegister::AUDC0)); out.putByte(myTIASound.get(TIARegister::AUDC1)); out.putByte(myTIASound.get(TIARegister::AUDF0)); out.putByte(myTIASound.get(TIARegister::AUDF1)); out.putByte(myTIASound.get(TIARegister::AUDV0)); out.putByte(myTIASound.get(TIARegister::AUDV1)); } else for(int i = 0; i < 6; ++i) out.putByte(0); out.putLong(myLastRegisterSetCycle); } catch(...) { myOSystem.logMessage("ERROR: SoundSDL2::save", 0); return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SoundSDL2::load(Serializer& in) { try { if(in.getString() != name()) return false; // Only update the TIA sound registers if sound is enabled // Make sure to empty the queue of previous sound fragments if(myIsInitializedFlag) { SDL_PauseAudio(1); myRegWriteQueue.clear(); myTIASound.set(TIARegister::AUDC0, in.getByte()); myTIASound.set(TIARegister::AUDC1, in.getByte()); myTIASound.set(TIARegister::AUDF0, in.getByte()); myTIASound.set(TIARegister::AUDF1, in.getByte()); myTIASound.set(TIARegister::AUDV0, in.getByte()); myTIASound.set(TIARegister::AUDV1, in.getByte()); if(!myIsMuted) SDL_PauseAudio(0); } else for(int i = 0; i < 6; ++i) in.getByte(); myLastRegisterSetCycle = in.getLong(); } catch(...) { myOSystem.logMessage("ERROR: SoundSDL2::load", 0); return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL2::RegWriteQueue::RegWriteQueue(uInt32 capacity) : myBuffer(make_unique(capacity)), myCapacity(capacity), mySize(0), myHead(0), myTail(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::RegWriteQueue::clear() { myHead = myTail = mySize = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::RegWriteQueue::dequeue() { if(mySize > 0) { myHead = (myHead + 1) % myCapacity; --mySize; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - double SoundSDL2::RegWriteQueue::duration() const { double duration = 0.0; for(uInt32 i = 0; i < mySize; ++i) { duration += myBuffer[(myHead + i) % myCapacity].delta; } return duration; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::RegWriteQueue::enqueue(uInt16 addr, uInt8 value, double delta) { // If an attempt is made to enqueue more than the queue can hold then // we'll enlarge the queue's capacity. if(mySize == myCapacity) grow(); RegWrite& reg = myBuffer[myTail]; reg.addr = addr; reg.value = value; reg.delta = delta; myTail = (myTail + 1) % myCapacity; ++mySize; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SoundSDL2::RegWrite& SoundSDL2::RegWriteQueue::front() const { assert(mySize != 0); return myBuffer[myHead]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 SoundSDL2::RegWriteQueue::size() const { return mySize; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SoundSDL2::RegWriteQueue::grow() { unique_ptr buffer = make_unique(myCapacity*2); for(uInt32 i = 0; i < mySize; ++i) buffer[i] = myBuffer[(myHead + i) % myCapacity]; myHead = 0; myTail = mySize; myCapacity *= 2; myBuffer = std::move(buffer); } #endif // SOUND_SUPPORT stella-5.1.1/src/common/SoundSDL2.hxx000066400000000000000000000203111324334165500173320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifdef SOUND_SUPPORT #ifndef SOUND_SDL2_HXX #define SOUND_SDL2_HXX class OSystem; #include "SDL_lib.hxx" #include "bspf.hxx" #include "TIASnd.hxx" #include "Sound.hxx" /** This class implements the sound API for SDL. @author Stephen Anthony and Bradford W. Mott */ class SoundSDL2 : public Sound { public: /** Create a new sound object. The init method must be invoked before using the object. */ SoundSDL2(OSystem& osystem); /** Destructor */ virtual ~SoundSDL2(); public: /** Enables/disables the sound subsystem. @param state True or false, to enable or disable the sound system */ void setEnabled(bool state) override; /** Sets the number of channels (mono or stereo sound). Note that this determines how the emulation should 'mix' the channels of the TIA sound system (of which there are always two). It does not specify the actual number of hardware channels that SDL should use; it will always attempt to use two channels in hardware. @param channels The number of channels */ void setChannels(uInt32 channels) override; /** Sets the display framerate. Sound generation for NTSC and PAL games depends on the framerate, so we need to set it here. @param framerate The base framerate depending on NTSC or PAL ROM */ void setFrameRate(float framerate) override; /** Initializes the sound device. This must be called before any calls are made to derived methods. */ void open() override; /** Should be called to close the sound device. Once called the sound device can be started again using the open method. */ void close() override; /** Set the mute state of the sound object. While muted no sound is played. @param state Mutes sound if true, unmute if false */ void mute(bool state) override; /** Reset the sound device. */ void reset() override; /** Sets the sound register to a given value. @param addr The register address @param value The value to save into the register @param cycle The system cycle at which the register is being updated */ void set(uInt16 addr, uInt8 value, uInt64 cycle) override; /** Sets the volume of the sound device to the specified level. The volume is given as a percentage from 0 to 100. Values outside this range indicate that the volume shouldn't be changed at all. @param percent The new volume percentage level for the sound device */ void setVolume(Int32 percent) override; /** Adjusts the volume of the sound device based on the given direction. @param direction Increase or decrease the current volume by a predefined amount based on the direction (1 = increase, -1 = decrease) */ void adjustVolume(Int8 direction) override; public: /** Saves the current state of this device to the given Serializer. @param out The serializer device to save to. @return The result of the save. True on success, false on failure. */ bool save(Serializer& out) const override; /** Loads the current state of this device from the given Serializer. @param in The Serializer device to load from. @return The result of the load. True on success, false on failure. */ bool load(Serializer& in) override; /** Get a descriptor for this console class (used in error checking). @return The name of the object */ string name() const override { return "TIASound"; } protected: /** Invoked by the sound callback to process the next sound fragment. The stream is 16-bits (even though the callback is 8-bits), since the TIASnd class always generates signed 16-bit stereo samples. @param stream Pointer to the start of the fragment @param length Length of the fragment */ void processFragment(Int16* stream, uInt32 length); protected: // Struct to hold information regarding a TIA sound register write struct RegWrite { uInt16 addr; uInt8 value; double delta; RegWrite(uInt16 a = 0, uInt8 v = 0, double d = 0.0) : addr(a), value(v), delta(d) { } }; /** A queue class used to hold TIA sound register writes before being processed while creating a sound fragment. */ class RegWriteQueue { public: /** Create a new queue instance with the specified initial capacity. If the queue ever reaches its capacity then it will automatically increase its size. */ RegWriteQueue(uInt32 capacity = 512); public: /** Clear any items stored in the queue. */ void clear(); /** Dequeue the first object in the queue. */ void dequeue(); /** Return the duration of all the items in the queue. */ double duration() const; /** Enqueue the specified object. */ void enqueue(uInt16 addr, uInt8 value, double delta); /** Return the item at the front on the queue. @return The item at the front of the queue. */ RegWrite& front() const; /** Answers the number of items currently in the queue. @return The number of items in the queue. */ uInt32 size() const; private: // Increase the size of the queue void grow(); private: unique_ptr myBuffer; uInt32 myCapacity; uInt32 mySize; uInt32 myHead; uInt32 myTail; private: // Following constructors and assignment operators not supported RegWriteQueue(const RegWriteQueue&) = delete; RegWriteQueue(RegWriteQueue&&) = delete; RegWriteQueue& operator=(const RegWriteQueue&) = delete; RegWriteQueue& operator=(RegWriteQueue&&) = delete; }; private: // TIASound emulation object TIASound myTIASound; // Indicates if the sound subsystem is to be initialized bool myIsEnabled; // Indicates if the sound device was successfully initialized bool myIsInitializedFlag; // Indicates the cycle when a sound register was last set uInt64 myLastRegisterSetCycle; // Indicates the number of channels (mono or stereo) uInt32 myNumChannels; // Log base 2 of the selected fragment size double myFragmentSizeLogBase2; // The myFragmentSizeLogBase2 variable is used in only two places, // both of which involve an expensive division in the sound // processing callback // These are pre-computed to speed up the callback as much as possible double myFragmentSizeLogDiv1, myFragmentSizeLogDiv2; // Indicates if the sound is currently muted bool myIsMuted; // Current volume as a percentage (0 - 100) uInt32 myVolume; // Audio specification structure SDL_AudioSpec myHardwareSpec; // Queue of TIA register writes RegWriteQueue myRegWriteQueue; private: // Callback function invoked by the SDL Audio library when it needs data static void callback(void* udata, uInt8* stream, int len); // Following constructors and assignment operators not supported SoundSDL2() = delete; SoundSDL2(const SoundSDL2&) = delete; SoundSDL2(SoundSDL2&&) = delete; SoundSDL2& operator=(const SoundSDL2&) = delete; SoundSDL2& operator=(SoundSDL2&&) = delete; }; #endif #endif // SOUND_SUPPORT stella-5.1.1/src/common/Stack.hxx000066400000000000000000000042421324334165500166670ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef STACK_HXX #define STACK_HXX #include #include #include "bspf.hxx" /** * Simple fixed size stack class. */ namespace Common { template class FixedStack { private: array _stack; uInt32 _size; public: using StackFunction = std::function; FixedStack() : _size(0) { } bool empty() const { return _size <= 0; } bool full() const { return _size >= CAPACITY; } T top() const { return _stack[_size - 1]; } void push(const T& x) { _stack[_size++] = x; } T pop() { return std::move(_stack[--_size]); } uInt32 size() const { return _size; } void replace(const T& oldItem, const T& newItem) { for(uInt32 i = 0; i < _size; ++i) { if(_stack[i] == oldItem) { _stack[i] = newItem; return; } } } // Apply the given function to every item in the stack // We do it this way so the stack API can be preserved, // and no access to individual elements is allowed outside // the class. void applyAll(const StackFunction& func) { for(uInt32 i = 0; i < _size; ++i) func(_stack[i]); } private: // Following constructors and assignment operators not supported FixedStack(const FixedStack&) = delete; FixedStack(FixedStack&&) = delete; FixedStack& operator=(const FixedStack&) = delete; FixedStack& operator=(FixedStack&&) = delete; }; } // Namespace Common #endif stella-5.1.1/src/common/StateManager.cxx000066400000000000000000000262761324334165500202030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Settings.hxx" #include "Console.hxx" #include "Cart.hxx" #include "Control.hxx" #include "Switches.hxx" #include "System.hxx" #include "Serializable.hxx" #include "RewindManager.hxx" #include "StateManager.hxx" #define STATE_HEADER "05010000state" // #define MOVIE_HEADER "03030000movie" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StateManager::StateManager(OSystem& osystem) : myOSystem(osystem), myCurrentSlot(0), myActiveMode(Mode::Off) { myRewindManager = make_unique(myOSystem, *this); reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StateManager::~StateManager() { } #if 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::toggleRecordMode() { if(myActiveMode != kMovieRecordMode) // Turn on movie record mode { myActiveMode = kOffMode; string moviefile = /*myOSystem.baseDir() +*/ "test.inp"; if(myMovieWriter.isOpen()) myMovieWriter.close(); if(!myMovieWriter.open(moviefile)) return false; // Prepend the ROM md5 so this state file only works with that ROM myMovieWriter.putString(myOSystem.console().properties().get(Cartridge_MD5)); if(!myOSystem.console().save(myMovieWriter)) return false; // Save controller types for this ROM // We need to check this, since some controllers save more state than // normal, and those states files wouldn't be compatible with normal // controllers. myMovieWriter.putString( myOSystem.console().controller(Controller::Left).name()); myMovieWriter.putString( myOSystem.console().controller(Controller::Right).name()); // If we get this far, we're really in movie record mode myActiveMode = kMovieRecordMode; } else // Turn off movie record mode { myActiveMode = kOffMode; myMovieWriter.close(); return false; } return myActiveMode == kMovieRecordMode; //////////////////////////////////////////////////////// // FIXME - For now, I'm going to use this to activate movie playback // Close the writer, since we're about to re-open in read mode myMovieWriter.close(); if(myActiveMode != kMoviePlaybackMode) // Turn on movie playback mode { myActiveMode = kOffMode; string moviefile = /*myOSystem.baseDir() + */ "test.inp"; if(myMovieReader.isOpen()) myMovieReader.close(); if(!myMovieReader.open(moviefile)) return false; // Check the ROM md5 if(myMovieReader.getString() != myOSystem.console().properties().get(Cartridge_MD5)) return false; if(!myOSystem.console().load(myMovieReader)) return false; // Check controller types const string& left = myMovieReader.getString(); const string& right = myMovieReader.getString(); if(left != myOSystem.console().controller(Controller::Left).name() || right != myOSystem.console().controller(Controller::Right).name()) return false; // If we get this far, we're really in movie record mode myActiveMode = kMoviePlaybackMode; } else // Turn off movie playback mode { myActiveMode = kOffMode; myMovieReader.close(); return false; } } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::toggleTimeMachine() { bool devSettings = myOSystem.settings().getBool("dev.settings"); myActiveMode = myActiveMode == Mode::TimeMachine ? Mode::Off : Mode::TimeMachine; if(myActiveMode == Mode::TimeMachine) myOSystem.frameBuffer().showMessage("Time Machine enabled"); else myOSystem.frameBuffer().showMessage("Time Machine disabled"); myOSystem.settings().setValue(devSettings ? "dev.timemachine" : "plr.timemachine", myActiveMode == Mode::TimeMachine); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::addExtraState(const string& message) { if(myActiveMode == Mode::TimeMachine) { RewindManager& r = myOSystem.state().rewindManager(); return r.addState(message); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::rewindStates(uInt32 numStates) { RewindManager& r = myOSystem.state().rewindManager(); return r.rewindStates(numStates); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::unwindStates(uInt32 numStates) { RewindManager& r = myOSystem.state().rewindManager(); return r.unwindStates(numStates); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::windStates(uInt32 numStates, bool unwind) { RewindManager& r = myOSystem.state().rewindManager(); return r.windStates(numStates, unwind); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::update() { switch(myActiveMode) { case Mode::TimeMachine: myRewindManager->addState("Time Machine", true); break; #if 0 case Mode::MovieRecord: myOSystem.console().controller(Controller::Left).save(myMovieWriter); myOSystem.console().controller(Controller::Right).save(myMovieWriter); myOSystem.console().switches().save(myMovieWriter); break; case Mode::MoviePlayback: myOSystem.console().controller(Controller::Left).load(myMovieReader); myOSystem.console().controller(Controller::Right).load(myMovieReader); myOSystem.console().switches().load(myMovieReader); break; #endif default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::loadState(int slot) { if(myOSystem.hasConsole()) { if(slot < 0) slot = myCurrentSlot; ostringstream buf; buf << myOSystem.stateDir() << myOSystem.console().properties().get(Cartridge_Name) << ".st" << slot; // Make sure the file can be opened in read-only mode Serializer in(buf.str(), true); if(!in) { buf.str(""); buf << "Can't open/load from state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); return; } // First test if we have a valid header // If so, do a complete state load using the Console buf.str(""); try { if(in.getString() != STATE_HEADER) buf << "Incompatible state " << slot << " file"; else if(in.getString() != myOSystem.console().cartridge().name()) buf << "State " << slot << " file doesn't match current ROM"; else { if(myOSystem.console().load(in)) buf << "State " << slot << " loaded"; else buf << "Invalid data in state " << slot << " file"; } } catch(...) { buf << "Invalid data in state " << slot << " file"; } myOSystem.frameBuffer().showMessage(buf.str()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::saveState(int slot) { if(myOSystem.hasConsole()) { if(slot < 0) slot = myCurrentSlot; ostringstream buf; buf << myOSystem.stateDir() << myOSystem.console().properties().get(Cartridge_Name) << ".st" << slot; // Make sure the file can be opened for writing Serializer out(buf.str()); if(!out) { buf.str(""); buf << "Can't open/save to state file " << slot; myOSystem.frameBuffer().showMessage(buf.str()); return; } try { // Add header so that if the state format changes in the future, // we'll know right away, without having to parse the rest of the file out.putString(STATE_HEADER); // Sanity check; prepend the cart type/name out.putString(myOSystem.console().cartridge().name()); } catch(...) { buf << "Error saving state " << slot; myOSystem.frameBuffer().showMessage(buf.str()); return; } // Do a complete state save using the Console buf.str(""); if(myOSystem.console().save(out)) { buf << "State " << slot << " saved"; if(myOSystem.settings().getBool("autoslot")) { myCurrentSlot = (slot + 1) % 10; buf << ", switching to slot " << slot; } } else buf << "Error saving state " << slot; myOSystem.frameBuffer().showMessage(buf.str()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::changeState() { myCurrentSlot = (myCurrentSlot + 1) % 10; // Print appropriate message ostringstream buf; buf << "Changed to slot " << myCurrentSlot; myOSystem.frameBuffer().showMessage(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::loadState(Serializer& in) { try { if(myOSystem.hasConsole()) { // Make sure the file can be opened for reading if(in) { // First test if we have a valid header and cart type // If so, do a complete state load using the Console return in.getString() == STATE_HEADER && in.getString() == myOSystem.console().cartridge().name() && myOSystem.console().load(in); } } } catch(...) { cerr << "ERROR: StateManager::loadState(Serializer&)" << endl; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool StateManager::saveState(Serializer& out) { try { if(myOSystem.hasConsole()) { // Make sure the file can be opened for writing if(out) { // Add header so that if the state format changes in the future, // we'll know right away, without having to parse the rest of the file out.putString(STATE_HEADER); // Sanity check; prepend the cart type/name out.putString(myOSystem.console().cartridge().name()); // Do a complete state save using the Console if(myOSystem.console().save(out)) return true; } } } catch(...) { cerr << "ERROR: StateManager::saveState(Serializer&)" << endl; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StateManager::reset() { myRewindManager->clear(); myActiveMode = myOSystem.settings().getBool( myOSystem.settings().getBool("dev.settings") ? "dev.timemachine" : "plr.timemachine") ? Mode::TimeMachine : Mode::Off; #if 0 myCurrentSlot = 0; switch(myActiveMode) { case kMovieRecordMode: myMovieWriter.close(); break; case kMoviePlaybackMode: myMovieReader.close(); break; default: break; } myActiveMode = kOffMode; #endif } stella-5.1.1/src/common/StateManager.hxx000066400000000000000000000107621324334165500202010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef STATE_MANAGER_HXX #define STATE_MANAGER_HXX class OSystem; class RewindManager; #include "Serializer.hxx" /** This class provides an interface to all things related to emulation state. States can be loaded or saved here, as well as recorded, rewound, and later played back. @author Stephen Anthony */ class StateManager { public: enum class Mode { Off, TimeMachine, MovieRecord, MoviePlayback }; /** Create a new statemananger class. */ StateManager(OSystem& osystem); ~StateManager(); public: /** Answers whether the manager is in record or playback mode. */ Mode mode() const { return myActiveMode; } #if 0 /** Toggle movie recording mode (FIXME - currently disabled) */ void toggleRecordMode(); #endif /** Toggle state rewind recording mode; this uses the RewindManager for its functionality. */ void toggleTimeMachine(); /** Sets state rewind recording mode; this uses the RewindManager for its functionality. */ void setRewindMode(Mode mode) { myActiveMode = mode; } /** Optionally adds one extra state when entering the Time Machine dialog; this uses the RewindManager for its functionality. */ bool addExtraState(const string& message); /** Rewinds states; this uses the RewindManager for its functionality. */ bool rewindStates(uInt32 numStates = 1); /** Unwinds states; this uses the RewindManager for its functionality. */ bool unwindStates(uInt32 numStates = 1); /** Rewinds/unwinds states; this uses the RewindManager for its functionality. */ bool windStates(uInt32 numStates, bool unwind); /** Updates the state of the system based on the currently active mode. */ void update(); /** Load a state into the current system. @param slot The state 'slot' to load state from */ void loadState(int slot = -1); /** Save the current state from the system. @param slot The state 'slot' to save into */ void saveState(int slot = -1); /** Switches to the next higher state slot (circular queue style). */ void changeState(); /** Load a state into the current system from the given Serializer. No messages are printed to the screen. @param in The Serializer object to use @return False on any load errors, else true */ bool loadState(Serializer& in); /** Save the current state from the system into the given Serializer. No messages are printed to the screen. @param out The Serializer object to use @return False on any save errors, else true */ bool saveState(Serializer& out); /** Resets manager to defaults. */ void reset(); /** The rewind facility for the state manager */ RewindManager& rewindManager() const { return *myRewindManager; } private: enum { kVersion = 001 }; // The parent OSystem object OSystem& myOSystem; // The current slot for load/save states int myCurrentSlot; // Whether the manager is in record or playback mode Mode myActiveMode; // MD5 of the currently active ROM (either in movie or rewind mode) string myMD5; // Serializer classes used to save/load the eventstream Serializer myMovieWriter; Serializer myMovieReader; // Stored savestates to be later rewound unique_ptr myRewindManager; private: // Following constructors and assignment operators not supported StateManager() = delete; StateManager(const StateManager&) = delete; StateManager(StateManager&&) = delete; StateManager& operator=(const StateManager&) = delete; StateManager& operator=(StateManager&&) = delete; }; #endif stella-5.1.1/src/common/StellaKeys.hxx000066400000000000000000000325771324334165500177160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef STELLA_KEYS_HXX #define STELLA_KEYS_HXX #include "SDL_lib.hxx" /** This class implements a thin wrapper around the SDL keysym enumerations, such that SDL-specific code doesn't have to go into the internal parts of the codebase. The keycodes are exactly the same, but from the POV of the rest of the code, they are *KBD* (keyboard) keys, not *SDL* keys. If the codebase is ported to future SDL versions or to some other toolkit, the intent is to simply change this file without having to modify all other classes that use StellaKey. @author Stephen Anthony */ // This comes directly from SDL_scancode.h enum StellaKey { KBDK_UNKNOWN = 0, /** * \name Usage page 0x07 * * These values are from usage page 0x07 (USB keyboard page). */ /* @{ */ KBDK_A = 4, KBDK_B = 5, KBDK_C = 6, KBDK_D = 7, KBDK_E = 8, KBDK_F = 9, KBDK_G = 10, KBDK_H = 11, KBDK_I = 12, KBDK_J = 13, KBDK_K = 14, KBDK_L = 15, KBDK_M = 16, KBDK_N = 17, KBDK_O = 18, KBDK_P = 19, KBDK_Q = 20, KBDK_R = 21, KBDK_S = 22, KBDK_T = 23, KBDK_U = 24, KBDK_V = 25, KBDK_W = 26, KBDK_X = 27, KBDK_Y = 28, KBDK_Z = 29, KBDK_1 = 30, KBDK_2 = 31, KBDK_3 = 32, KBDK_4 = 33, KBDK_5 = 34, KBDK_6 = 35, KBDK_7 = 36, KBDK_8 = 37, KBDK_9 = 38, KBDK_0 = 39, KBDK_RETURN = 40, KBDK_ESCAPE = 41, KBDK_BACKSPACE = 42, KBDK_TAB = 43, KBDK_SPACE = 44, KBDK_MINUS = 45, KBDK_EQUALS = 46, KBDK_LEFTBRACKET = 47, KBDK_RIGHTBRACKET = 48, KBDK_BACKSLASH = 49, /**< Located at the lower left of the return * key on ISO keyboards and at the right end * of the QWERTY row on ANSI keyboards. * Produces REVERSE SOLIDUS (backslash) and * VERTICAL LINE in a US layout, REVERSE * SOLIDUS and VERTICAL LINE in a UK Mac * layout, NUMBER SIGN and TILDE in a UK * Windows layout, DOLLAR SIGN and POUND SIGN * in a Swiss German layout, NUMBER SIGN and * APOSTROPHE in a German layout, GRAVE * ACCENT and POUND SIGN in a French Mac * layout, and ASTERISK and MICRO SIGN in a * French Windows layout. */ KBDK_NONUSHASH = 50, /**< ISO USB keyboards actually use this code * instead of 49 for the same key, but all * OSes I've seen treat the two codes * identically. So, as an implementor, unless * your keyboard generates both of those * codes and your OS treats them differently, * you should generate KBDK_BACKSLASH * instead of this code. As a user, you * should not rely on this code because SDL * will never generate it with most (all?) * keyboards. */ KBDK_SEMICOLON = 51, KBDK_APOSTROPHE = 52, KBDK_GRAVE = 53, /**< Located in the top left corner (on both ANSI * and ISO keyboards). Produces GRAVE ACCENT and * TILDE in a US Windows layout and in US and UK * Mac layouts on ANSI keyboards, GRAVE ACCENT * and NOT SIGN in a UK Windows layout, SECTION * SIGN and PLUS-MINUS SIGN in US and UK Mac * layouts on ISO keyboards, SECTION SIGN and * DEGREE SIGN in a Swiss German layout (Mac: * only on ISO keyboards), CIRCUMFLEX ACCENT and * DEGREE SIGN in a German layout (Mac: only on * ISO keyboards), SUPERSCRIPT TWO and TILDE in a * French Windows layout, COMMERCIAL AT and * NUMBER SIGN in a French Mac layout on ISO * keyboards, and LESS-THAN SIGN and GREATER-THAN * SIGN in a Swiss German, German, or French Mac * layout on ANSI keyboards. */ KBDK_COMMA = 54, KBDK_PERIOD = 55, KBDK_SLASH = 56, KBDK_CAPSLOCK = 57, KBDK_F1 = 58, KBDK_F2 = 59, KBDK_F3 = 60, KBDK_F4 = 61, KBDK_F5 = 62, KBDK_F6 = 63, KBDK_F7 = 64, KBDK_F8 = 65, KBDK_F9 = 66, KBDK_F10 = 67, KBDK_F11 = 68, KBDK_F12 = 69, KBDK_PRINTSCREEN = 70, KBDK_SCROLLLOCK = 71, KBDK_PAUSE = 72, KBDK_INSERT = 73, /**< insert on PC, help on some Mac keyboards (but does send code 73, not 117) */ KBDK_HOME = 74, KBDK_PAGEUP = 75, KBDK_DELETE = 76, KBDK_END = 77, KBDK_PAGEDOWN = 78, KBDK_RIGHT = 79, KBDK_LEFT = 80, KBDK_DOWN = 81, KBDK_UP = 82, KBDK_NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards */ KBDK_KP_DIVIDE = 84, KBDK_KP_MULTIPLY = 85, KBDK_KP_MINUS = 86, KBDK_KP_PLUS = 87, KBDK_KP_ENTER = 88, KBDK_KP_1 = 89, KBDK_KP_2 = 90, KBDK_KP_3 = 91, KBDK_KP_4 = 92, KBDK_KP_5 = 93, KBDK_KP_6 = 94, KBDK_KP_7 = 95, KBDK_KP_8 = 96, KBDK_KP_9 = 97, KBDK_KP_0 = 98, KBDK_KP_PERIOD = 99, KBDK_NONUSBACKSLASH = 100, /**< This is the additional key that ISO * keyboards have over ANSI ones, * located between left shift and Y. * Produces GRAVE ACCENT and TILDE in a * US or UK Mac layout, REVERSE SOLIDUS * (backslash) and VERTICAL LINE in a * US or UK Windows layout, and * LESS-THAN SIGN and GREATER-THAN SIGN * in a Swiss German, German, or French * layout. */ KBDK_APPLICATION = 101, /**< windows contextual menu, compose */ KBDK_POWER = 102, /**< The USB document says this is a status flag, * not a physical key - but some Mac keyboards * do have a power key. */ KBDK_KP_EQUALS = 103, KBDK_F13 = 104, KBDK_F14 = 105, KBDK_F15 = 106, KBDK_F16 = 107, KBDK_F17 = 108, KBDK_F18 = 109, KBDK_F19 = 110, KBDK_F20 = 111, KBDK_F21 = 112, KBDK_F22 = 113, KBDK_F23 = 114, KBDK_F24 = 115, KBDK_EXECUTE = 116, KBDK_HELP = 117, KBDK_MENU = 118, KBDK_SELECT = 119, KBDK_STOP = 120, KBDK_AGAIN = 121, /**< redo */ KBDK_UNDO = 122, KBDK_CUT = 123, KBDK_COPY = 124, KBDK_PASTE = 125, KBDK_FIND = 126, KBDK_MUTE = 127, KBDK_VOLUMEUP = 128, KBDK_VOLUMEDOWN = 129, /* not sure whether there's a reason to enable these */ /* KBDK_LOCKINGCAPSLOCK = 130, */ /* KBDK_LOCKINGNUMLOCK = 131, */ /* KBDK_LOCKINGSCROLLLOCK = 132, */ KBDK_KP_COMMA = 133, KBDK_KP_EQUALSAS400 = 134, KBDK_INTERNATIONAL1 = 135, /**< used on Asian keyboards, see footnotes in USB doc */ KBDK_INTERNATIONAL2 = 136, KBDK_INTERNATIONAL3 = 137, /**< Yen */ KBDK_INTERNATIONAL4 = 138, KBDK_INTERNATIONAL5 = 139, KBDK_INTERNATIONAL6 = 140, KBDK_INTERNATIONAL7 = 141, KBDK_INTERNATIONAL8 = 142, KBDK_INTERNATIONAL9 = 143, KBDK_LANG1 = 144, /**< Hangul/English toggle */ KBDK_LANG2 = 145, /**< Hanja conversion */ KBDK_LANG3 = 146, /**< Katakana */ KBDK_LANG4 = 147, /**< Hiragana */ KBDK_LANG5 = 148, /**< Zenkaku/Hankaku */ KBDK_LANG6 = 149, /**< reserved */ KBDK_LANG7 = 150, /**< reserved */ KBDK_LANG8 = 151, /**< reserved */ KBDK_LANG9 = 152, /**< reserved */ KBDK_ALTERASE = 153, /**< Erase-Eaze */ KBDK_SYSREQ = 154, KBDK_CANCEL = 155, KBDK_CLEAR = 156, KBDK_PRIOR = 157, KBDK_RETURN2 = 158, KBDK_SEPARATOR = 159, KBDK_OUT = 160, KBDK_OPER = 161, KBDK_CLEARAGAIN = 162, KBDK_CRSEL = 163, KBDK_EXSEL = 164, KBDK_KP_00 = 176, KBDK_KP_000 = 177, KBDK_THOUSANDSSEPARATOR = 178, KBDK_DECIMALSEPARATOR = 179, KBDK_CURRENCYUNIT = 180, KBDK_CURRENCYSUBUNIT = 181, KBDK_KP_LEFTPAREN = 182, KBDK_KP_RIGHTPAREN = 183, KBDK_KP_LEFTBRACE = 184, KBDK_KP_RIGHTBRACE = 185, KBDK_KP_TAB = 186, KBDK_KP_BACKSPACE = 187, KBDK_KP_A = 188, KBDK_KP_B = 189, KBDK_KP_C = 190, KBDK_KP_D = 191, KBDK_KP_E = 192, KBDK_KP_F = 193, KBDK_KP_XOR = 194, KBDK_KP_POWER = 195, KBDK_KP_PERCENT = 196, KBDK_KP_LESS = 197, KBDK_KP_GREATER = 198, KBDK_KP_AMPERSAND = 199, KBDK_KP_DBLAMPERSAND = 200, KBDK_KP_VERTICALBAR = 201, KBDK_KP_DBLVERTICALBAR = 202, KBDK_KP_COLON = 203, KBDK_KP_HASH = 204, KBDK_KP_SPACE = 205, KBDK_KP_AT = 206, KBDK_KP_EXCLAM = 207, KBDK_KP_MEMSTORE = 208, KBDK_KP_MEMRECALL = 209, KBDK_KP_MEMCLEAR = 210, KBDK_KP_MEMADD = 211, KBDK_KP_MEMSUBTRACT = 212, KBDK_KP_MEMMULTIPLY = 213, KBDK_KP_MEMDIVIDE = 214, KBDK_KP_PLUSMINUS = 215, KBDK_KP_CLEAR = 216, KBDK_KP_CLEARENTRY = 217, KBDK_KP_BINARY = 218, KBDK_KP_OCTAL = 219, KBDK_KP_DECIMAL = 220, KBDK_KP_HEXADECIMAL = 221, KBDK_LCTRL = 224, KBDK_LSHIFT = 225, KBDK_LALT = 226, /**< alt, option */ KBDK_LGUI = 227, /**< windows, command (apple), meta */ KBDK_RCTRL = 228, KBDK_RSHIFT = 229, KBDK_RALT = 230, /**< alt gr, option */ KBDK_RGUI = 231, /**< windows, command (apple), meta */ KBDK_MODE = 257, /**< I'm not sure if this is really not covered * by any of the above, but since there's a * special KMOD_MODE for it I'm adding it here */ /* @} *//* Usage page 0x07 */ /** * \name Usage page 0x0C * * These values are mapped from usage page 0x0C (USB consumer page). */ /* @{ */ KBDK_AUDIONEXT = 258, KBDK_AUDIOPREV = 259, KBDK_AUDIOSTOP = 260, KBDK_AUDIOPLAY = 261, KBDK_AUDIOMUTE = 262, KBDK_MEDIASELECT = 263, KBDK_WWW = 264, KBDK_MAIL = 265, KBDK_CALCULATOR = 266, KBDK_COMPUTER = 267, KBDK_AC_SEARCH = 268, KBDK_AC_HOME = 269, KBDK_AC_BACK = 270, KBDK_AC_FORWARD = 271, KBDK_AC_STOP = 272, KBDK_AC_REFRESH = 273, KBDK_AC_BOOKMARKS = 274, /* @} *//* Usage page 0x0C */ /** * \name Walther keys * * These are values that Christian Walther added (for mac keyboard?). */ /* @{ */ KBDK_BRIGHTNESSDOWN = 275, KBDK_BRIGHTNESSUP = 276, KBDK_DISPLAYSWITCH = 277, /**< display mirroring/dual display switch, video mode switch */ KBDK_KBDILLUMTOGGLE = 278, KBDK_KBDILLUMDOWN = 279, KBDK_KBDILLUMUP = 280, KBDK_EJECT = 281, KBDK_SLEEP = 282, KBDK_APP1 = 283, KBDK_APP2 = 284, /* @} *//* Walther keys */ /* Add any other keys here. */ KBDK_LAST = 512 /**< not a key, just marks the number of scancodes for array bounds */ }; // This comes directly from SDL_keycode.h enum StellaMod { KBDM_NONE = 0x0000, KBDM_LSHIFT = 0x0001, KBDM_RSHIFT = 0x0002, KBDM_LCTRL = 0x0040, KBDM_RCTRL = 0x0080, KBDM_LALT = 0x0100, KBDM_RALT = 0x0200, KBDM_LGUI = 0x0400, KBDM_RGUI = 0x0800, KBDM_NUM = 0x1000, KBDM_CAPS = 0x2000, KBDM_MODE = 0x4000, KBDM_RESERVED = 0x8000, KBDM_CTRL = (KBDM_LCTRL|KBDM_RCTRL), KBDM_SHIFT = (KBDM_LSHIFT|KBDM_RSHIFT), KBDM_ALT = (KBDM_LALT|KBDM_RALT), KBDM_GUI = (KBDM_LGUI|KBDM_RGUI) }; // Test if specified modifier is pressed namespace StellaModTest { inline bool isAlt(int mod) { #if defined(BSPF_MAC_OSX) || defined(OSX_KEYS) return (mod & KBDM_GUI); #else return (mod & KBDM_ALT); #endif } inline bool isControl(int mod) { return (mod & KBDM_CTRL); } inline bool isShift(int mod) { return (mod & KBDM_SHIFT); } }; #endif /* StellaKeys */ stella-5.1.1/src/common/StringParser.hxx000066400000000000000000000050171324334165500202460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef STRING_PARSER_HXX #define STRING_PARSER_HXX #include "bspf.hxx" /** This class converts a string into a StringList by splitting on a delimiter and size. @author Stephen Anthony */ class StringParser { public: /** Split the given string based on the newline character. @param str The string to split */ StringParser(const string& str) { istringstream buf(str); string line; while(std::getline(buf, line, '\n')) myStringList.push_back(line); } /** Split the given string based on the newline character, making sure that no string is longer than maximum string length. @param str The string to split @param maxlen The maximum length of string to generate */ StringParser(const string& str, uInt32 maxlen) { istringstream buf(str); string line; while(std::getline(buf, line, '\n')) { size_t beg = 0, len = maxlen, size = line.size(); if(size <= len) myStringList.push_back(line); else { while((beg+maxlen) < size) { size_t spos = line.find_last_of(' ', beg+len); if(spos > beg) len = spos - beg; myStringList.push_back(line.substr(beg, len)); beg += len + 1; len = maxlen; } myStringList.push_back(line.substr(beg)); } } } const StringList& stringList() const { return myStringList; } private: StringList myStringList; private: // Following constructors and assignment operators not supported StringParser() = delete; StringParser(const StringParser&) = delete; StringParser(StringParser&&) = delete; StringParser& operator=(const StringParser&) = delete; StringParser& operator=(StringParser&&) = delete; }; #endif stella-5.1.1/src/common/Variant.hxx000066400000000000000000000062571324334165500172360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef VARIANT_HXX #define VARIANT_HXX #include "Rect.hxx" #include "bspf.hxx" /** This class implements a very simple variant type, which is convertible to several other types. It stores the actual data as a string, and converts to other types as required. Eventually, this class may be extended to use templates and become a more full-featured variant type. @author Stephen Anthony */ class Variant { private: // Underlying data store is (currently) always a string string data; // Use singleton so we use only one ostringstream object inline ostringstream& buf() { static ostringstream buf; return buf; } public: Variant() { } Variant(const string& s) : data(s) { } Variant(const char* s) : data(s) { } Variant(Int32 i) { buf().str(""); buf() << i; data = buf().str(); } Variant(uInt32 i) { buf().str(""); buf() << i; data = buf().str(); } Variant(float f) { buf().str(""); buf() << f; data = buf().str(); } Variant(double d) { buf().str(""); buf() << d; data = buf().str(); } Variant(bool b) { buf().str(""); buf() << b; data = buf().str(); } Variant(const GUI::Size& s) { buf().str(""); buf() << s; data = buf().str(); } // Conversion methods const string& toString() const { return data; } const char* const toCString() const { return data.c_str(); } const Int32 toInt() const { return atoi(data.c_str()); } const float toFloat() const { return float(atof(data.c_str())); } const bool toBool() const { return data == "1" || data == "true"; } const GUI::Size toSize() const { return GUI::Size(data); } // Comparison bool operator==(const Variant& v) const { return data == v.data; } bool operator!=(const Variant& v) const { return data != v.data; } friend ostream& operator<<(ostream& os, const Variant& v) { return os << v.data; } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static const Variant EmptyVariant; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - using VariantList = vector>; namespace VarList { inline void push_back(VariantList& list, const Variant& name, const Variant& tag = EmptyVariant) { list.emplace_back(name.toString(), tag); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static const VariantList EmptyVarList; #endif stella-5.1.1/src/common/Vec.hxx000066400000000000000000000022031324334165500163320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef VECTOR_OPS_HXX #define VECTOR_OPS_HXX #include "bspf.hxx" namespace Vec { template void append(vector& dst, const vector& src) { dst.insert(dst.cend(), src.cbegin(), src.cend()); } template void insertAt(vector& dst, uInt32 idx, const T& element) { dst.insert(dst.cbegin()+idx, element); } template void removeAt(vector& dst, uInt32 idx) { dst.erase(dst.cbegin()+idx); } } // Namespace Vec #endif stella-5.1.1/src/common/Version.hxx000066400000000000000000000014451324334165500172510ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef VERSION_HXX #define VERSION_HXX #define STELLA_VERSION "5.1.1" #define STELLA_BUILD "4144" #endif stella-5.1.1/src/common/ZipHandler.cxx000066400000000000000000000465431324334165500176670ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #include #include "ZipHandler.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ZipHandler::ZipHandler() : myZip(nullptr) { for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum) myZipCache[cachenum] = nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ZipHandler::~ZipHandler() { zip_file_cache_clear(); free_zip_file(myZip); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ZipHandler::open(const string& filename) { // Close already open file if(myZip) zip_file_close(myZip); // And open a new one zip_file_open(filename.c_str(), &myZip); reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ZipHandler::reset() { // Reset the position and go from there if(myZip) myZip->cd_pos = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ZipHandler::hasNext() { return myZip && (myZip->cd_pos < myZip->ecd.cd_size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string ZipHandler::next() { if(myZip) { bool valid = false; const zip_file_header* header = nullptr; do { header = zip_file_next_file(myZip); // Ignore zero-length files and '__MACOSX' virtual directories valid = header && (header->uncompressed_length > 0) && !BSPF::startsWithIgnoreCase(header->filename, "__MACOSX"); } while(!valid && myZip->cd_pos < myZip->ecd.cd_size); return valid ? header->filename : EmptyString; } else return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 ZipHandler::decompress(BytePtr& image) { static const char* const zip_error_s[] = { "ZIPERR_NONE", "ZIPERR_OUT_OF_MEMORY", "ZIPERR_FILE_ERROR", "ZIPERR_BAD_SIGNATURE", "ZIPERR_DECOMPRESS_ERROR", "ZIPERR_FILE_TRUNCATED", "ZIPERR_FILE_CORRUPT", "ZIPERR_UNSUPPORTED", "ZIPERR_BUFFER_TOO_SMALL" }; if(myZip) { uInt32 length = myZip->header.uncompressed_length; image = make_unique(length); ZipHandler::zip_error err = zip_file_decompress(myZip, image.get(), length); if(err == ZIPERR_NONE) return length; else throw runtime_error(zip_error_s[err]); } else throw runtime_error("Invalid ZIP archive"); } /*------------------------------------------------- replaces functionality of various osd_xxx file access functions -------------------------------------------------*/ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ZipHandler::stream_open(const char* filename, fstream** stream, uInt64& length) { fstream* in = new fstream(filename, fstream::in | fstream::binary); if(!in || !in->is_open()) { *stream = nullptr; length = 0; return false; } else { in->exceptions( std::ios_base::failbit | std::ios_base::badbit | std::ios_base::eofbit ); *stream = in; in->seekg(0, std::ios::end); length = in->tellg(); in->seekg(0, std::ios::beg); return true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ZipHandler::stream_close(fstream** stream) { if(*stream) { if((*stream)->is_open()) (*stream)->close(); delete *stream; *stream = nullptr; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ZipHandler::stream_read(fstream* stream, void* buffer, uInt64 offset, uInt32 length, uInt32& actual) { try { stream->seekg(offset); stream->read((char*)buffer, length); actual = (uInt32)stream->gcount(); return true; } catch(...) { return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /*------------------------------------------------- zip_file_open - opens a ZIP file for reading -------------------------------------------------*/ ZipHandler::zip_error ZipHandler::zip_file_open(const char* filename, zip_file** zip) { zip_error ziperr = ZIPERR_NONE; uInt32 read_length; zip_file* newzip; char* string; int cachenum; bool success; // Ensure we start with a NULL result *zip = nullptr; // See if we are in the cache, and reopen if so for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum) { zip_file* cached = myZipCache[cachenum]; // If we have a valid entry and it matches our filename, use it and remove // from the cache if(cached != nullptr && cached->filename != nullptr && strcmp(filename, cached->filename) == 0) { *zip = cached; myZipCache[cachenum] = nullptr; return ZIPERR_NONE; } } // Allocate memory for the zip_file structure newzip = (zip_file*)malloc(sizeof(*newzip)); if (newzip == nullptr) return ZIPERR_OUT_OF_MEMORY; memset(newzip, 0, sizeof(*newzip)); // Open the file if(!stream_open(filename, &newzip->file, newzip->length)) { ziperr = ZIPERR_FILE_ERROR; goto error; } // Read ecd data ziperr = read_ecd(newzip); if(ziperr != ZIPERR_NONE) goto error; // Verify that we can work with this zipfile (no disk spanning allowed) if (newzip->ecd.disk_number != newzip->ecd.cd_start_disk_number || newzip->ecd.cd_disk_entries != newzip->ecd.cd_total_entries) { ziperr = ZIPERR_UNSUPPORTED; goto error; } // Allocate memory for the central directory newzip->cd = (uInt8*)malloc(newzip->ecd.cd_size + 1); if(newzip->cd == nullptr) { ziperr = ZIPERR_OUT_OF_MEMORY; goto error; } // Read the central directory success = stream_read(newzip->file, newzip->cd, newzip->ecd.cd_start_disk_offset, newzip->ecd.cd_size, read_length); if(!success || read_length != newzip->ecd.cd_size) { ziperr = success ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR; goto error; } // Make a copy of the filename for caching purposes string = (char*)malloc(strlen(filename) + 1); if (string == nullptr) { ziperr = ZIPERR_OUT_OF_MEMORY; goto error; } strcpy(string, filename); newzip->filename = string; *zip = newzip; // Count ROM files (we do it at this level so it will be cached) while(hasNext()) { const std::string& file = next(); if(BSPF::endsWithIgnoreCase(file, ".a26") || BSPF::endsWithIgnoreCase(file, ".bin") || BSPF::endsWithIgnoreCase(file, ".rom")) (*zip)->romfiles++; } return ZIPERR_NONE; error: free_zip_file(newzip); return ziperr; } /*------------------------------------------------- zip_file_close - close a ZIP file and add it to the cache -------------------------------------------------*/ void ZipHandler::zip_file_close(zip_file* zip) { int cachenum; // Close the open files if(zip->file) stream_close(&zip->file); // Find the first NULL entry in the cache for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum) if(myZipCache[cachenum] == nullptr) break; // If no room left in the cache, free the bottommost entry if(cachenum == ZIP_CACHE_SIZE) free_zip_file(myZipCache[--cachenum]); // Move everyone else down and place us at the top if(cachenum != 0) memmove(&myZipCache[1], &myZipCache[0], cachenum * sizeof(myZipCache[0])); myZipCache[0] = zip; } /*------------------------------------------------- zip_file_cache_clear - clear the ZIP file cache and free all memory -------------------------------------------------*/ void ZipHandler::zip_file_cache_clear() { // Clear call cache entries for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum) { if(myZipCache[cachenum] != nullptr) { free_zip_file(myZipCache[cachenum]); myZipCache[cachenum] = nullptr; } } } /*************************************************************************** CONTAINED FILE ACCESS ***************************************************************************/ /*------------------------------------------------- zip_file_next_entry - return the next entry in the ZIP -------------------------------------------------*/ const ZipHandler::zip_file_header* ZipHandler::zip_file_next_file(zip_file* zip) { // Fix up any modified data if(zip->header.raw != nullptr) { zip->header.raw[ZIPCFN + zip->header.filename_length] = zip->header.saved; zip->header.raw = nullptr; } // If we're at or past the end, we're done if(zip->cd_pos >= zip->ecd.cd_size) return nullptr; // Extract file header info zip->header.raw = zip->cd + zip->cd_pos; zip->header.rawlength = ZIPCFN; zip->header.signature = read_dword(zip->header.raw + ZIPCENSIG); zip->header.version_created = read_word (zip->header.raw + ZIPCVER); zip->header.version_needed = read_word (zip->header.raw + ZIPCVXT); zip->header.bit_flag = read_word (zip->header.raw + ZIPCFLG); zip->header.compression = read_word (zip->header.raw + ZIPCMTHD); zip->header.file_time = read_word (zip->header.raw + ZIPCTIM); zip->header.file_date = read_word (zip->header.raw + ZIPCDAT); zip->header.crc = read_dword(zip->header.raw + ZIPCCRC); zip->header.compressed_length = read_dword(zip->header.raw + ZIPCSIZ); zip->header.uncompressed_length = read_dword(zip->header.raw + ZIPCUNC); zip->header.filename_length = read_word (zip->header.raw + ZIPCFNL); zip->header.extra_field_length = read_word (zip->header.raw + ZIPCXTL); zip->header.file_comment_length = read_word (zip->header.raw + ZIPCCML); zip->header.start_disk_number = read_word (zip->header.raw + ZIPDSK); zip->header.internal_attributes = read_word (zip->header.raw + ZIPINT); zip->header.external_attributes = read_dword(zip->header.raw + ZIPEXT); zip->header.local_header_offset = read_dword(zip->header.raw + ZIPOFST); zip->header.filename = (char*)zip->header.raw + ZIPCFN; // Make sure we have enough data zip->header.rawlength += zip->header.filename_length; zip->header.rawlength += zip->header.extra_field_length; zip->header.rawlength += zip->header.file_comment_length; if(zip->cd_pos + zip->header.rawlength > zip->ecd.cd_size) return nullptr; // NULL terminate the filename uInt32 size = ZIPCFN + zip->header.filename_length; zip->header.saved = zip->header.raw[size]; zip->header.raw[size] = 0; // Advance the position zip->cd_pos += zip->header.rawlength; return &zip->header; } /*------------------------------------------------- zip_file_decompress - decompress a file from a ZIP into the target buffer -------------------------------------------------*/ ZipHandler::zip_error ZipHandler::zip_file_decompress(zip_file* zip, void* buffer, uInt32 length) { zip_error ziperr; uInt64 offset; // If we don't have enough buffer, error if(length < zip->header.uncompressed_length) return ZIPERR_BUFFER_TOO_SMALL; // Make sure the info in the header aligns with what we know if(zip->header.start_disk_number != zip->ecd.disk_number) return ZIPERR_UNSUPPORTED; // Get the compressed data offset ziperr = get_compressed_data_offset(zip, offset); if(ziperr != ZIPERR_NONE) return ziperr; // Handle compression types switch(zip->header.compression) { case 0: ziperr = decompress_data_type_0(zip, offset, buffer, length); break; case 8: ziperr = decompress_data_type_8(zip, offset, buffer, length); break; default: ziperr = ZIPERR_UNSUPPORTED; break; } return ziperr; } /*************************************************************************** CACHE MANAGEMENT ***************************************************************************/ /*------------------------------------------------- free_zip_file - free all the data for a zip_file -------------------------------------------------*/ void ZipHandler::free_zip_file(zip_file* zip) { if(zip != nullptr) { if(zip->file) stream_close(&zip->file); if(zip->filename != nullptr) free((void*)zip->filename); if(zip->ecd.raw != nullptr) free(zip->ecd.raw); if(zip->cd != nullptr) free(zip->cd); free(zip); } } /*************************************************************************** ZIP FILE PARSING ***************************************************************************/ /*------------------------------------------------- read_ecd - read the ECD data -------------------------------------------------*/ ZipHandler::zip_error ZipHandler::read_ecd(zip_file* zip) { uInt32 buflen = 1024; uInt8* buffer; // We may need multiple tries while(buflen < 65536) { uInt32 read_length; Int32 offset; // Max out the buffer length at the size of the file if(buflen > zip->length) buflen = (uInt32)zip->length; // Allocate buffer buffer = (uInt8*)malloc(buflen + 1); if(buffer == nullptr) return ZIPERR_OUT_OF_MEMORY; // Read in one buffers' worth of data bool success = stream_read(zip->file, buffer, zip->length - buflen, buflen, read_length); if(!success || read_length != buflen) { free(buffer); return ZIPERR_FILE_ERROR; } // Find the ECD signature for(offset = buflen - 22; offset >= 0; offset--) if(buffer[offset + 0] == 'P' && buffer[offset + 1] == 'K' && buffer[offset + 2] == 0x05 && buffer[offset + 3] == 0x06) break; // If we found it, fill out the data if(offset >= 0) { // Reuse the buffer as our ECD buffer zip->ecd.raw = buffer; zip->ecd.rawlength = buflen - offset; // Append a NULL terminator to the comment memmove(&buffer[0], &buffer[offset], zip->ecd.rawlength); zip->ecd.raw[zip->ecd.rawlength] = 0; // Extract ecd info zip->ecd.signature = read_dword(zip->ecd.raw + ZIPESIG); zip->ecd.disk_number = read_word (zip->ecd.raw + ZIPEDSK); zip->ecd.cd_start_disk_number = read_word (zip->ecd.raw + ZIPECEN); zip->ecd.cd_disk_entries = read_word (zip->ecd.raw + ZIPENUM); zip->ecd.cd_total_entries = read_word (zip->ecd.raw + ZIPECENN); zip->ecd.cd_size = read_dword(zip->ecd.raw + ZIPECSZ); zip->ecd.cd_start_disk_offset = read_dword(zip->ecd.raw + ZIPEOFST); zip->ecd.comment_length = read_word (zip->ecd.raw + ZIPECOML); zip->ecd.comment = (const char *)(zip->ecd.raw + ZIPECOM); return ZIPERR_NONE; } // Didn't find it; free this buffer and expand our search free(buffer); if(buflen < zip->length) buflen *= 2; else return ZIPERR_BAD_SIGNATURE; } return ZIPERR_OUT_OF_MEMORY; } /*------------------------------------------------- get_compressed_data_offset - return the offset of the compressed data -------------------------------------------------*/ ZipHandler::zip_error ZipHandler::get_compressed_data_offset(zip_file* zip, uInt64& offset) { uInt32 read_length; // Make sure the file handle is open if(zip->file == nullptr && !stream_open(zip->filename, &zip->file, zip->length)) return ZIPERR_FILE_ERROR; // Now go read the fixed-sized part of the local file header bool success = stream_read(zip->file, zip->buffer, zip->header.local_header_offset, ZIPNAME, read_length); if(!success || read_length != ZIPNAME) return success ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR; // Compute the final offset offset = zip->header.local_header_offset + ZIPNAME; offset += read_word(zip->buffer + ZIPFNLN); offset += read_word(zip->buffer + ZIPXTRALN); return ZIPERR_NONE; } /*************************************************************************** DECOMPRESSION INTERFACES ***************************************************************************/ /*------------------------------------------------- decompress_data_type_0 - "decompress" type 0 data (which is uncompressed) -------------------------------------------------*/ ZipHandler::zip_error ZipHandler::decompress_data_type_0(zip_file* zip, uInt64 offset, void* buffer, uInt32 length) { uInt32 read_length; // The data is uncompressed; just read it bool success = stream_read(zip->file, buffer, offset, zip->header.compressed_length, read_length); if(!success) return ZIPERR_FILE_ERROR; else if(read_length != zip->header.compressed_length) return ZIPERR_FILE_TRUNCATED; else return ZIPERR_NONE; } /*------------------------------------------------- decompress_data_type_8 - decompress type 8 data (which is deflated) -------------------------------------------------*/ ZipHandler::zip_error ZipHandler::decompress_data_type_8(zip_file* zip, uInt64 offset, void* buffer, uInt32 length) { uInt32 input_remaining = zip->header.compressed_length; uInt32 read_length; z_stream stream; int zerr; #if 0 // TODO - check newer versions of ZIP, and determine why this specific // version (0x14) is important // Make sure we don't need a newer mechanism if (zip->header.version_needed > 0x14) return ZIPERR_UNSUPPORTED; #endif // Reset the stream memset(&stream, 0, sizeof(stream)); stream.next_out = (Bytef *)buffer; stream.avail_out = length; // Initialize the decompressor zerr = inflateInit2(&stream, -MAX_WBITS); if(zerr != Z_OK) return ZIPERR_DECOMPRESS_ERROR; // Loop until we're done for(;;) { // Read in the next chunk of data bool success = stream_read(zip->file, zip->buffer, offset, std::min(input_remaining, (uInt32)sizeof(zip->buffer)), read_length); if(!success) { inflateEnd(&stream); return ZIPERR_FILE_ERROR; } offset += read_length; // If we read nothing, but still have data left, the file is truncated if(read_length == 0 && input_remaining > 0) { inflateEnd(&stream); return ZIPERR_FILE_TRUNCATED; } // Fill out the input data stream.next_in = zip->buffer; stream.avail_in = read_length; input_remaining -= read_length; // Add a dummy byte at end of compressed data if(input_remaining == 0) stream.avail_in++; // Now inflate zerr = inflate(&stream, Z_NO_FLUSH); if(zerr == Z_STREAM_END) break; if(zerr != Z_OK) { inflateEnd(&stream); return ZIPERR_DECOMPRESS_ERROR; } } // Finish decompression zerr = inflateEnd(&stream); if(zerr != Z_OK) return ZIPERR_DECOMPRESS_ERROR; // If anything looks funny, report an error if(stream.avail_out > 0 || input_remaining > 0) return ZIPERR_DECOMPRESS_ERROR; return ZIPERR_NONE; } stella-5.1.1/src/common/ZipHandler.hxx000066400000000000000000000242011324334165500176570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ZIP_HANDLER_HXX #define ZIP_HANDLER_HXX #include "bspf.hxx" /*************************************************************************** Copyright Aaron Giles All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name 'MAME' nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ #define ZIP_DECOMPRESS_BUFSIZE 16384 /** This class implements a thin wrapper around the zip file management code from the MAME project. @author Wrapper class by Stephen Anthony, with main functionality by Aaron Giles */ class ZipHandler { public: ZipHandler(); ~ZipHandler(); // Open ZIP file for processing void open(const string& filename); // The following form an iterator for processing the filenames in the ZIP file void reset(); // Reset iterator to first file bool hasNext(); // Answer whether there are more files present string next(); // Get next file // Decompress the currently selected file and return its length // An exception will be thrown on any errors uInt32 decompress(BytePtr& image); // Answer the number of ROM files found in the archive // Currently, this means files with extension a26/bin/rom uInt16 romFiles() const { return myZip ? myZip->romfiles : 0; } private: // Replaces functionaity of various osd_xxxx functions static bool stream_open(const char* filename, fstream** stream, uInt64& length); static void stream_close(fstream** stream); static bool stream_read(fstream* stream, void* buffer, uInt64 offset, uInt32 length, uInt32& actual); /* Error types */ enum zip_error { ZIPERR_NONE = 0, ZIPERR_OUT_OF_MEMORY, ZIPERR_FILE_ERROR, ZIPERR_BAD_SIGNATURE, ZIPERR_DECOMPRESS_ERROR, ZIPERR_FILE_TRUNCATED, ZIPERR_FILE_CORRUPT, ZIPERR_UNSUPPORTED, ZIPERR_BUFFER_TOO_SMALL }; /* contains extracted file header information */ struct zip_file_header { uInt32 signature; /* central file header signature */ uInt16 version_created; /* version made by */ uInt16 version_needed; /* version needed to extract */ uInt16 bit_flag; /* general purpose bit flag */ uInt16 compression; /* compression method */ uInt16 file_time; /* last mod file time */ uInt16 file_date; /* last mod file date */ uInt32 crc; /* crc-32 */ uInt32 compressed_length; /* compressed size */ uInt32 uncompressed_length; /* uncompressed size */ uInt16 filename_length; /* filename length */ uInt16 extra_field_length; /* extra field length */ uInt16 file_comment_length; /* file comment length */ uInt16 start_disk_number; /* disk number start */ uInt16 internal_attributes; /* internal file attributes */ uInt32 external_attributes; /* external file attributes */ uInt32 local_header_offset; /* relative offset of local header */ const char* filename; /* filename */ uInt8* raw; /* pointer to the raw data */ uInt32 rawlength; /* length of the raw data */ uInt8 saved; /* saved byte from after filename */ }; /* contains extracted end of central directory information */ struct zip_ecd { uInt32 signature; /* end of central dir signature */ uInt16 disk_number; /* number of this disk */ uInt16 cd_start_disk_number; /* number of the disk with the start of the central directory */ uInt16 cd_disk_entries; /* total number of entries in the central directory on this disk */ uInt16 cd_total_entries; /* total number of entries in the central directory */ uInt32 cd_size; /* size of the central directory */ uInt32 cd_start_disk_offset; /* offset of start of central directory with respect to the starting disk number */ uInt16 comment_length; /* .ZIP file comment length */ const char* comment; /* .ZIP file comment */ uInt8* raw; /* pointer to the raw data */ uInt32 rawlength; /* length of the raw data */ }; /* describes an open ZIP file */ struct zip_file { const char* filename; /* copy of ZIP filename (for caching) */ fstream* file; /* C++ fstream file handle */ uInt64 length; /* length of zip file */ uInt16 romfiles; /* number of ROM files in central directory */ zip_ecd ecd; /* end of central directory */ uInt8* cd; /* central directory raw data */ uInt32 cd_pos; /* position in central directory */ zip_file_header header; /* current file header */ uInt8 buffer[ZIP_DECOMPRESS_BUFSIZE]; /* buffer for decompression */ }; enum { /* number of open files to cache */ ZIP_CACHE_SIZE = 8, /* offsets in end of central directory structure */ ZIPESIG = 0x00, ZIPEDSK = 0x04, ZIPECEN = 0x06, ZIPENUM = 0x08, ZIPECENN = 0x0a, ZIPECSZ = 0x0c, ZIPEOFST = 0x10, ZIPECOML = 0x14, ZIPECOM = 0x16, /* offsets in central directory entry structure */ ZIPCENSIG = 0x00, ZIPCVER = 0x04, ZIPCOS = 0x05, ZIPCVXT = 0x06, ZIPCEXOS = 0x07, ZIPCFLG = 0x08, ZIPCMTHD = 0x0a, ZIPCTIM = 0x0c, ZIPCDAT = 0x0e, ZIPCCRC = 0x10, ZIPCSIZ = 0x14, ZIPCUNC = 0x18, ZIPCFNL = 0x1c, ZIPCXTL = 0x1e, ZIPCCML = 0x20, ZIPDSK = 0x22, ZIPINT = 0x24, ZIPEXT = 0x26, ZIPOFST = 0x2a, ZIPCFN = 0x2e, /* offsets in local file header structure */ ZIPLOCSIG = 0x00, ZIPVER = 0x04, ZIPGENFLG = 0x06, ZIPMTHD = 0x08, ZIPTIME = 0x0a, ZIPDATE = 0x0c, ZIPCRC = 0x0e, ZIPSIZE = 0x12, ZIPUNCMP = 0x16, ZIPFNLN = 0x1a, ZIPXTRALN = 0x1c, ZIPNAME = 0x1e }; private: /* ----- ZIP file access ----- */ /* open a ZIP file and parse its central directory */ zip_error zip_file_open(const char* filename, zip_file** zip); /* close a ZIP file (may actually be left open due to caching) */ void zip_file_close(zip_file* zip); /* clear out all open ZIP files from the cache */ void zip_file_cache_clear(); /* ----- contained file access ----- */ /* find the next file in the ZIP */ const zip_file_header* zip_file_next_file(zip_file* zip); /* decompress the most recently found file in the ZIP */ zip_error zip_file_decompress(zip_file* zip, void* buffer, uInt32 length); inline static uInt16 read_word(uInt8* buf) { uInt16 p0 = uInt16(buf[0]), p1 = uInt16(buf[1]); return (p1 << 8) | p0; } inline static uInt32 read_dword(uInt8* buf) { return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; } /* cache management */ static void free_zip_file(zip_file* zip); /* ZIP file parsing */ static zip_error read_ecd(zip_file* zip); static zip_error get_compressed_data_offset(zip_file* zip, uInt64& offset); /* decompression interfaces */ static zip_error decompress_data_type_0(zip_file* zip, uInt64 offset, void* buffer, uInt32 length); static zip_error decompress_data_type_8(zip_file* zip, uInt64 offset, void* buffer, uInt32 length); private: zip_file* myZip; zip_file* myZipCache[ZIP_CACHE_SIZE]; private: // Following constructors and assignment operators not supported ZipHandler(const ZipHandler&) = delete; ZipHandler(ZipHandler&&) = delete; ZipHandler& operator=(const ZipHandler&) = delete; ZipHandler& operator=(ZipHandler&&) = delete; }; #endif /* ZIP_HANDLER_HXX */ stella-5.1.1/src/common/bspf.hxx000066400000000000000000000152471324334165500165630ustar00rootroot00000000000000//============================================================================ // // BBBBB SSSS PPPPP FFFFFF // BB BB SS SS PP PP FF // BB BB SS PP PP FF // BBBBB SSSS PPPPP FFFF -- "Brad's Simple Portability Framework" // BB BB SS PP FF // BB BB SS SS PP FF // BBBBB SSSS PP FF // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef BSPF_HXX #define BSPF_HXX /** This file defines various basic data types and preprocessor variables that need to be defined for different operating systems. @author Bradford W. Mott and Stephen Anthony */ #include // Types for 8/16/32/64-bit signed and unsigned integers using Int8 = int8_t; using uInt8 = uint8_t; using Int16 = int16_t; using uInt16 = uint16_t; using Int32 = int32_t; using uInt32 = uint32_t; using Int64 = int64_t; using uInt64 = uint64_t; // The following code should provide access to the standard C++ objects and // types: cout, cerr, string, ostream, istream, etc. #include #include #include #include #include #include #include #include #include #include #include #include using std::cin; using std::cout; using std::cerr; using std::endl; using std::string; using std::istream; using std::ostream; using std::fstream; using std::iostream; using std::ifstream; using std::ofstream; using std::ostringstream; using std::istringstream; using std::stringstream; using std::unique_ptr; using std::shared_ptr; using std::make_unique; using std::make_shared; using std::array; using std::vector; using std::runtime_error; using std::memcpy; // Common array types using IntArray = std::vector; using uIntArray = std::vector; using BoolArray = std::vector; using ByteArray = std::vector; using ShortArray = std::vector; using StringList = std::vector; using BytePtr = std::unique_ptr; static const string EmptyString(""); namespace BSPF { // Defines to help with path handling #if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX) static const string PATH_SEPARATOR = "/"; #define ATTRIBUTE_FMT_PRINTF __attribute__((__format__ (__printf__, 2, 0))) #elif defined(BSPF_WINDOWS) static const string PATH_SEPARATOR = "\\"; #pragma warning (disable : 4146) // unary minus operator applied to unsigned type #pragma warning(2:4264) // no override available for virtual member function from base 'class'; function is hidden #pragma warning(2:4265) // class has virtual functions, but destructor is not virtual #pragma warning(2:4266) // no override available for virtual member function from base 'type'; function is hidden #define ATTRIBUTE_FMT_PRINTF #else #error Update src/common/bspf.hxx for path separator #endif // CPU architecture type // This isn't complete yet, but takes care of all the major platforms #if defined(__i386__) || defined(_M_IX86) static const string ARCH = "i386"; #elif defined(__x86_64__) || defined(_WIN64) static const string ARCH = "x86_64"; #elif defined(__powerpc__) || defined(__ppc__) static const string ARCH = "ppc"; #else static const string ARCH = "NOARCH"; #endif // Combines 'max' and 'min', and clamps value to the upper/lower value // if it is outside the specified range template inline T clamp(T val, T lower, T upper) { return (val < lower) ? lower : (val > upper) ? upper : val; } template inline void clamp(T& val, T lower, T upper, T setVal) { if(val < lower || val > upper) val = setVal; } // Compare two strings, ignoring case inline int compareIgnoreCase(const string& s1, const string& s2) { #if defined BSPF_WINDOWS && !defined __GNUG__ return _stricmp(s1.c_str(), s2.c_str()); #else return strcasecmp(s1.c_str(), s2.c_str()); #endif } inline int compareIgnoreCase(const char* s1, const char* s2) { #if defined BSPF_WINDOWS && !defined __GNUG__ return _stricmp(s1, s2); #else return strcasecmp(s1, s2); #endif } // Test whether the first string starts with the second one (case insensitive) inline bool startsWithIgnoreCase(const string& s1, const string& s2) { #if defined BSPF_WINDOWS && !defined __GNUG__ return _strnicmp(s1.c_str(), s2.c_str(), s2.length()) == 0; #else return strncasecmp(s1.c_str(), s2.c_str(), s2.length()) == 0; #endif } inline bool startsWithIgnoreCase(const char* s1, const char* s2) { #if defined BSPF_WINDOWS && !defined __GNUG__ return _strnicmp(s1, s2, strlen(s2)) == 0; #else return strncasecmp(s1, s2, strlen(s2)) == 0; #endif } // Test whether two strings are equal (case insensitive) inline bool equalsIgnoreCase(const string& s1, const string& s2) { return compareIgnoreCase(s1, s2) == 0; } // Find location (if any) of the second string within the first, // starting from 'startpos' in the first string inline size_t findIgnoreCase(const string& s1, const string& s2, size_t startpos = 0) { auto pos = std::search(s1.cbegin()+startpos, s1.cend(), s2.cbegin(), s2.cend(), [](char ch1, char ch2) { return toupper(uInt8(ch1)) == toupper(uInt8(ch2)); }); return pos == s1.cend() ? string::npos : pos - (s1.cbegin()+startpos); } // Test whether the first string ends with the second one (case insensitive) inline bool endsWithIgnoreCase(const string& s1, const string& s2) { if(s1.length() >= s2.length()) { const char* end = s1.c_str() + s1.length() - s2.length(); return compareIgnoreCase(end, s2.c_str()) == 0; } return false; } // Test whether the first string contains the second one (case insensitive) inline bool containsIgnoreCase(const string& s1, const string& s2) { return findIgnoreCase(s1, s2) != string::npos; } // Test whether the first string matches the second one (case insensitive) // - the first character must match // - the following characters must appear in the order of the first string inline bool matches(const string& s1, const string& s2) { if(BSPF::startsWithIgnoreCase(s1, s2.substr(0, 1))) { size_t pos = 1; for(uInt32 j = 1; j < s2.size(); j++) { size_t found = BSPF::findIgnoreCase(s1, s2.substr(j, 1), pos); if(found == string::npos) return false; pos += found + 1; } return true; } return false; } } // namespace BSPF #endif stella-5.1.1/src/common/main.cxx000066400000000000000000000120721324334165500165410ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "MediaFactory.hxx" #include "Console.hxx" #include "Event.hxx" #include "EventHandler.hxx" #include "FrameBuffer.hxx" #include "PropsSet.hxx" #include "Sound.hxx" #include "Settings.hxx" #include "FSNode.hxx" #include "OSystem.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #if defined(BSPF_MAC_OSX) int stellaMain(int argc, char* argv[]) #else int main(int argc, char* argv[]) #endif { std::ios_base::sync_with_stdio(false); // Create the parent OSystem object unique_ptr theOSystem = MediaFactory::createOSystem(); theOSystem->loadConfig(); theOSystem->logMessage("Loading config options ...", 2); auto Cleanup = [&theOSystem]() { theOSystem->logMessage("Cleanup from main", 2); theOSystem->saveConfig(); return 0; }; // Take care of commandline arguments theOSystem->logMessage("Loading commandline arguments ...", 2); string romfile = theOSystem->settings().loadCommandLine(argc, argv); // Finally, make sure the settings are valid // We do it once here, so the rest of the program can assume valid settings theOSystem->logMessage("Validating config options ...", 2); theOSystem->settings().validate(); // Create the full OSystem after the settings, since settings are // probably needed for defaults theOSystem->logMessage("Creating the OSystem ...", 2); if(!theOSystem->create()) { theOSystem->logMessage("ERROR: Couldn't create OSystem", 0); return Cleanup(); } // Check to see if the user requested info about a specific ROM, // or the list of internal ROMs // If so, show the information and immediately exit if(theOSystem->settings().getBool("listrominfo")) { theOSystem->logMessage("Showing output from 'listrominfo' ...", 2); theOSystem->propSet().print(); return Cleanup(); } else if(theOSystem->settings().getBool("rominfo")) { theOSystem->logMessage("Showing output from 'rominfo' ...", 2); FilesystemNode romnode(romfile); theOSystem->logMessage(theOSystem->getROMInfo(romnode), 0); return Cleanup(); } else if(theOSystem->settings().getBool("help")) { theOSystem->logMessage("Displaying usage", 2); theOSystem->settings().usage(); return Cleanup(); } //// Main loop //// // First we check if a ROM is specified on the commandline. If so, and if // the ROM actually exists, use it to create a new console. // Next we check if a directory is specified on the commandline. If so, // open the rom launcher in that directory. // If not, use the built-in ROM launcher. In this case, we enter 'launcher' // mode and let the main event loop take care of opening a new console/ROM. FilesystemNode romnode(romfile); if(romfile == "" || romnode.isDirectory()) { theOSystem->logMessage("Attempting to use ROM launcher ...", 2); bool launcherOpened = romfile != "" ? theOSystem->createLauncher(romnode.getPath()) : theOSystem->createLauncher(); if(!launcherOpened) { theOSystem->logMessage("Launcher could not be started, showing usage", 2); theOSystem->settings().usage(); return Cleanup(); } } else { const string& result = theOSystem->createConsole(romnode); if(result != EmptyString) return Cleanup(); if(theOSystem->settings().getBool("takesnapshot")) { theOSystem->logMessage("Taking snapshots with 'takesnapshot' ...", 2); for(int i = 0; i < 30; ++i) theOSystem->frameBuffer().update(); theOSystem->eventHandler().takeSnapshot(); return Cleanup(); } #ifdef DEBUGGER_SUPPORT // Set up any breakpoint that was on the command line // (and remove the key from the settings, so they won't get set again) const string& initBreak = theOSystem->settings().getString("break"); if(initBreak != "") { Debugger& dbg = theOSystem->debugger(); int bp = dbg.stringToValue(initBreak); dbg.setBreakPoint(bp, true); theOSystem->settings().setValue("break", ""); } #endif } // Start the main loop, and don't exit until the user issues a QUIT command theOSystem->logMessage("Starting main loop ...", 2); theOSystem->mainLoop(); theOSystem->logMessage("Finished main loop ...", 2); // Cleanup time ... return Cleanup(); } stella-5.1.1/src/common/module.mk000066400000000000000000000007051324334165500167070ustar00rootroot00000000000000MODULE := src/common MODULE_OBJS := \ src/common/main.o \ src/common/Base.o \ src/common/EventHandlerSDL2.o \ src/common/FrameBufferSDL2.o \ src/common/FBSurfaceSDL2.o \ src/common/SoundSDL2.o \ src/common/FSNodeZIP.o \ src/common/PNGLibrary.o \ src/common/MouseControl.o \ src/common/RewindManager.o \ src/common/StateManager.o \ src/common/ZipHandler.o MODULE_DIRS += \ src/common # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/common/smartmod.hxx000066400000000000000000000041161324334165500174500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SMARTMOD_HXX #define SMARTMOD_HXX #include "bspf.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template uInt8 smartmod(uInt8 x) { return x % base; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> inline uInt8 smartmod<2>(uInt8 x) { return x & 0x01; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> inline uInt8 smartmod<4>(uInt8 x) { return x & 0x03; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> inline uInt8 smartmod<8>(uInt8 x) { return x & 0x07; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> inline uInt8 smartmod<16>(uInt8 x) { return x & 0x0F; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> inline uInt8 smartmod<32>(uInt8 x) { return x & 0x1F; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> inline uInt8 smartmod<64>(uInt8 x) { return x & 0x3F; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> inline uInt8 smartmod<128>(uInt8 x) { return x & 0x7F; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template<> inline uInt8 smartmod<256>(uInt8 x) { return x & 0xFF; } #endif // SMARTMOD_HXX stella-5.1.1/src/common/stella-128x128.png000066400000000000000000000441021324334165500200150ustar00rootroot00000000000000PNG  IHDR>aiCCPICC ProfilexTkA6n"Zkx"IYhE6bk Ed3In6&*Ezd/JZE(ޫ(b-nL~7}ov r4 Ril|Bj A4%UN$As{z[V{wwҶ@G*q Y<ߡ)t9Nyx+=Y"|@5-MS%@H8qR>׋infObN~N>! ?F?aĆ=5`5_M'Tq. VJp8dasZHOLn}&wVQygE0  HPEaP@<14r?#{2u$jtbDA{6=Q<("qCA*Oy\V;噹sM^|vWGyz?W15s-_̗)UKuZ17ߟl;=..s7VgjHUO^gc)1&v!.K `m)m$``/]?[xF QT*d4o(/lșmSqens}nk~8X<R5 vz)Ӗ9R,bRPCRR%eKUbvؙn9BħJeRR~NցoEx IDATxWיw* $L0jFi(QCً ^i^7{a>H ȍ:Ǫ UĀ$C?P)@ ·O~xxgʆmWa¯D,EA=#Ʉ=8>_-牅\+[TQlY"Vȑ}wtq9]h'F 6$<:D#ΦBfzZA}鯁ʳ6qIs$-"%7qgtyr~"HΟI~pe~wN j5&8/}m^hr693/ V{g*lw[{isc{6*T}pV7BPLk;a|I7[\% × '4ItvwyW?{a?]9}w|AZ. ;u)-Ihw޸8hq;9UOJjs3VagR?>Y-TN@'+DN7wy}oOhxO{uJKG'Kss2 婷fi,bbƩft*5R6 x4)5sͿK3uQ|lJsC/ȧ}Udҍrk#M$U;hx95~!m]ONJJa%m.W BBxl)8; a?~ngX/gRb4f!?J~r_\L;^$Jc3R)ef 8n/Sgu%ջTN@2׋|k`PH+njR$e@|U1Swum9]MgřZ]Jx@QKNA&E)VKŝgb',LJi}^joRE'* ݕRͥ ,n~JOڞȧS311Vn>Iw$M2LWDߖ .NiwSMnWt1P_FHONDXLv睒B__qu\]OKK HEeVB<(]ǥR_ ۗvS9^-h^YOdž d]+3TK~FT / iIR([qRb9UKeE+sDg lZf>snBjOx\^O@ @:O 7tDEjuo`*on#A倠ʼnFy/R Ks —<1UF}RE;7ċԜJ6D6u&-\^LicV䅽OvR6ﮥvLVq\lǯa nR&b7DDqhV6hk֝)4R#$ "yR&?kUTZZRAp"]{=WcJ9g*rDGY HVs?~fo  [o\j/&T5.zU˥{a0S4NڽnZYHAbn' c 467wӭۉôO8LUdgY:+^zԠ<^/ .5e[>M݋g@6;&NlSNDQ.tԩTzXݫPWq@XOw"5<?.;L pDJ UK-'NF F~Z?*6@ha]m 2ASKr^9JLM`;L.ӬtMy*W?O+~G߆dosAA$PjX(QϠ$j[a߼[k4~[L9&p*崶7cV pj|>X2VƋa{/[i5BqC>*_ClӍktѯ{ 12A#[rZ m %׫ҼZl<~`>t|/g^YyЍMʹb|[D!-RTY7Yu?4svk=-H׮7ɺ1C"?@"8?c~)ӠoVgϷQylos풢?MURqAZeޠ=HufN/+tvoĐ]meHm.c~z%$h6HLBE22ކ3z+$]"RJD,X8j VP,* ʿ+߽59{P4*ܺo_0MLi++C-.$"".:SJw"_z/, bWe kοUJ;܏exb#@g~a 9^ܽ|v9SMxm:LS HH< *l^c!riN8к 0wy~Zs$,[Dpw>9W_ZVە!|D=&QI`'@'|,;W?rf?[, f\J-yIEr>ck+wip"|ǯ1; vZ BPH'kH.b] x~RNw7;r HGD%"?3 ߖ zվ;߿Ԯ§όr6WwKUteֺ k2˘{PvSp;_'V$9r!H jw"|=dv׷kD5K<'nyoC?zD7 0occPNj@@oN.TD:d?1J3ugbLILD DRB`2r}!CyPN[`r+_%"QBB'ͷ'?;?;n脢"u:VS 2El9o&&L2?{DO!^` j@ƣwxhD(aH,QõrZ "^X$*I7%k>o_Lsz<ڽǷ a`CuHPX, F QxG= #W2 @DhϾ!#gUJ>^Y_/KCŸaԜ ?x9SzY|v*uw81YO(%D;f @sɴnZ1..C,fhxy.r7(ҍqncݻF1?ߕbnQ8woCy!qe4Hǃ {t}սCCAC723j^xjj,RL0_yu?E{x?8Bq8S}ݹJ U>P+ α|f:! GDnK+~#F9K{bh1^PW<'}ƅ:F[ݟ}aٲ!Rs&on'퇯_w!Q 9>C6u8VpCg ;`ɣqo3X ^)aO Q~7WF>cSӯ{s:7՜@ZU8WrV=.ί6Pkݰ'A U kmr8YXHotu̷1H&P 6%"^z O:z >&ƛncsztB\6A|6ܩ#2ng81WM{^pΩݹi$$)6X09zX7!#:$x6F[x՝r GD9^r}%!u~CF>|ߕ驉W}}y _d)%{-k esUk NUts1?hB,%b^2jX tS:?U1nĤ$}}Z~%fmT]Ox;U_""C7ۯ*<ps6ʼ9vrjEݐ ʡ,ˑhLمX%|{k8~C&7* LJȷp2,D>1͍r< _C$k/< _ة+ͷa_Lܸj R ^$1ӳ崿c"O7 9*y| xȒ5,t&H%U;% 4XDXIs1$=^NAϜĿ7{:%bU3&u{ȚEˑrp8LԴUYPԅ;(5Bw'zҠ{6XO<}"VrİCN(bSJݝJwj@P~}fޯS,,uh~-szWYu rl W_֥rMPf*:&S>0D~ I 009jkĥa g,Cum~Б ,WIa5f:=>s6$d͑ _'g|Z+W_g3E@]ŀg- TI8_%|M*18\*b4nsp,(SKX:I!@,$}|"-EkHr`_ Fq~Rza>'\"bxU<}K5b M.x}_X ّ1BL!S (!$#EăaUGƁN~5\-{oe\-m`=Tܯ=žK~q 2Çnz,]lһ{r8c}r]X8s(!^sA8_ d&9w_8*?n@]Qn1b-* ">C$^UA,ِ7W(7_#Q`RRV*/sS mx]^~ڑ7A;'@HgCt128L@K=n`lEsrm`Mz >*[ogqNBkZoZ)/C1' zߝW?kӽпYkA>8 2FA XGmӈ&M7nJy?ݰ+lYӠ, X 6,6;磱yK">v4FKی)ؓ [W "מO_> 6Ӌp IDAT\@+0Žw~E<^T@à9,]+܅A 3TGI!pG0 D&*B8@([:B,cf'־zFY v(kB5cޤY^?X0^5} &QᏦf>@"y[0}] xa#MGJ&OFkDbN!]:"K"$󳓵 GϵB.7YLhD?Cn}"O}:D@79JM   OB_JܯVn ܶpN(:!  0vhe>Nbvhj}&R S"IhRAtqH >X"UT9T``E\TϮvC`1 4|8>7ƽlLŹ^ ]p bųStmWW0N!6V)܅0=h0[ |E84Xomp_߾ģ8=CF-!GmNTpqHsyu !);ᖒ5E*&s^=E xS^<[yg׀sS@Ǯ`kl2#5*#FQ!ZsnÕf;{x`cN81*Ѫ}WcWcAY8[EҮpRH1,!\)d$,A" Q10cXDwXN֌&$}l!MUc;osw/x @ѯw2hD=@?3#fQϯ {Wulx 9_ 80[ gh;k"1t7a#5\"r\d!rȯG뗇ݼrGݣyrC[#٩D QJ_]߁{웎҉o00fQHHJm%&=.z%{BO?|_R\)˭ܡx\"( |&k:c& D* srpxt-ǩq>/0Գ+qbQqf`@ta(M8=ʈ*t_CoT\b +b0V^9{)-T3U}Yi"*Zq@yGTnP(Rwy$ 6 H*fKO8KvRܷ+ޝѢc ~x]P)lBq$Nx =Yݽ2ߨC`MH"KqQs  vAܔ7vxW #ߜ;$*;;>3Y<2"(e@@)!Oؼ{L_o^Fk~ JDzP 1Xḝ:m_VVl2iǥ~{U9'V%m8S(: ,<AǵCL)]H&1G/W+= ZIb~q0| "9WmdcOPRPř BYQ({ :=eB$UKMS @VxhuFܣX]9am͖W1_wF;q ֳebA7?1~3J] XxD ]\H|G{8~(K$UZhg8Z;>et@eJ1- Tuaf6c>'ߧf6'A^ ޶ņ ,{udаZbۧ>rn3(Ҍrև'G{&f50,8BA";M7HbNC gNDZ I,bݽ'h`['.@'TRJj[EQUqc^a:<.I:ROC7K HΫ=r$hY$)FV-p?X}֭GN廗j D]A+W`qhbP_|{_ҘG\`>EdL$ZHpxY>[i$w+%[<$-g&HGuD>Sy "I&cDA@!5c఼]|3į%Nr;2>3P!0'=dCj-v^k'/m𪊰^_YU @'DN B̝H*QxV:Bыi_D!G2Ao"8[R/)8"O }Ff|/"_``nYs=t$%XRF)a-K?a7l+}כZ-OO ̿K~4Q܌.v06|ˀɅi~xZc"I4?Y`g.b*fnA˭zqי> ?i2}'q,[֙GOikd]!K(ux?,h~рRaP@B'?7~&ˣ0%Н` xpR09sviv>&,]:Znk%eEX1N|3Nt|q;W'bD1'Qa{"?imQjFOhÜsޛC{=rٲU_" RiAhRGH#Zw8nnL OO9H 43ވ`F]tmt^ꏞ拾g3c֏43*a'uG$X?fY .#E` x̢fHUGg*q3$cB+d'νQڈts1\%RZ=;H:FMTYFAVyfI{{[1T4g,4ٯG f1K fq~7p2D$7~ :c4?ps^>a0xvϝBZt7H,v3+}lE-"KnDQGpZO㵉p: IL]n7^=Z [ΫhwnDqUWnz;[)fYU"Y<(0*%PG3$n (H`h+DF_׳.l62lvY*RwX];jlpH|IknE%z_h$h/nckz1<"@~<N0[!`0r:U!̩v "7/rV9{T&@">0` Mu`$c&ΰ мUl6kv^LrH{WJ6ƙ5]3OSk)4\ FE$r/7}vl >PH!8toD"?Tb}r(꽧l,$V]j3RqĊ9Z&lzҧ>R A|{8&f!!Ybݺ_F e @vG8!;d1Hd=s%N]R@ Cb!D~4cԎ(͒ ?x$L~5A-[}\+8` `.<0#!#WHR,4m lӞ^kUUFwx{=Sl1evUKoT9R?7$4&Eig r-\3+$/65B8ǎ̲,##\KFo|1AF\N2 'dp%L)![D6Tf$QËM+ӬjBgQ\.3H|5 lf UGZ^o,uI&a'#IO%<)ȍozby${`(Kc~X8VAD@.M k~ EAN:Zp~D2ۡenfA6=8u D[eLG(Gj}rmIe) L'M6І2h2g?~Q1(^iZћ!־C?zfh~;ʵ@\0/{(F6C7J! 6lC \hJ ?֙m@<T}҃X+u[,}xPaD chC) lp O<< ȍ4PHvȎ!jG2՛ޘ ^vqds‚E;x=\Mls P:=,̓~j&Q p(ئC~)tfP;(A8<9z8Jc&nd#Q1X+V۝] @[x*R~QBJ;Mw<}~Ï&6*?۸!{7:2n Er _ Q_'^%ʉ\26Dž2q~ U0=D`WbX;0,ltol6_-[}ZX=`fa&|  2=N ~NlclXF!$g? ;h )cU!þV#^_'.o5FCP8,Uu[g9 |UQ YG>, K#B stX9j{}U֟F]ˇ /_)A\,%7J~ychҴLAu ̨3 |5|juǘ~7'n.L?qgiT qrz˒ F$\]@aFW1UYdÒ~61%m1ZUTK:9;*6ArF{s?Y<`?dc'mY0乂6'|ɨJEf7+`;s؜3'#ױ?9_5Z%߉"G4U7r_?& 3_@?@'w[Z DwasTG ntv>+׉rj6 px7&&y腫VJ is'x>RH~PWVsl j@O.@߃D$ďon'QaA"!GlOVއlIYf.Ywwwsl RhQT>Et{ ~ AVqUc.*$8ԏpP"s}u"{'Dz&%@ 䐽ͽT#kًH#rdU9ҿpC?u`ںCh9S5cܛ:K/z2u];'TjUT vvP[X6Fv0#C HJ^ :Ҫl4pqh:TӁ)SxGoWGr @=r߂:jzXK3m6u=zBPcmftʼ+%/GPd"בaFF">K71PJ\"^sp{-]%5U) p,8r@xA{Xڮ MA`R*&*<g3 |H=]R !m6Ax^)vJ,lkO{e3H"K[~ū۬zsc5ܯw}i?hooUڇLw#M9oJ|.dYg=z@1z qp{m("%*UЌzJ*a߽JM~q="%#^ 9z#q1:ݾϺ߫@~s}h]5 ۛV4ÚHO2qW1@ *!B:P@rAJ vd֡*3{o{*|̙"Pΐ0Z7>;)yOL-.m6Z,=-wk''2<_/zO">{_M0Qb[^4}PR‘DbѶ<|SF8N;TF'1(n& pt"_#Y{90ުU'8#ySM,שCQ…yGB ( bHȳR B$eJduT\ $m=_i`3"DfVǑi^(gFk@IDAT&bnapo٪H뾀xձS e2Vqf@<|x6#"&ʃ8n8[€FA%D3!"oK1%zTL| ߫U?P n W[[ "@џA&>zY,4O&ND,J8!!; S0jsA.kCV7OL<;J}8Xdu=#[yB-'J,HwX>l WcF>_*z-2wO*X49.QnwݛppK$DUDĽah~<\q>/d=c0| <$smtRubr\W=$Ϗ."̜ d&49! DUvdeP1u3zp|?; ǭN%]_25W"]FEծ9RCf8!͗pkJvݙ~1`!K [@!#*HŌF)k]- @_'JNc?'mH'C@ҹf"ɜ}+9 1 r;ΡIyv} ,]ݾ Ĭ- <Tb ܯ]Uvk Mea*+Ek˜&3ɛ-pB `[>8"m,~_FZdO$C&%D8L'7^ A\oܯwuD$29#ea"^"0z;fvɕqw'L~ Ÿ0lj@1꠽w{Ewǹ_xl'o? 2DF(/|]}`O?_c,D)xr.AENU;cg%'jM aܞ@ʿFSIENDB`stella-5.1.1/src/common/stella-16x16.png000066400000000000000000000012311324334165500176410ustar00rootroot00000000000000PNG  IHDRasRGBbKGD pHYs  tIME /˛:IDAT8˝OHq?~͔ ,HP$jP $?.` :$%($ ik^R빼d:wġJ"_%Pݥ:;r]~j3cc@@;M*apDOӦ" }p9fXƒE!MankMm;UR '1-t| kہ@V9$mXd`g@_#\ ZOQOb $&qhB`{k֞v,sڷeN2LumdF3sHbqRY8 <,-zD@ t+%9[ J[:BiP)Ȥ\&LCm%m5]06p|AxUzGyB |e]'fiUGh G =x\Aܾ7hqjYG. 4liKG:I03tIENDB`stella-5.1.1/src/common/stella-22x22.png000066400000000000000000000020761324334165500176430ustar00rootroot00000000000000PNG  IHDRĴl;sRGBbKGD pHYs  tIME &DՋIDAT8˭KlUf(SZ hтG-R_ȣШh 7&nX15D$aF"ZS4RRtE!)"U~MO9C>GDu;|g`xa3pm5zU_g//:B<~q̀=qRɀlJjgd֕rj 3H66} V8]0x&S̄-&խ"H܏ƣh, uh ǺHOuyB,#.cCKEPP5iEiH1h6U NHHh&lO܁9KۏXR?9(I}i\w+qנ"Ӧ%C`4:GX]#8Q'iި,\HƠJw^L9{|Q.;Ҝ˪7AwIײEsj>XFEɔ~ d>e7/jǾcNXQX[L.F~p V;m^Em\**,ͱh 8ɘBIENDB`stella-5.1.1/src/common/stella-24x24.png000066400000000000000000000023021324334165500176370ustar00rootroot00000000000000PNG  IHDRw=sRGBbKGD pHYs  tIME  ^]BIDATHǵ[lTUuΙ3L[I)ŢۋB_HI1O$&D / b A77^t.g6 UwֿwJa"/tع:&{yo 対8ikVT$7^2o0c^~0iTYKh|k> ^~{E]lmzhH@@c8Nef "k76k&:brhΎ@ͼM8,_)&us?M1QD& عtkh$tc i,T,J 7 y&w3Ӟ PNP `uuQ/H&\iG\T ٍBr.d 4n{ѱ)$T ¶g F m@!o CH\_v g1>P t~xRxPV-?0͇NqzFP ,XY ܉Y0fP)@`1^.xY)t J?km(dsN3xkjqU2tθ91;Ef?Ʒw8ޟXkSiپl c\:NcA(t/5жOS@gS>U1Gr@?.Rîӭ]Ǯ yUo`X\[-kY8. "IENDB`stella-5.1.1/src/common/stella-32x32.png000066400000000000000000000033141324334165500176410ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME .#LIDATXŗ[l\W}.s\؞q.umH"q. hڴ\^BE(B*<B }H+-@ M|I'v81=eƞ9gp&Dn)e׿^_ O?yE2ZcfSY8= oǎt//NFzS:;N>GeVҙk|7>o)Rʈ17L$b;ήX$J Glѳ oF,^sgSBkC^nrhItx1Z̠Lp%*ZspPv -%T&CHͭP-(c'X/-ޯN*/hg T[U !,;?=u}̭`YZ"Xes;CJD ]Pc; Ⱥ-K_]V ,f t(؛c~`V?I:#`5hPdzAY#"vU97 F}R:b䦜N #v>ٱǦP s `t$meWpU`P;/}ر *j[5x̤ ׅ%4 t`L2k@%G8\71<щoO`S Aӂt?y@CY9  'gY4ڻ!k4 U*=7o([o}C%W'wwx ?w!WCAh9'Nm(]x9 "X㝨 <A$ 'Z!CυB*"0 W1z2YigB-.CV x쨀@0< @w2 Rry5 4+e[ 9 vTC. "O}r04 I(`hi>ېs}@@8J+WFd= Dx;^џ_ܢsu L0dt(JqveX57lEsSYej4$ɦ`Pp Ŭ=iG7^}WMXɴN00 D7',,@&RLDgSOC .ш DSnYYd;qs7I[wW``ui.xS讇|D!+0v7(R8 6#9G{JE:RGCͲ/d;*yxoLx'Q$WJYI\V6ʲ.Euqx]ݣ֣O>U';rv'f Mu]` w\*{F79KY`1v/^ <{p9 "O%fTQ)\6oe" N?9ebi~b"'+~.(Sd{f.]mw`4$^1>S*<w5ge܍DmlRA ~V[_Yt)^>hiǢAUaZ% >Oxw6QIIENDB`stella-5.1.1/src/common/stella-48x48.png000066400000000000000000000062651324334165500176670ustar00rootroot00000000000000PNG  IHDR00WsRGBbKGD pHYs  tIME )A[ 5IDATh՚[l\umpHEZEInl˶,;Eq8MP'"H6Z Hk-mQ(ڗ}оm$ipTeYR],R$m3Շ}Mi98pp܉B䀽@4&cM[]Kݡĵ_7YFuGZ3Ֆճfr|`7SWƦ ]Ƚ}=osSww\G =<{ǻrqpp uzVz tk'Ӄㄮ ey>[x4ԝ3;vD^NF^i"45\!rӜ;WJ^=~ £{9Dlャ&siq"q]¡"$ҏYuP+sSDJ>wp4PM< wr(2F P/qP_>RuOμ'b%廀מ0L[]mg`XP.hJV(## ptkV”߹o[/:Q n.R%%18b5$x.,V֫#02OשOGņ*k#sYE\^g;#7*Mxf @c[tZgzr|әΌT7R`bHw1?An)V]ޭ (y)GJ,?u Wv(hcݧRjMZ{y%J$QQ?1g-0G_:IŲ>_UJzB.nk+,.L+XA17JSOԡ~AcjcH*VmhZ:NJ8!3ɦrR迧Yo\Y4oӕ29e &*'tX_PXIOG #yeZBmk%2?|_z" P JCK' dChFvWN߷ z:'I s__zqBUr-H0xڦX K'1{?CR\7[*TI}ӟq|!K0<O?l9hh4a~:< T8b?@-).$k )SkfэC<<24"섋WR%ȦQ= pc)X$*m-`Q)kn׮9S'>#Zik^d2_I8yI 6Ā+Pڌ j)yKHY٩]ocz6C ԛW@a5ʞ|>Xq!##+7uA vߓmUuɣ_dSfǾ=d%8J n\Uȵ$,,^o \P.4nA \ƶ @k'7L+Dтlb^|rlZx.͎$\7!ZW2bzC1f@v45Qk% t>; 1$8ϾWk#ki@neL4Lm8ou+`db]ҀI2 N q1|$lfs9]:B8N%NllW1CmT R}a;[ ,X¡͆L3|6MlJsc(Y.%WA,뷪ĎF/gԍ0 `utC,< Larc JUIՇv8Iъ?P^/tXl(z0mB92A8q:+EYK8k )7)Q*AWlh6cR @r,?[redVI@:cy0Q.ۘ9ڦ8D dİ7H\]h{hvF.4j=*He[] C6@*K05l&w`톾n ~3ځJ A.,v`ȳ>0BU\uy{\п[p5^E]#14ʹQWg>uL4"b1([QCBO_X[4E`TcDq3C kܙ뒿6}O de'CiE0L'0'07yd6 (QHW&+M瑕L% ۹ZO>,YU "!^k^\C$~A J@v>KV=l>$YZNDZ338#>ГW68.A]rX.tnoto9"`SKEMk$ƞI\I՚f42|/?*]j=92ڎH^3|/|l:Y]H9{$ 3Mդ`+鵊T#F g`@>.>~l%kM(xޓj!IENDB`stella-5.1.1/src/common/stella-64x64.png000066400000000000000000000115011324334165500176500ustar00rootroot00000000000000PNG  IHDR@@iqsRGBbKGD pHYs  tIME -98jIDATxil\ump$,˲eٖlqb;8Ӹim6nZ$h6H(PE$- 4]>uA?K-!)NM$J")qwp83y{1imYvP3C;?9W{tޫVS*P(s] Jqw}ɧ=OACVED~a9TY.ipepOskZ9w*}kI6 DuTù<םmG5}eBP_Xgi:2y&ZXY37q".ojdoӞY0=<ʕQ|ǁ{^ o>PrOMX"2o1;1M|' 18q)ZG[Wx5Fcwn58$BO%A: nf DN7kLSs=2hOR[#!ZM¥! F8 ZRw C@nUϹvO_ӢtжGo2FF&~,I48N<9Fbm - VDw~_8@S'jyo(oh("3dYZ% qm2r~ pޏޞ֯~ܪ=: W$&zf@:897f 8VKpQ4?Jms?ܗ}D'0~IAjSY`eZґz|6Xq:l{#Ɩ40 Vfwgo~%V@8Jzf'OcUT2Rpvfa"uGԷMi> ^P:=P?Z =x TpnR/y#R|xYxVy䮃[μ٭\$`^06iB7yX)b&:Z[_*jPql_uc94 #w8qQaљr -n޷E&2F6kS?TC=7ojۧ 0|kzi* i!/ A!0j_{q#i1h%ͤE-Wͨqb+ 0tͦ\Vx>Ȥ2`U'7XPϘDv HAj=:0m[:n;|azef5xf {aNsjhktH A[j1.HJ'C;׎w 4jUș)"  -pnyW@doBZɄgX݀xa'Q-=#mp9%00a‚mK[! O'Lۊ?efJNRZs7v+ϔZ 52 05gog;x0"=L6᡻MCCK+.`Ս.εz \znh 3ݫ7v %NnjVajn(CZ&)! A:\RPPilu EVvigێe B3Cl ^.~=5\:!c\UV٤HsRm!]B" ÓP[^CF9@f6mb~ד |"Kvڨ݃E7`+"4R4xvZmc.-7JM*ˉaĢݔk^XuoJ=ׁe탍 Ȅs\՘7+gwÍ>{ϏWJ/9n–"mO \ "iZ T+V̄L0>gKg}0 s]@ϵ4iawrbUTJIWO ;tTw^J@ #L#hk7Ŷʄ5~RY+eN^l0\1A24cijN~fL 8ښTz:nѽZKӎcGH&ʱeRÎax 8yQ~ۉa@6a"#ج{p@.ڙīڂb4}/=H7_{Lez`d̢B`+246k¥\.8m򍰆km@h a 2 j";ca;d6~z(]"ne]K+ׅ/xI?=>c L(c ",a@Zl4ZFT>\7)\SRyVE;,T7apɡB9kR"+1 6k04.V=K`oЦ+Zά;7Cڊ#{u`~QOؑ/7QKtlNoĞXB9Z_|= `e馭kԈwdZP k4?yԕ+GrĄ6ȅ*lFk28Yr'KzaB5 gFE*y>nrrT7..dO}Clhbe8& Q\QP,U[ )^^=V5MqR ZjRI;/+J-<}%}ߙĖK *vA9 b́_,ԢJ0J^Xį{%Y*? wy~ ƦAfU*.kw{$j njӣVO{Wo4ga}޽HTht`+Ikw ]HZ4Bn ,7b7~:ܙwREeFmv챙R\W2[p5 DluC:U[ 0ӗߜr-iBh9n,T;',ӆwHo - ekORKmή1t9#Nƴ;;ԂrmdJ}y6g 7kI s*^Z*`oZH \ /Lik*Rla2A"q]OZjq5}ʪ3V~`gi-LNP]i18fb+z?mVK2^ӡWb?.}sv>+_U{1M;IENDB`stella-5.1.1/src/common/stella.png000066400000000000000000000004341324334165500170620ustar00rootroot00000000000000PNG  IHDR #ꦷbKGD X pHYsHHFk>IDATh EL-!b֔++8;C}'z +33| @6(@v٠ dsg/C8/6ODT8uCxy^#tG;no9"8gKOX3 ;Z)΀^{sGyrGIENDB`stella-5.1.1/src/common/stella_icon.hxx000066400000000000000000000303411324334165500201150ustar00rootroot00000000000000static uInt32 stella_icon[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; stella-5.1.1/src/common/tv_filters/000077500000000000000000000000001324334165500172505ustar00rootroot00000000000000stella-5.1.1/src/common/tv_filters/AtariNTSC.cxx000066400000000000000000000443641324334165500215370ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "AtariNTSC.hxx" // blitter related #ifndef restrict #if defined (__GNUC__) #define restrict __restrict__ #elif defined (_MSC_VER) && _MSC_VER > 1300 #define restrict __restrict #else /* no support for restricted pointers */ #define restrict #endif #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::initialize(const Setup& setup, const uInt8* palette) { init(myImpl, setup); initializePalette(palette); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::initializePalette(const uInt8* palette) { // Palette stores R/G/B data for 'palette_size' entries for ( uInt32 entry = 0; entry < palette_size; ++entry ) { float r = myImpl.to_float [*palette++]; float g = myImpl.to_float [*palette++]; float b = myImpl.to_float [*palette++]; float y, i, q = RGB_TO_YIQ( r, g, b, y, i ); // Generate kernel int ir, ig, ib = YIQ_TO_RGB( y, i, q, myImpl.to_rgb, int, ir, ig ); uInt32 rgb = PACK_RGB( ir, ig, ib ); uInt32* kernel = myColorTable[entry]; genKernel(myImpl, y, i, q, kernel); for ( uInt32 c = 0; c < rgb_kernel_size / 2; ++c ) { uInt32 error = rgb - kernel [c ] - kernel [(c+10)%14+14] - kernel [c + 7] - kernel [c + 3 +14]; kernel [c + 3 + 14] += error; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::enableThreading(bool enable) { uInt32 systemThreads = enable ? std::thread::hardware_concurrency() : 0; if(systemThreads <= 1) { myWorkerThreads = 0; myTotalThreads = 1; } else { systemThreads = std::min(4u, systemThreads); myWorkerThreads = systemThreads - 1; myTotalThreads = systemThreads; myThreads = make_unique(myWorkerThreads); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::render(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height, void* rgb_out, const uInt32 out_pitch, uInt32* rgb_in) { // Spawn the threads... for(uInt32 i = 0; i < myWorkerThreads; ++i) { myThreads[i] = std::thread([=] { rgb_in == nullptr ? renderThread(atari_in, in_width, in_height, myTotalThreads, i+1, rgb_out, out_pitch) : renderWithPhosphorThread(atari_in, in_width, in_height, myTotalThreads, i+1, rgb_in, rgb_out, out_pitch); }); } // Make the main thread busy too rgb_in == nullptr ? renderThread(atari_in, in_width, in_height, myTotalThreads, 0, rgb_out, out_pitch) : renderWithPhosphorThread(atari_in, in_width, in_height, myTotalThreads, 0, rgb_in, rgb_out, out_pitch); // ...and make them join again for(uInt32 i = 0; i < myWorkerThreads; ++i) myThreads[i].join(); // Copy phosphor values into out buffer if(rgb_in != nullptr) memcpy(rgb_out, rgb_in, in_height * out_pitch); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::renderThread(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, void* rgb_out, const uInt32 out_pitch) { // Adapt parameters to thread number const uInt32 yStart = in_height * threadNum / numThreads; const uInt32 yEnd = in_height * (threadNum + 1) / numThreads; atari_in += in_width * yStart; rgb_out = static_cast(rgb_out) + out_pitch * yStart; uInt32 const chunk_count = (in_width - 1) / PIXEL_in_chunk; for(uInt32 y = yStart; y < yEnd; ++y) { const uInt8* line_in = atari_in; ATARI_NTSC_BEGIN_ROW(NTSC_black, line_in[0]); uInt32* restrict line_out = static_cast(rgb_out); ++line_in; for(uInt32 n = chunk_count; n; --n) { // order of input and output pixels must not be altered ATARI_NTSC_COLOR_IN(0, line_in[0]); ATARI_NTSC_RGB_OUT_8888(0, line_out[0]); ATARI_NTSC_RGB_OUT_8888(1, line_out[1]); ATARI_NTSC_RGB_OUT_8888(2, line_out[2]); ATARI_NTSC_RGB_OUT_8888(3, line_out[3]); ATARI_NTSC_COLOR_IN(1, line_in[1]); ATARI_NTSC_RGB_OUT_8888(4, line_out[4]); ATARI_NTSC_RGB_OUT_8888(5, line_out[5]); ATARI_NTSC_RGB_OUT_8888(6, line_out[6]); line_in += 2; line_out += 7; } // finish final pixels ATARI_NTSC_COLOR_IN(0, line_in[0]); ATARI_NTSC_RGB_OUT_8888(0, line_out[0]); ATARI_NTSC_RGB_OUT_8888(1, line_out[1]); ATARI_NTSC_RGB_OUT_8888(2, line_out[2]); ATARI_NTSC_RGB_OUT_8888(3, line_out[3]); ATARI_NTSC_COLOR_IN(1, NTSC_black); ATARI_NTSC_RGB_OUT_8888(4, line_out[4]); ATARI_NTSC_RGB_OUT_8888(5, line_out[5]); ATARI_NTSC_RGB_OUT_8888(6, line_out[6]); line_in += 2; line_out += 7; ATARI_NTSC_COLOR_IN(0, NTSC_black); ATARI_NTSC_RGB_OUT_8888(0, line_out[0]); ATARI_NTSC_RGB_OUT_8888(1, line_out[1]); ATARI_NTSC_RGB_OUT_8888(2, line_out[2]); ATARI_NTSC_RGB_OUT_8888(3, line_out[3]); ATARI_NTSC_COLOR_IN(1, NTSC_black); ATARI_NTSC_RGB_OUT_8888(4, line_out[4]); #if 0 ATARI_NTSC_RGB_OUT_8888(5, line_out[5]); ATARI_NTSC_RGB_OUT_8888(6, line_out[6]); #endif atari_in += in_width; rgb_out = static_cast(rgb_out) + out_pitch; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, uInt32* rgb_in, void* rgb_out, const uInt32 out_pitch) { // Adapt parameters to thread number const uInt32 yStart = in_height * threadNum / numThreads; const uInt32 yEnd = in_height * (threadNum + 1) / numThreads; uInt32 bufofs = AtariNTSC::outWidth(in_width) * yStart; uInt32* out = static_cast(rgb_out); atari_in += in_width * yStart; rgb_out = static_cast(rgb_out) + out_pitch * yStart; uInt32 const chunk_count = (in_width - 1) / PIXEL_in_chunk; for(uInt32 y = yStart; y < yEnd; ++y) { const uInt8* line_in = atari_in; ATARI_NTSC_BEGIN_ROW(NTSC_black, line_in[0]); uInt32* restrict line_out = static_cast(rgb_out); ++line_in; for(uInt32 n = chunk_count; n; --n) { // order of input and output pixels must not be altered ATARI_NTSC_COLOR_IN(0, line_in[0]); ATARI_NTSC_RGB_OUT_8888(0, line_out[0]); ATARI_NTSC_RGB_OUT_8888(1, line_out[1]); ATARI_NTSC_RGB_OUT_8888(2, line_out[2]); ATARI_NTSC_RGB_OUT_8888(3, line_out[3]); ATARI_NTSC_COLOR_IN(1, line_in[1]); ATARI_NTSC_RGB_OUT_8888(4, line_out[4]); ATARI_NTSC_RGB_OUT_8888(5, line_out[5]); ATARI_NTSC_RGB_OUT_8888(6, line_out[6]); line_in += 2; line_out += 7; } // finish final pixels ATARI_NTSC_COLOR_IN(0, line_in[0]); ATARI_NTSC_RGB_OUT_8888(0, line_out[0]); ATARI_NTSC_RGB_OUT_8888(1, line_out[1]); ATARI_NTSC_RGB_OUT_8888(2, line_out[2]); ATARI_NTSC_RGB_OUT_8888(3, line_out[3]); ATARI_NTSC_COLOR_IN(1, NTSC_black); ATARI_NTSC_RGB_OUT_8888(4, line_out[4]); ATARI_NTSC_RGB_OUT_8888(5, line_out[5]); ATARI_NTSC_RGB_OUT_8888(6, line_out[6]); line_in += 2; line_out += 7; ATARI_NTSC_COLOR_IN(0, NTSC_black); ATARI_NTSC_RGB_OUT_8888(0, line_out[0]); ATARI_NTSC_RGB_OUT_8888(1, line_out[1]); ATARI_NTSC_RGB_OUT_8888(2, line_out[2]); ATARI_NTSC_RGB_OUT_8888(3, line_out[3]); ATARI_NTSC_COLOR_IN(1, NTSC_black); ATARI_NTSC_RGB_OUT_8888(4, line_out[4]); #if 0 ATARI_NTSC_RGB_OUT_8888(5, line_out[5]); ATARI_NTSC_RGB_OUT_8888(6, line_out[6]); #endif // Do phosphor mode (blend the resulting frames) // Note: The code assumes that AtariNTSC::outWidth(kTIAW) == outPitch == 565 for (uInt32 x = AtariNTSC::outWidth(in_width) / 8; x; --x) { // Store back into displayed frame buffer (for next frame) rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; } // finish final pixels rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; #if 0 rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; rgb_in[bufofs] = getRGBPhosphor(out[bufofs], rgb_in[bufofs]); bufofs++; #endif atari_in += in_width; rgb_out = static_cast(rgb_out) + out_pitch; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline uInt32 AtariNTSC::getRGBPhosphor(const uInt32 c, const uInt32 p) const { #define TO_RGB(color, red, green, blue) \ const uInt8 red = color >> 16; const uInt8 green = color >> 8; const uInt8 blue = color; TO_RGB(c, rc, gc, bc); TO_RGB(p, rp, gp, bp); // Mix current calculated frame with previous displayed frame const uInt8 rn = myPhosphorPalette[rc][rp]; const uInt8 gn = myPhosphorPalette[gc][gp]; const uInt8 bn = myPhosphorPalette[bc][bp]; return (rn << 16) | (gn << 8) | bn; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::init(init_t& impl, const Setup& setup) { impl.brightness = float(setup.brightness) * (0.5f * rgb_unit) + rgb_offset; impl.contrast = float(setup.contrast) * (0.5f * rgb_unit) + rgb_unit; impl.artifacts = float(setup.artifacts); if ( impl.artifacts > 0 ) impl.artifacts *= artifacts_max - artifacts_mid; impl.artifacts = impl.artifacts * artifacts_mid + artifacts_mid; impl.fringing = float(setup.fringing); if ( impl.fringing > 0 ) impl.fringing *= fringing_max - fringing_mid; impl.fringing = impl.fringing * fringing_mid + fringing_mid; initFilters(impl, setup); /* generate gamma table */ if ( gamma_size > 1 ) { float const to_float = 1.0f / (gamma_size - (gamma_size > 1)); float const gamma = 1.1333f - float(setup.gamma) * 0.5f; /* match common PC's 2.2 gamma to TV's 2.65 gamma */ int i; for ( i = 0; i < gamma_size; i++ ) impl.to_float [i] = float(pow( i * to_float, gamma )) * impl.contrast + impl.brightness; } /* setup decoder matricies */ { float hue = float(setup.hue) * PI + PI / 180 * ext_decoder_hue; float sat = float(setup.saturation) + 1; hue += PI / 180 * (std_decoder_hue - ext_decoder_hue); float s = float(sin( hue )) * sat; float c = float(cos( hue )) * sat; float* out = impl.to_rgb; int n; n = burst_count; do { float const* in = default_decoder; int n2 = 3; do { float i = *in++; float q = *in++; *out++ = i * c - q * s; *out++ = i * s + q * c; } while ( --n2 ); if ( burst_count <= 1 ) break; ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */ } while ( --n ); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariNTSC::initFilters(init_t& impl, const Setup& setup) { float kernels [kernel_size * 2]; /* generate luma (y) filter using sinc kernel */ { /* sinc with rolloff (dsf) */ float const rolloff = 1 + float(setup.sharpness) * 0.032; float const maxh = 32; float const pow_a_n = float(pow( rolloff, maxh )); float sum; int i; /* quadratic mapping to reduce negative (blurring) range */ float to_angle = float(setup.resolution) + 1; to_angle = PI / maxh * float(LUMA_CUTOFF) * (to_angle * to_angle + 1); kernels [kernel_size * 3 / 2] = maxh; /* default center value */ for ( i = 0; i < kernel_half * 2 + 1; i++ ) { int x = i - kernel_half; float angle = x * to_angle; /* instability occurs at center point with rolloff very close to 1.0 */ if ( x || pow_a_n > 1.056 || pow_a_n < 0.981 ) { float rolloff_cos_a = rolloff * float(cos( angle )); float num = 1 - rolloff_cos_a - pow_a_n * float(cos( maxh * angle )) + pow_a_n * rolloff * float(cos( (maxh - 1) * angle )); float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff; float dsf = num / den; kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - 0.5; } } /* apply blackman window and find sum */ sum = 0; for ( i = 0; i < kernel_half * 2 + 1; i++ ) { float x = PI * 2 / (kernel_half * 2) * i; float blackman = 0.42f - 0.5f * float(cos( x )) + 0.08f * float(cos( x * 2 )); sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman); } /* normalize kernel */ sum = 1.0f / sum; for ( i = 0; i < kernel_half * 2 + 1; i++ ) { int x = kernel_size * 3 / 2 - kernel_half + i; kernels [x] *= sum; } } /* generate chroma (iq) filter using gaussian kernel */ { float const cutoff_factor = -0.03125f; float cutoff = float(setup.bleed); int i; if ( cutoff < 0 ) { /* keep extreme value accessible only near upper end of scale (1.0) */ cutoff *= cutoff; cutoff *= cutoff; cutoff *= cutoff; cutoff *= -30.0f / 0.65f; } cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff; for ( i = -kernel_half; i <= kernel_half; i++ ) kernels [kernel_size / 2 + i] = float(exp( i * i * cutoff )); /* normalize even and odd phases separately */ for ( i = 0; i < 2; i++ ) { float sum = 0; int x; for ( x = i; x < kernel_size; x += 2 ) sum += kernels [x]; sum = 1.0f / sum; for ( x = i; x < kernel_size; x += 2 ) { kernels [x] *= sum; } } } /* generate linear rescale kernels */ float weight = 1.0f; float* out = impl.kernel; int n = rescale_out; do { float remain = 0; int i; weight -= 1.0f / rescale_in; for ( i = 0; i < kernel_size * 2; i++ ) { float cur = kernels [i]; float m = cur * weight; *out++ = m + remain; remain = cur - m; } } while ( --n ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Generate pixel at all burst phases and column alignments void AtariNTSC::genKernel(init_t& impl, float y, float i, float q, uInt32* out) { /* generate for each scanline burst phase */ float const* to_rgb = impl.to_rgb; int burst_remain = burst_count; y -= rgb_offset; do { /* Encode yiq into *two* composite signals (to allow control over artifacting). Convolve these with kernels which: filter respective components, apply sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack into integer. Based on algorithm by NewRisingSun. */ pixel_info_t const* pixel = atari_ntsc_pixels; int alignment_remain = alignment_count; do { /* negate is -1 when composite starts at odd multiple of 2 */ float const yy = y * impl.fringing * pixel->negate; float const ic0 = (i + yy) * pixel->kernel [0]; float const qc1 = (q + yy) * pixel->kernel [1]; float const ic2 = (i - yy) * pixel->kernel [2]; float const qc3 = (q - yy) * pixel->kernel [3]; float const factor = impl.artifacts * pixel->negate; float const ii = i * factor; float const yc0 = (y + ii) * pixel->kernel [0]; float const yc2 = (y - ii) * pixel->kernel [2]; float const qq = q * factor; float const yc1 = (y + qq) * pixel->kernel [1]; float const yc3 = (y - qq) * pixel->kernel [3]; float const* k = &impl.kernel [pixel->offset]; int n; ++pixel; for ( n = rgb_kernel_size; n; --n ) { float fi = k[0]*ic0 + k[2]*ic2; float fq = k[1]*qc1 + k[3]*qc3; float fy = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 + k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset; if ( k < &impl.kernel [kernel_size * 2 * (rescale_out - 1)] ) k += kernel_size * 2 - 1; else k -= kernel_size * 2 * (rescale_out - 1) + 2; { int r, g, b = YIQ_TO_RGB( fy, fi, fq, to_rgb, int, r, g ); *out++ = PACK_RGB( r, g, b ) - rgb_bias; } } } while ( alignment_count > 1 && --alignment_remain ); } while ( --burst_remain ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const AtariNTSC::Setup AtariNTSC::TV_Composite = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.15, 0.0, 0.0, 0.0 }; const AtariNTSC::Setup AtariNTSC::TV_SVideo = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.45, -1.0, -1.0, 0.0 }; const AtariNTSC::Setup AtariNTSC::TV_RGB = { 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.70, -1.0, -1.0, -1.0 }; const AtariNTSC::Setup AtariNTSC::TV_Bad = { 0.1, -0.3, 0.3, 0.25, 0.2, 0.0, 0.1, 0.5, 0.5, 0.5 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const AtariNTSC::pixel_info_t AtariNTSC::atari_ntsc_pixels[alignment_count] = { { PIXEL_OFFSET( -4, -9 ), { 1, 1, 1, 1 } }, { PIXEL_OFFSET( 0, -5 ), { 1, 1, 1, 1 } }, }; const float AtariNTSC::default_decoder[6] = { 0.9563f, 0.6210f, -0.2721f, -0.6474f, -1.1070f, 1.7046f }; stella-5.1.1/src/common/tv_filters/AtariNTSC.hxx000066400000000000000000000250321324334165500215330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ /* * Atari TIA NTSC video filter * Based on nes_ntsc 0.2.2. http://www.slack.net/~ant * * Copyright (C) 2006-2009 Shay Green. This module is free software; you * can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. This * module is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. You should have received a copy of the GNU Lesser General Public * License along with this module; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** The class is basically a thin wrapper around atari_ntsc_xxx structs and methods, so that the rest of the codebase isn't affected by updated versions of Blargg code. */ #ifndef ATARI_NTSC_HXX #define ATARI_NTSC_HXX #include #include #include "bspf.hxx" class AtariNTSC { public: enum { palette_size = 256, entry_size = 2 * 14, }; // By default, threading is turned off AtariNTSC() { enableThreading(false); } // Image parameters, ranging from -1.0 to 1.0. Actual internal values shown // in parenthesis and should remain fairly stable in future versions. struct Setup { // Basic parameters double hue; // -1 = -180 degrees +1 = +180 degrees double saturation; // -1 = grayscale (0.0) +1 = oversaturated colors (2.0) double contrast; // -1 = dark (0.5) +1 = light (1.5) double brightness; // -1 = dark (0.5) +1 = light (1.5) double sharpness; // edge contrast enhancement/blurring // Advanced parameters double gamma; // -1 = dark (1.5) +1 = light (0.5) double resolution; // image resolution double artifacts; // artifacts caused by color changes double fringing; // color artifacts caused by brightness changes double bleed; // color bleed (color resolution reduction) }; // Video format presets static const Setup TV_Composite; // color bleeding + artifacts static const Setup TV_SVideo; // color bleeding only static const Setup TV_RGB; // crisp image static const Setup TV_Bad; // badly adjusted TV // Initializes and adjusts parameters. void initialize(const Setup& setup, const uInt8* palette); void initializePalette(const uInt8* palette); // Set up threading void enableThreading(bool enable); // Set phosphor palette, for use in Blargg + phosphor mode void setPhosphorPalette(uInt8 palette[256][256]) { memcpy(myPhosphorPalette, palette, 256 * 256); } // Filters one or more rows of pixels. Input pixels are 8-bit Atari // palette colors. // In_row_width is the number of pixels to get to the next input row. // Out_pitch is the number of *bytes* to get to the next output row. void render(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height, void* rgb_out, const uInt32 out_pitch, uInt32* rgb_in = nullptr); // Number of input pixels that will fit within given output width. // Might be rounded down slightly; use outWidth() on result to find // rounded value. static constexpr uInt32 inWidth( uInt32 out_width ) { return (((out_width-5) / PIXEL_out_chunk - 1) * PIXEL_in_chunk + 1); } // Number of output pixels written by blitter for given input width. // Width might be rounded down slightly; use inWidth() on result to // find rounded value. Guaranteed not to round 160 down at all. static constexpr uInt32 outWidth(uInt32 in_width) { return ((((in_width) - 1) / PIXEL_in_chunk + 1)* PIXEL_out_chunk) + 5; } private: // Threaded rendering void renderThread(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, void* rgb_out, const uInt32 out_pitch); void renderWithPhosphorThread(const uInt8* atari_in, const uInt32 in_width, const uInt32 in_height, const uInt32 numThreads, const uInt32 threadNum, uInt32* rgb_in, void* rgb_out, const uInt32 out_pitch); /** Used to calculate an averaged color for the 'phosphor' effect. @param c RGB Color 1 (current frame) @param cp RGB Color 2 (previous frame) @return Averaged value of the two RGB colors */ uInt32 getRGBPhosphor(const uInt32 c, const uInt32 cp) const; private: enum { PIXEL_in_chunk = 2, // number of input pixels read per chunk PIXEL_out_chunk = 7, // number of output pixels generated per chunk NTSC_black = 0, // palette index for black alignment_count = 2, burst_count = 1, rescale_in = 8, rescale_out = 7, burst_size = entry_size / burst_count, kernel_half = 16, kernel_size = kernel_half * 2 + 1, gamma_size = 256, rgb_builder = ((1 << 21) | (1 << 11) | (1 << 1)), rgb_kernel_size = burst_size / alignment_count, rgb_bits = 8, rgb_unit = (1 << rgb_bits), rgb_bias = rgb_unit * 2 * rgb_builder, std_decoder_hue = 0, ext_decoder_hue = std_decoder_hue + 15 }; #define artifacts_mid 1.5f #define artifacts_max 2.5f #define fringing_mid 1.0f #define fringing_max 2.0f #define rgb_offset (rgb_unit * 2 + 0.5f) #undef PI #define PI 3.14159265358979323846f #define LUMA_CUTOFF 0.20 uInt32 myColorTable[palette_size][entry_size]; uInt8 myPhosphorPalette[256][256]; // Rendering threads unique_ptr myThreads; // Number of rendering and total threads uInt32 myWorkerThreads, myTotalThreads; struct init_t { float to_rgb [burst_count * 6]; float to_float [gamma_size]; float contrast; float brightness; float artifacts; float fringing; float kernel [rescale_out * kernel_size * 2]; }; init_t myImpl; struct pixel_info_t { int offset; float negate; float kernel [4]; }; static const pixel_info_t atari_ntsc_pixels[alignment_count]; static const float default_decoder[6]; void init(init_t& impl, const Setup& setup); void initFilters(init_t& impl, const Setup& setup); // Generate pixel at all burst phases and column alignments void genKernel(init_t& impl, float y, float i, float q, uInt32* out); // Begins outputting row and starts two pixels. First pixel will be cut // off a bit. Use atari_ntsc_black for unused pixels. #define ATARI_NTSC_BEGIN_ROW( pixel0, pixel1 ) \ unsigned const atari_ntsc_pixel0_ = (pixel0);\ uInt32 const* kernel0 = myColorTable[atari_ntsc_pixel0_];\ unsigned const atari_ntsc_pixel1_ = (pixel1);\ uInt32 const* kernel1 = myColorTable[atari_ntsc_pixel1_];\ uInt32 const* kernelx0;\ uInt32 const* kernelx1 = kernel0 // Begins input pixel #define ATARI_NTSC_COLOR_IN( index, color ) {\ unsigned color_;\ kernelx##index = kernel##index;\ kernel##index = (color_ = (color), myColorTable[color_]);\ } // Generates output in the specified 32-bit format (x = junk bits). // native: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format) // 8888: 00000000 RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8-8 32-bit ARGB) #define ATARI_NTSC_RGB_OUT_8888( index, rgb_out ) {\ uInt32 raw_ =\ kernel0 [index ] + kernel1 [(index+10)%7+14] +\ kernelx0 [(index+7)%14] + kernelx1 [(index+ 3)%7+14+7];\ ATARI_NTSC_CLAMP_( raw_, 0 );\ rgb_out = (raw_>>5 & 0x00FF0000)|(raw_>>3 & 0x0000FF00)|(raw_>>1 & 0x000000FF);\ } // Common ntsc macros #define atari_ntsc_clamp_mask (rgb_builder * 3 / 2) #define atari_ntsc_clamp_add (rgb_builder * 0x101) #define ATARI_NTSC_CLAMP_( io, shift ) {\ uInt32 sub = (io) >> (9-(shift)) & atari_ntsc_clamp_mask;\ uInt32 clamp = atari_ntsc_clamp_add - sub;\ io |= clamp;\ clamp -= sub;\ io &= clamp;\ } // Kernel generation #define ROTATE_IQ( i, q, sin_b, cos_b ) {\ float t;\ t = i * cos_b - q * sin_b;\ q = i * sin_b + q * cos_b;\ i = t;\ } #define RGB_TO_YIQ( r, g, b, y, i ) (\ (y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\ (i = (r) * 0.595716f - (g) * 0.274453f - (b) * 0.321263f),\ ((r) * 0.211456f - (g) * 0.522591f + (b) * 0.311135f)\ ) #define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\ r = type(y + to_rgb [0] * i + to_rgb [1] * q),\ g = type(y + to_rgb [2] * i + to_rgb [3] * q),\ type(y + to_rgb [4] * i + to_rgb [5] * q)\ ) #ifndef PACK_RGB #define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1) #endif #define PIXEL_OFFSET_( ntsc, scaled ) \ (kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \ (kernel_size * 2 * scaled)) #define PIXEL_OFFSET( ntsc, scaled ) \ PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\ (((scaled) + rescale_out * 10) % rescale_out) ),\ (1.0f - (((ntsc) + 100) & 2)) #define DISTRIBUTE_ERROR( a, b, c ) {\ uInt32 fourth = (error + 2 * rgb_builder) >> 2;\ fourth &= (rgb_bias >> 1) - rgb_builder;\ fourth -= rgb_bias >> 2;\ out [a] += fourth;\ out [b] += fourth;\ out [c] += fourth;\ out [i] += error - (fourth * 3);\ } #define RGB_PALETTE_OUT( rgb, out_ )\ {\ unsigned char* out = (out_);\ uInt32 clamped = (rgb);\ ATARI_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\ out [0] = (unsigned char) (clamped >> 21);\ out [1] = (unsigned char) (clamped >> 11);\ out [2] = (unsigned char) (clamped >> 1);\ } }; #endif stella-5.1.1/src/common/tv_filters/NTSCFilter.cxx000066400000000000000000000215431324334165500217160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "TIASurface.hxx" #include "Settings.hxx" #include "NTSCFilter.hxx" constexpr double scaleFrom100(double x) { return (x/50.0) - 1.0; } constexpr uInt32 scaleTo100(double x) { return uInt32(50*(x+1.0)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NTSCFilter::NTSCFilter() : mySetup(AtariNTSC::TV_Composite), myPreset(PRESET_OFF), myCurrentAdjustable(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::setPreset(Preset preset) { myPreset = preset; string msg = "disabled"; switch(myPreset) { case PRESET_COMPOSITE: mySetup = AtariNTSC::TV_Composite; msg = "COMPOSITE"; break; case PRESET_SVIDEO: mySetup = AtariNTSC::TV_SVideo; msg = "S-VIDEO"; break; case PRESET_RGB: mySetup = AtariNTSC::TV_RGB; msg = "RGB"; break; case PRESET_BAD: mySetup = AtariNTSC::TV_Bad; msg = "BAD ADJUST"; break; case PRESET_CUSTOM: mySetup = myCustomSetup; msg = "CUSTOM"; break; default: return msg; } myNTSC.initialize(mySetup, myTIAPalette); return msg; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::getPreset() const { switch(myPreset) { case PRESET_COMPOSITE: return "COMPOSITE"; case PRESET_SVIDEO: return "S-VIDEO"; case PRESET_RGB: return "RGB"; case PRESET_BAD: return "BAD ADJUST"; case PRESET_CUSTOM: return "CUSTOM"; default: return "Disabled"; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::setNextAdjustable() { if(myPreset != PRESET_CUSTOM) return "'Custom' TV mode not selected"; myCurrentAdjustable = (myCurrentAdjustable + 1) % 10; ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type << "' selected"; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::setPreviousAdjustable() { if(myPreset != PRESET_CUSTOM) return "'Custom' TV mode not selected"; if(myCurrentAdjustable == 0) myCurrentAdjustable = 9; else myCurrentAdjustable--; ostringstream buf; buf << "Custom adjustable '" << ourCustomAdjustables[myCurrentAdjustable].type << "' selected"; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::increaseAdjustable() { if(myPreset != PRESET_CUSTOM) return "'Custom' TV mode not selected"; uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); newval += 2; if(newval > 100) newval = 100; *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newval); ostringstream buf; buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type << "' set to " << newval; setPreset(myPreset); return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string NTSCFilter::decreaseAdjustable() { if(myPreset != PRESET_CUSTOM) return "'Custom' TV mode not selected"; uInt32 newval = scaleTo100(*ourCustomAdjustables[myCurrentAdjustable].value); if(newval < 2) newval = 0; else newval -= 2; *ourCustomAdjustables[myCurrentAdjustable].value = scaleFrom100(newval); ostringstream buf; buf << "Custom '" << ourCustomAdjustables[myCurrentAdjustable].type << "' set to " << newval; setPreset(myPreset); return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::loadConfig(const Settings& settings) { // Load adjustables for custom mode myCustomSetup.hue = BSPF::clamp(settings.getFloat("tv.hue"), -1.0f, 1.0f); myCustomSetup.saturation = BSPF::clamp(settings.getFloat("tv.saturation"), -1.0f, 1.0f); myCustomSetup.contrast = BSPF::clamp(settings.getFloat("tv.contrast"), -1.0f, 1.0f); myCustomSetup.brightness = BSPF::clamp(settings.getFloat("tv.brightness"), -1.0f, 1.0f); myCustomSetup.sharpness = BSPF::clamp(settings.getFloat("tv.sharpness"), -1.0f, 1.0f); myCustomSetup.gamma = BSPF::clamp(settings.getFloat("tv.gamma"), -1.0f, 1.0f); myCustomSetup.resolution = BSPF::clamp(settings.getFloat("tv.resolution"), -1.0f, 1.0f); myCustomSetup.artifacts = BSPF::clamp(settings.getFloat("tv.artifacts"), -1.0f, 1.0f); myCustomSetup.fringing = BSPF::clamp(settings.getFloat("tv.fringing"), -1.0f, 1.0f); myCustomSetup.bleed = BSPF::clamp(settings.getFloat("tv.bleed"), -1.0f, 1.0f); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::saveConfig(Settings& settings) const { // Save adjustables for custom mode settings.setValue("tv.hue", myCustomSetup.hue); settings.setValue("tv.saturation", myCustomSetup.saturation); settings.setValue("tv.contrast", myCustomSetup.contrast); settings.setValue("tv.brightness", myCustomSetup.brightness); settings.setValue("tv.sharpness", myCustomSetup.sharpness); settings.setValue("tv.gamma", myCustomSetup.gamma); settings.setValue("tv.resolution", myCustomSetup.resolution); settings.setValue("tv.artifacts", myCustomSetup.artifacts); settings.setValue("tv.fringing", myCustomSetup.fringing); settings.setValue("tv.bleed", myCustomSetup.bleed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::getAdjustables(Adjustable& adjustable, Preset preset) const { switch(preset) { case PRESET_COMPOSITE: convertToAdjustable(adjustable, AtariNTSC::TV_Composite); break; case PRESET_SVIDEO: convertToAdjustable(adjustable, AtariNTSC::TV_SVideo); break; case PRESET_RGB: convertToAdjustable(adjustable, AtariNTSC::TV_RGB); break; case PRESET_BAD: convertToAdjustable(adjustable, AtariNTSC::TV_Bad); break; case PRESET_CUSTOM: convertToAdjustable(adjustable, myCustomSetup); break; default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::setCustomAdjustables(Adjustable& adjustable) { myCustomSetup.hue = scaleFrom100(adjustable.hue); myCustomSetup.saturation = scaleFrom100(adjustable.saturation); myCustomSetup.contrast = scaleFrom100(adjustable.contrast); myCustomSetup.brightness = scaleFrom100(adjustable.brightness); myCustomSetup.sharpness = scaleFrom100(adjustable.sharpness); myCustomSetup.gamma = scaleFrom100(adjustable.gamma); myCustomSetup.resolution = scaleFrom100(adjustable.resolution); myCustomSetup.artifacts = scaleFrom100(adjustable.artifacts); myCustomSetup.fringing = scaleFrom100(adjustable.fringing); myCustomSetup.bleed = scaleFrom100(adjustable.bleed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void NTSCFilter::convertToAdjustable(Adjustable& adjustable, const AtariNTSC::Setup& setup) const { adjustable.hue = scaleTo100(setup.hue); adjustable.saturation = scaleTo100(setup.saturation); adjustable.contrast = scaleTo100(setup.contrast); adjustable.brightness = scaleTo100(setup.brightness); adjustable.sharpness = scaleTo100(setup.sharpness); adjustable.gamma = scaleTo100(setup.gamma); adjustable.resolution = scaleTo100(setup.resolution); adjustable.artifacts = scaleTo100(setup.artifacts); adjustable.fringing = scaleTo100(setup.fringing); adjustable.bleed = scaleTo100(setup.bleed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AtariNTSC::Setup NTSCFilter::myCustomSetup = AtariNTSC::TV_Composite; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const NTSCFilter::AdjustableTag NTSCFilter::ourCustomAdjustables[10] = { { "contrast", &myCustomSetup.contrast }, { "brightness", &myCustomSetup.brightness }, { "hue", &myCustomSetup.hue }, { "saturation", &myCustomSetup.saturation }, { "gamma", &myCustomSetup.gamma }, { "sharpness", &myCustomSetup.sharpness }, { "resolution", &myCustomSetup.resolution }, { "artifacts", &myCustomSetup.artifacts }, { "fringing", &myCustomSetup.fringing }, { "bleeding", &myCustomSetup.bleed } }; stella-5.1.1/src/common/tv_filters/NTSCFilter.hxx000066400000000000000000000127541324334165500217270ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef NTSC_FILTER_HXX #define NTSC_FILTER_HXX class TIASurface; class Settings; #include "bspf.hxx" #include "AtariNTSC.hxx" /** This class is based on the Blargg NTSC filter code from Atari800, and is derived from 'filter_ntsc.(h|c)'. Original code based on implementation from http://www.slack.net/~ant. The class is basically a thin wrapper around the AtariNTSC class. */ class NTSCFilter { public: NTSCFilter(); public: // Set one of the available preset adjustments (Composite, S-Video, RGB, etc) enum Preset { PRESET_OFF, PRESET_COMPOSITE, PRESET_SVIDEO, PRESET_RGB, PRESET_BAD, PRESET_CUSTOM }; /* Normally used in conjunction with custom mode, contains all aspects currently adjustable in NTSC TV emulation. */ struct Adjustable { uInt32 hue, saturation, contrast, brightness, gamma, sharpness, resolution, artifacts, fringing, bleed; }; public: /* Informs the NTSC filter about the current TIA palette. The filter uses this as a baseline for calculating its own internal palette in YIQ format. */ inline void setTIAPalette(const uInt32* palette) { uInt8* ptr = myTIAPalette; // Set palette for normal fill for(uInt32 i = 0; i < AtariNTSC::palette_size; ++i) { *ptr++ = (palette[i] >> 16) & 0xff; *ptr++ = (palette[i] >> 8) & 0xff; *ptr++ = palette[i] & 0xff; } myNTSC.initializePalette(myTIAPalette); } inline void setPhosphorPalette(uInt8 palette[256][256]) { myNTSC.setPhosphorPalette(palette); } // The following are meant to be used strictly for toggling from the GUI string setPreset(Preset preset); // Get current preset info encoded as a string string getPreset() const; // Get adjustables for the given preset // Values will be scaled to 0 - 100 range, independent of how // they're actually stored internally void getAdjustables(Adjustable& adjustable, Preset preset) const; // Set custom adjustables to given values // Values will be scaled to 0 - 100 range, independent of how // they're actually stored internally void setCustomAdjustables(Adjustable& adjustable); // The following methods cycle through each custom adjustable // They are used in conjunction with the increase/decrease // methods, which change the currently selected adjustable // Changes are made this way since otherwise 20 key-combinations // would be needed to dynamically change each setting, and now // only 4 combinations are necessary string setNextAdjustable(); string setPreviousAdjustable(); string increaseAdjustable(); string decreaseAdjustable(); // Load and save NTSC-related settings void loadConfig(const Settings& settings); void saveConfig(Settings& settings) const; // Perform Blargg filtering on input buffer, place results in // output buffer inline void render(uInt8* src_buf, uInt32 src_width, uInt32 src_height, uInt32* dest_buf, uInt32 dest_pitch) { myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch); } inline void render(uInt8* src_buf, uInt32 src_width, uInt32 src_height, uInt32* dest_buf, uInt32 dest_pitch, uInt32* prev_buf) { myNTSC.render(src_buf, src_width, src_height, dest_buf, dest_pitch, prev_buf); } // Enable threading for the NTSC rendering inline void enableThreading(bool enable) { myNTSC.enableThreading(enable); } private: // Convert from atari_ntsc_setup_t values to equivalent adjustables void convertToAdjustable(Adjustable& adjustable, const AtariNTSC::Setup& setup) const; private: // The NTSC object AtariNTSC myNTSC; // Contains controls used to adjust the palette in the NTSC filter // This is the main setup object used by the underlying ntsc code AtariNTSC::Setup mySetup; // This setup is used only in custom mode (after it is modified, // it is copied to mySetup) static AtariNTSC::Setup myCustomSetup; // Current preset in use Preset myPreset; // The base 2600 palette contains 128 normal colours // and 128 black&white colours (PAL colour loss) // Each colour is represented by 3 bytes, in R,G,B order uInt8 myTIAPalette[AtariNTSC::palette_size * 3]; struct AdjustableTag { const char* const type; double* value; }; uInt32 myCurrentAdjustable; static const AdjustableTag ourCustomAdjustables[10]; private: // Following constructors and assignment operators not supported NTSCFilter(const NTSCFilter&) = delete; NTSCFilter(NTSCFilter&&) = delete; NTSCFilter& operator=(const NTSCFilter&) = delete; NTSCFilter& operator=(NTSCFilter&&) = delete; }; #endif stella-5.1.1/src/common/tv_filters/module.mk000066400000000000000000000003331324334165500210650ustar00rootroot00000000000000MODULE := src/common/tv_filters MODULE_OBJS := \ src/common/tv_filters/NTSCFilter.o \ src/common/tv_filters/AtariNTSC.o MODULE_DIRS += \ src/common/tv_filters # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/debugger/000077500000000000000000000000001324334165500153635ustar00rootroot00000000000000stella-5.1.1/src/debugger/CartDebug.cxx000066400000000000000000001404261324334165500177560ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "System.hxx" #include "M6502.hxx" #include "FSNode.hxx" #include "DiStella.hxx" #include "Debugger.hxx" #include "DebuggerParser.hxx" #include "CpuDebug.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "Version.hxx" #include "Cart.hxx" #include "CartDebug.hxx" #include "CartDebugWidget.hxx" #include "CartRamWidget.hxx" #include "RomWidget.hxx" #include "Base.hxx" using Common::Base; using std::hex; using std::dec; using std::setfill; using std::setw; using std::left; using std::right; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartDebug::CartDebug(Debugger& dbg, Console& console, const OSystem& osystem) : DebuggerSystem(dbg, console), myOSystem(osystem), myDebugWidget(nullptr), myAddrToLineIsROM(true), myRWPortAddress(0), myLabelLength(8) // longest pre-defined label { // Add case sensitive compare for user labels // TODO - should user labels be case insensitive too? auto usrCmp = [](const string& a, const string& b) { return a < b; }; myUserAddresses = LabelToAddr(usrCmp); // Add case insensitive compare for system labels auto sysCmp = [](const string& a, const string& b) { return BSPF::compareIgnoreCase(a, b) < 0; }; mySystemAddresses = LabelToAddr(sysCmp); // Add Zero-page RAM addresses for(uInt16 i = 0x80; i <= 0xFF; ++i) { myState.rport.push_back(i); myState.wport.push_back(i); myOldState.rport.push_back(i); myOldState.wport.push_back(i); } // Create bank information for each potential bank, and an extra one for ZP RAM // Banksizes greater than 4096 indicate multi-bank ROMs, but we handle only // 4K pieces at a time // Banksizes less than 4K use the actual value uInt32 banksize = 0; myConsole.cartridge().getImage(banksize); BankInfo info; info.size = std::min(banksize, 4096u); for(uInt32 i = 0; i < myConsole.cartridge().bankCount(); ++i) myBankInfo.push_back(info); info.size = 128; // ZP RAM myBankInfo.push_back(info); // We know the address for the startup bank right now myBankInfo[myConsole.cartridge().startBank()].addressList.push_front( myDebugger.dpeek(0xfffc)); addLabel("Start", myDebugger.dpeek(0xfffc, DATA)); // Add system equates for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) { if(ourTIAMnemonicR[addr]) mySystemAddresses.emplace(ourTIAMnemonicR[addr], addr); myReserved.TIARead[addr] = false; } for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) { if(ourTIAMnemonicW[addr]) mySystemAddresses.emplace(ourTIAMnemonicW[addr], addr); myReserved.TIAWrite[addr] = false; } for(uInt16 addr = 0x280; addr <= 0x297; ++addr) { if(ourIOMnemonic[addr-0x280]) mySystemAddresses.emplace(ourIOMnemonic[addr-0x280], addr); myReserved.IOReadWrite[addr-0x280] = false; } for(uInt16 addr = 0x80; addr <= 0xFF; ++addr) { mySystemAddresses.emplace(ourZPMnemonic[addr-0x80], addr); myReserved.ZPRAM[addr-0x80] = false; } myReserved.Label.clear(); myDisassembly.list.reserve(2048); // Add settings for Distella DiStella::settings.gfxFormat = myOSystem.settings().getInt("dis.gfxformat") == 16 ? Base::F_16 : Base::F_2; DiStella::settings.resolveCode = myOSystem.settings().getBool("dis.resolve"); DiStella::settings.showAddresses = myOSystem.settings().getBool("dis.showaddr"); DiStella::settings.aFlag = false; // Not currently configurable DiStella::settings.fFlag = true; // Not currently configurable DiStella::settings.rFlag = myOSystem.settings().getBool("dis.relocate"); DiStella::settings.bFlag = true; // Not currently configurable DiStella::settings.bytesWidth = 8+1; // TODO - configure based on window size } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const DebuggerState& CartDebug::getState() { myState.ram.clear(); for(uInt32 i = 0; i < myState.rport.size(); ++i) myState.ram.push_back(myDebugger.peek(myState.rport[i])); if(myDebugWidget) myState.bank = myDebugWidget->bankState(); return myState; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebug::saveOldState() { myOldState.ram.clear(); for(uInt32 i = 0; i < myOldState.rport.size(); ++i) myOldState.ram.push_back(myDebugger.peek(myOldState.rport[i])); if(myDebugWidget) { myOldState.bank = myDebugWidget->bankState(); myDebugWidget->saveOldState(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebug::triggerReadFromWritePort(uInt16 addr) { myRWPortAddress = addr; mySystem.setDirtyPage(addr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::readFromWritePort() { uInt16 addr = myRWPortAddress; myRWPortAddress = 0; // A read from the write port occurs when the read is actually in the write // port address space AND the last access was actually a read (the latter // differentiates between reads that are normally part of a write cycle vs. // ones that are illegal) if(mySystem.m6502().lastReadAddress() && (mySystem.getPageAccessType(addr) & System::PA_WRITE) == System::PA_WRITE) return addr; else return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::lastReadBaseAddress() { return mySystem.m6502().lastReadBaseAddress(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::lastWriteBaseAddress() { return mySystem.m6502().lastWriteBaseAddress(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::toString() { ostringstream buf; uInt32 bytesPerLine; switch(Base::format()) { case Base::F_16: case Base::F_10: bytesPerLine = 0x10; break; case Base::F_2: bytesPerLine = 0x04; break; case Base::F_DEFAULT: default: return DebuggerParser::red("invalid base, this is a BUG"); } const CartState& state = static_cast(getState()); const CartState& oldstate = static_cast(getOldState()); uInt32 curraddr = 0, bytesSoFar = 0; for(uInt32 i = 0; i < state.ram.size(); i += bytesPerLine, bytesSoFar += bytesPerLine) { // We detect different 'pages' of RAM when the addresses jump by // more than the number of bytes on the previous line, or when 256 // bytes have been previously output if(state.rport[i] - curraddr > bytesPerLine || bytesSoFar >= 256) { char port[37]; std::snprintf(port, 36, "%04x: (rport = %04x, wport = %04x)\n", state.rport[i], state.rport[i], state.wport[i]); port[2] = port[3] = 'x'; buf << DebuggerParser::red(port); bytesSoFar = 0; } curraddr = state.rport[i]; buf << Base::HEX2 << (curraddr & 0x00ff) << ": "; for(uInt8 j = 0; j < bytesPerLine; ++j) { buf << myDebugger.invIfChanged(state.ram[i+j], oldstate.ram[i+j]) << " "; if(j == 0x07) buf << " "; } buf << endl; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::disassemble(bool force) { // Test current disassembly; don't re-disassemble if it hasn't changed // Also check if the current PC is in the current list bool bankChanged = myConsole.cartridge().bankChanged(); uInt16 PC = myDebugger.cpuDebug().pc(); int pcline = addressToLine(PC); bool pcfound = (pcline != -1) && (uInt32(pcline) < myDisassembly.list.size()) && (myDisassembly.list[pcline].disasm[0] != '.'); bool pagedirty = (PC & 0x1000) ? mySystem.isPageDirty(0x1000, 0x1FFF) : mySystem.isPageDirty(0x80, 0xFF); bool changed = !mySystem.autodetectMode() && (force || bankChanged || !pcfound || pagedirty); if(changed) { // Are we disassembling from ROM or ZP RAM? BankInfo& info = (PC & 0x1000) ? myBankInfo[getBank()] : myBankInfo[myBankInfo.size()-1]; // If the offset has changed, all old addresses must be 'converted' // For example, if the list contains any $fxxx and the address space is now // $bxxx, it must be changed uInt16 offset = (PC - (PC % 0x1000)); AddressList& addresses = info.addressList; for(auto& i: addresses) i = (i & 0xFFF) + offset; // Only add addresses when absolutely necessary, to cut down on the // work that Distella has to do if(bankChanged || !pcfound) { AddressList::const_iterator i; for(i = addresses.cbegin(); i != addresses.cend(); ++i) { if (PC == *i) // already present break; } // Otherwise, add the item at the end if (i == addresses.end()) addresses.push_back(PC); } // Always attempt to resolve code sections unless it's been // specifically disabled bool found = fillDisassemblyList(info, PC); if(!found && DiStella::settings.resolveCode) { // Temporarily turn off code resolution DiStella::settings.resolveCode = false; fillDisassemblyList(info, PC); DiStella::settings.resolveCode = true; } } return changed; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::fillDisassemblyList(BankInfo& info, uInt16 search) { // An empty address list means that DiStella can't do a disassembly if(info.addressList.size() == 0) return false; myDisassembly.list.clear(); myDisassembly.fieldwidth = 24 + myLabelLength; DiStella distella(*this, myDisassembly.list, info, DiStella::settings, myDisLabels, myDisDirectives, myReserved); // Parts of the disassembly will be accessed later in different ways // We place those parts in separate maps, to speed up access bool found = false; myAddrToLineList.clear(); myAddrToLineIsROM = info.offset & 0x1000; for(uInt32 i = 0; i < myDisassembly.list.size(); ++i) { const DisassemblyTag& tag = myDisassembly.list[i]; const uInt16 address = tag.address & 0xFFF; // Exclude 'ROW'; they don't have a valid address if(tag.type != CartDebug::ROW) { // Create a mapping from addresses to line numbers myAddrToLineList.emplace(address, i); // Did we find the search value? if(address == (search & 0xFFF)) found = true; } } return found; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::addressToLine(uInt16 address) const { // Switching between ZP RAM address space and Cart/ROM address space // means the line isn't present if(!myAddrToLineIsROM != !(address & 0x1000)) return -1; const auto& iter = myAddrToLineList.find(address & 0xFFF); return iter != myAddrToLineList.end() ? iter->second : -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::disassemble(uInt16 start, uInt16 lines) const { // Fill the string with disassembled data start &= 0xFFF; ostringstream buffer; // First find the lines in the range, and determine the longest string uInt32 list_size = uInt32(myDisassembly.list.size()); uInt32 begin = list_size, end = 0, length = 0; for(end = 0; end < list_size && lines > 0; ++end) { const CartDebug::DisassemblyTag& tag = myDisassembly.list[end]; if((tag.address & 0xfff) >= start) { if(begin == list_size) begin = end; if(tag.type != CartDebug::ROW) length = std::max(length, uInt32(tag.disasm.length())); --lines; } } // Now output the disassembly, using as little space as possible for(uInt32 i = begin; i < end; ++i) { const CartDebug::DisassemblyTag& tag = myDisassembly.list[i]; if(tag.type == CartDebug::NONE) continue; else if(tag.address) buffer << std::uppercase << std::hex << std::setw(4) << std::setfill('0') << tag.address << ": "; else buffer << " "; buffer << tag.disasm << std::setw(int(length - tag.disasm.length() + 2)) << std::setfill(' ') << " " << std::setw(4) << std::left << tag.ccount << " " << tag.bytes << endl; } return buffer.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end, int bank) { if(end < start || start == 0 || end == 0) return false; if(bank < 0) // Do we want the current bank or ZP RAM? bank = (myDebugger.cpuDebug().pc() & 0x1000) ? getBank() : int(myBankInfo.size())-1; bank = std::min(bank, bankCount()); BankInfo& info = myBankInfo[bank]; DirectiveList& list = info.directiveList; DirectiveTag tag; tag.type = type; tag.start = start; tag.end = end; DirectiveList::iterator i; // If the same directive and range is added, consider it a removal instead for(i = list.begin(); i != list.end(); ++i) { if(i->type == tag.type && i->start == tag.start && i->end == tag.end) { list.erase(i); return false; } } // Otherwise, scan the list and make space for a 'smart' merge // Note that there are 4 possibilities: // 1: a range is completely inside the new range // 2: a range is completely outside the new range // 3: a range overlaps at the beginning of the new range // 4: a range overlaps at the end of the new range for(i = list.begin(); i != list.end(); ++i) { // Case 1: remove range that is completely inside new range if(tag.start <= i->start && tag.end >= i->end) { i = list.erase(i); } // Case 2: split the old range else if(tag.start >= i->start && tag.end <= i->end) { // Only split when necessary if(tag.type == i->type) return true; // node is fine as-is // Create new endpoint DirectiveTag tag2; tag2.type = i->type; tag2.start = tag.end + 1; tag2.end = i->end; // Modify startpoint i->end = tag.start - 1; // Insert new endpoint i++; list.insert(i, tag2); break; // no need to go further; this is the insertion point } // Case 3: truncate end of old range else if(tag.start >= i->start && tag.start <= i->end) { i->end = tag.start - 1; } // Case 4: truncate start of old range else if(tag.end >= i->start && tag.end <= i->end) { i->start = tag.end + 1; } } // We now know that the new range can be inserted without overlap // Where possible, consecutive ranges should be merged rather than // new nodes created for(i = list.begin(); i != list.end(); ++i) { if(tag.end < i->start) // node should be inserted *before* this one { bool createNode = true; // Is the new range ending consecutive with the old range beginning? // If so, a merge will suffice if(i->type == tag.type && tag.end + 1 == i->start) { i->start = tag.start; createNode = false; // a merge was done, so a new node isn't needed } // Can we also merge with the previous range (if any)? if(i != list.begin()) { DirectiveList::iterator p = i; --p; if(p->type == tag.type && p->end + 1 == tag.start) { if(createNode) // a merge with right-hand range didn't previously occur { p->end = tag.end; createNode = false; // a merge was done, so a new node isn't needed } else // merge all three ranges { i->start = p->start; i = list.erase(p); createNode = false; // a merge was done, so a new node isn't needed } } } // Create the node only when necessary if(createNode) i = list.insert(i, tag); break; } } // Otherwise, add the tag at the end if(i == list.end()) list.push_back(tag); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::getBank() { return myConsole.cartridge().getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::bankCount() const { return myConsole.cartridge().bankCount(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::addLabel(const string& label, uInt16 address) { // Only user-defined labels can be added or redefined switch(addressType(address)) { case ADDR_TIA: case ADDR_IO: return false; default: removeLabel(label); myUserAddresses.emplace(label, address); myUserLabels.emplace(address, label); myLabelLength = std::max(myLabelLength, uInt16(label.size())); mySystem.setDirtyPage(address); return true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::removeLabel(const string& label) { // Only user-defined labels can be removed const auto& iter = myUserAddresses.find(label); if(iter != myUserAddresses.end()) { // Erase the address assigned to the label const auto& iter2 = myUserLabels.find(iter->second); if(iter2 != myUserLabels.end()) myUserLabels.erase(iter2); // Erase the label itself mySystem.setDirtyPage(iter->second); myUserAddresses.erase(iter); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDebug::getLabel(ostream& buf, uInt16 addr, bool isRead, int places) const { switch(addressType(addr)) { case ADDR_TIA: { if(isRead) { uInt16 a = addr & 0x0F, offset = addr & 0xFFF0; if(ourTIAMnemonicR[a]) { buf << ourTIAMnemonicR[a]; if(offset > 0) buf << "|$" << Base::HEX2 << offset; } else buf << "$" << Base::HEX2 << addr; } else { uInt16 a = addr & 0x3F, offset = addr & 0xFFC0; if(ourTIAMnemonicW[a]) { buf << ourTIAMnemonicW[a]; if(offset > 0) buf << "|$" << Base::HEX2 << offset; } else buf << "$" << Base::HEX2 << addr; } return true; } case ADDR_IO: { uInt16 a = addr & 0xFF, offset = addr & 0xFD00; if(a <= 0x97) { if(ourIOMnemonic[a - 0x80]) { buf << ourIOMnemonic[a - 0x80]; if(offset > 0) buf << "|$" << Base::HEX2 << offset; } else buf << "$" << Base::HEX2 << addr; } else buf << "$" << Base::HEX2 << addr; return true; } case ADDR_ZPRAM: { // RAM can use user-defined labels; otherwise we default to // standard mnemonics auto iter = myUserLabels.find(addr); if(iter != myUserLabels.end()) { buf << iter->second; } else { uInt16 a = addr & 0xFF, offset = addr & 0xFF00; if((iter = myUserLabels.find(a)) != myUserLabels.end()) buf << iter->second; else buf << ourZPMnemonic[a - 0x80]; if(offset > 0) buf << "|$" << Base::HEX2 << offset; } return true; } case ADDR_ROM: { // These addresses can never be in the system labels list const auto& iter = myUserLabels.find(addr); if(iter != myUserLabels.end()) { buf << iter->second; return true; } break; } } switch(places) { case 2: buf << "$" << Base::HEX2 << addr; return true; case 4: buf << "$" << Base::HEX4 << addr; return true; case 8: buf << "$" << Base::HEX8 << addr; return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::getLabel(uInt16 addr, bool isRead, int places) const { ostringstream buf; getLabel(buf, addr, isRead, places); return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebug::getAddress(const string& label) const { LabelToAddr::const_iterator iter; if((iter = mySystemAddresses.find(label)) != mySystemAddresses.end()) return iter->second; else if((iter = myUserAddresses.find(label)) != myUserAddresses.end()) return iter->second; else return -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::loadListFile() { // The default naming/location for list files is the ROM dir based on the // actual ROM filename if(myListFile == "") { FilesystemNode lst(myOSystem.romFile().getPathWithExt("") + ".lst"); if(lst.isFile() && lst.isReadable()) myListFile = lst.getPath(); else return DebuggerParser::red("list file not found in:\n " + lst.getShortPath()); } FilesystemNode node(myListFile); ifstream in(node.getPath()); if(!in.is_open()) return DebuggerParser::red("list file '" + node.getShortPath() + "' not readable"); while(!in.eof()) { string line, addr_s; getline(in, line); if(line.length() == 0 || line[0] == '-') continue; else // Search for constants { stringstream buf(line); // Swallow first value, then get actual numerical value for address // We need to read the address as a string, since it may contain 'U' int addr = -1; buf >> addr >> addr_s; if(addr_s.length() == 0) continue; const char* p = addr_s[0] == 'U' ? addr_s.c_str() + 1 : addr_s.c_str(); addr = int(strtoul(p, nullptr, 16)); // For now, completely ignore ROM addresses if(!(addr & 0x1000)) { // Search for pattern 'xx yy CONSTANT =' buf.seekg(20); // skip potential '????' int xx = -1, yy = -1; char eq = '\0'; buf >> hex >> xx >> hex >> yy >> line >> eq; if(xx >= 0 && yy >= 0 && eq == '=') //myUserCLabels.emplace(xx*256+yy, line); addLabel(line, xx * 256 + yy); } } } myDebugger.rom().invalidate(); return "loaded " + node.getShortPath() + " OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::loadSymbolFile() { // The default naming/location for symbol files is the ROM dir based on the // actual ROM filename if(mySymbolFile == "") { FilesystemNode sym(myOSystem.romFile().getPathWithExt("") + ".sym"); if(sym.isFile() && sym.isReadable()) mySymbolFile = sym.getPath(); else return DebuggerParser::red("symbol file not found in:\n " + sym.getShortPath()); } FilesystemNode node(mySymbolFile); ifstream in(node.getPath()); if(!in.is_open()) return DebuggerParser::red("symbol file '" + node.getShortPath() + "' not readable"); myUserAddresses.clear(); myUserLabels.clear(); while(!in.eof()) { string label; int value = -1; getline(in, label); stringstream buf(label); buf >> label >> hex >> value; if(label.length() > 0 && label[0] != '-' && value >= 0) { // Make sure the value doesn't represent a constant // For now, we simply ignore constants completely //const auto& iter = myUserCLabels.find(value); //if(iter == myUserCLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second)) const auto& iter = myUserLabels.find(value); if (iter == myUserLabels.end() || !BSPF::equalsIgnoreCase(label, iter->second)) { // Check for period, and strip leading number string::size_type pos = label.find_first_of(".", 0); if(pos != string::npos) addLabel(label.substr(pos), value); else { pos = label.find_last_of("$"); if (pos == string::npos || pos != label.length() - 1) addLabel(label, value); } } } } myDebugger.rom().invalidate(); return "loaded " + node.getShortPath() + " OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::loadConfigFile() { // There are two possible locations for loading config files // (in order of decreasing relevance): // 1) ROM dir based on properties entry name // 2) CFG dir based on properties entry name if(myCfgFile == "") { const string& propsname = myConsole.properties().get(Cartridge_Name) + ".cfg"; FilesystemNode case1(myOSystem.romFile().getParent().getPath() + propsname); FilesystemNode case2(myOSystem.cfgDir() + propsname); if(case1.isFile() && case1.isReadable()) myCfgFile = case1.getPath(); else if(case2.isFile() && case2.isReadable()) myCfgFile = case2.getPath(); else return DebuggerParser::red("config file not found in:\n " + case1.getShortPath() + "\n " + case2.getShortPath()); } FilesystemNode node(myCfgFile); ifstream in(node.getPath()); if(!in.is_open()) return "Unable to load directives from " + node.getPath(); // Erase all previous directives for(auto& bi: myBankInfo) bi.directiveList.clear(); int currentbank = 0; while(!in.eof()) { // Skip leading space int c = in.peek(); while(c == ' ' || c == '\t') { in.get(); c = in.peek(); } string line; c = in.peek(); if(c == '/') // Comment, swallow line and continue { getline(in, line); continue; } else if(c == '[') { in.get(); getline(in, line, ']'); stringstream buf(line); buf >> currentbank; } else // Should be commands from this point on { getline(in, line); stringstream buf; buf << line; string directive; uInt16 start = 0, end = 0; buf >> directive; if(BSPF::startsWithIgnoreCase(directive, "ORG")) { // TODO - figure out what to do with this buf >> hex >> start; } else if(BSPF::startsWithIgnoreCase(directive, "CODE")) { buf >> hex >> start >> hex >> end; addDirective(CartDebug::CODE, start, end, currentbank); } else if(BSPF::startsWithIgnoreCase(directive, "GFX")) { buf >> hex >> start >> hex >> end; addDirective(CartDebug::GFX, start, end, currentbank); } else if(BSPF::startsWithIgnoreCase(directive, "PGFX")) { buf >> hex >> start >> hex >> end; addDirective(CartDebug::PGFX, start, end, currentbank); } else if(BSPF::startsWithIgnoreCase(directive, "DATA")) { buf >> hex >> start >> hex >> end; addDirective(CartDebug::DATA, start, end, currentbank); } else if(BSPF::startsWithIgnoreCase(directive, "ROW")) { buf >> hex >> start; buf >> hex >> end; addDirective(CartDebug::ROW, start, end, currentbank); } } } myDebugger.rom().invalidate(); stringstream retVal; if(myConsole.cartridge().bankCount() > 1) retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n"); retVal << "loaded " << node.getShortPath() << " OK"; return retVal.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveConfigFile() { // While there are two possible locations for loading config files, // the main 'config' directory is used whenever possible when saving, // unless the rom-specific file already exists FilesystemNode node; FilesystemNode case0(myCfgFile); if(myCfgFile != "" && case0.isFile() && case0.isWritable()) node = case0; else { const string& propsname = myConsole.properties().get(Cartridge_Name) + ".cfg"; node = FilesystemNode(myOSystem.cfgDir() + propsname); } const string& name = myConsole.properties().get(Cartridge_Name); const string& md5 = myConsole.properties().get(Cartridge_MD5); ofstream out(node.getPath()); if(!out.is_open()) return "Unable to save directives to " + node.getShortPath(); // Store all bank information out << "//Stella.pro: \"" << name << "\"" << endl << "//MD5: " << md5 << endl << endl; for(uInt32 b = 0; b < myConsole.cartridge().bankCount(); ++b) { out << "[" << b << "]" << endl; getBankDirectives(out, myBankInfo[b]); } stringstream retVal; if(myConsole.cartridge().bankCount() > 1) retVal << DebuggerParser::red("config file for multi-bank ROM not fully supported\n"); retVal << "saved " << node.getShortPath() << " OK"; return retVal.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveDisassembly() { if(myDisasmFile == "") { const string& propsname = myConsole.properties().get(Cartridge_Name) + ".asm"; myDisasmFile = FilesystemNode(myOSystem.defaultSaveDir() + propsname).getPath(); } FilesystemNode node(myDisasmFile); ofstream out(node.getPath()); if(!out.is_open()) return "Unable to save disassembly to " + node.getShortPath(); #define ALIGN(x) setfill(' ') << left << setw(x) // We can't print the header to the disassembly until it's actually // been processed; therefore buffer output to a string first ostringstream buf; buf << "\n\n;***********************************************************\n" << "; Bank " << myConsole.cartridge().getBank(); if (myConsole.cartridge().bankCount() > 1) buf << " / 0.." << myConsole.cartridge().bankCount() - 1; buf << "\n;***********************************************************\n\n"; // Use specific settings for disassembly output // This will most likely differ from what you see in the debugger DiStella::Settings settings; settings.gfxFormat = DiStella::settings.gfxFormat; settings.resolveCode = true; settings.showAddresses = false; settings.aFlag = false; // Otherwise DASM gets confused settings.fFlag = DiStella::settings.fFlag; settings.rFlag = DiStella::settings.rFlag; settings.bytesWidth = 8+1; // same as Stella debugger settings.bFlag = DiStella::settings.bFlag;; // process break routine (TODO) Disassembly disasm; disasm.list.reserve(2048); for(int bank = 0; bank < myConsole.cartridge().bankCount(); ++bank) { BankInfo& info = myBankInfo[bank]; // An empty address list means that DiStella can't do a disassembly if(info.addressList.size() == 0) continue; // Disassemble bank disasm.list.clear(); DiStella distella(*this, disasm.list, info, settings, myDisLabels, myDisDirectives, myReserved); if (myReserved.breakFound) addLabel("Break", myDebugger.dpeek(0xfffe)); buf << " SEG CODE\n" << " ORG $" << Base::HEX4 << info.offset << "\n\n"; // Format in 'distella' style for(uInt32 i = 0; i < disasm.list.size(); ++i) { const DisassemblyTag& tag = disasm.list[i]; // Add label (if any) if(tag.label != "") buf << ALIGN(4) << (tag.label) << "\n"; buf << " "; switch(tag.type) { case CartDebug::CODE: { buf << ALIGN(32) << tag.disasm << tag.ccount.substr(0, 5) << tag.ctotal << tag.ccount.substr(5, 2); if (tag.disasm.find("WSYNC") != std::string::npos) buf << "\n;---------------------------------------"; break; } case CartDebug::ROW: { buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8*4-1) << "; $" << Base::HEX4 << tag.address << " (*)"; break; } case CartDebug::GFX: { buf << ".byte " << (settings.gfxFormat == Base::F_2 ? "%" : "$") << tag.bytes << " ; |"; for(int c = 12; c < 20; ++c) buf << ((tag.disasm[c] == '\x1e') ? "#" : " "); buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (G)"; break; } case CartDebug::PGFX: { buf << ".byte " << (settings.gfxFormat == Base::F_2 ? "%" : "$") << tag.bytes << " ; |"; for(int c = 12; c < 20; ++c) buf << ((tag.disasm[c] == '\x1f') ? "*" : " "); buf << ALIGN(13) << "|" << "$" << Base::HEX4 << tag.address << " (P)"; break; } case CartDebug::DATA: { buf << ".byte " << ALIGN(32) << tag.disasm.substr(6, 8 * 4 - 1) << "; $" << Base::HEX4 << tag.address << " (D)"; break; } case CartDebug::NONE: default: { break; } } // switch buf << "\n"; } } // Some boilerplate, similar to what DiStella adds time_t currtime; time(&currtime); out << "; Disassembly of " << myOSystem.romFile().getShortPath() << "\n" << "; Disassembled " << ctime(&currtime) << "; Using Stella " << STELLA_VERSION << "\n;\n" << "; ROM properties name : " << myConsole.properties().get(Cartridge_Name) << "\n" << "; ROM properties MD5 : " << myConsole.properties().get(Cartridge_MD5) << "\n" << "; Bankswitch type : " << myConsole.cartridge().about() << "\n;\n" << "; Legend: * = CODE not yet run (tentative code)\n" << "; D = DATA directive (referenced in some way)\n" << "; G = GFX directive, shown as '#' (stored in player, missile, ball)\n" << "; P = PGFX directive, shown as '*' (stored in playfield)\n" << "; i = indexed accessed only\n" << "; c = used by code executed in RAM\n" << "; s = used by stack\n" << "; ! = page crossed, 1 cycle penalty\n" << "\n processor 6502\n\n"; bool addrUsed = false; for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) addrUsed = addrUsed || myReserved.TIARead[addr] || (mySystem.getAccessFlags(addr) & WRITE); for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) addrUsed = addrUsed || myReserved.TIAWrite[addr] || (mySystem.getAccessFlags(addr) & DATA); for(uInt16 addr = 0x00; addr <= 0x17; ++addr) addrUsed = addrUsed || myReserved.IOReadWrite[addr]; if(addrUsed) { out << "\n;-----------------------------------------------------------\n" << "; TIA and IO constants accessed\n" << ";-----------------------------------------------------------\n\n"; // TIA read access for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) if(myReserved.TIARead[addr] && ourTIAMnemonicR[addr]) out << ALIGN(16) << ourTIAMnemonicR[addr] << "= $" << Base::HEX2 << right << addr << " ; (R)\n"; else if (mySystem.getAccessFlags(addr) & DATA) out << ";" << ALIGN(16-1) << ourTIAMnemonicR[addr] << "= $" << Base::HEX2 << right << addr << " ; (Ri)\n"; out << "\n"; // TIA write access for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) if(myReserved.TIAWrite[addr] && ourTIAMnemonicW[addr]) out << ALIGN(16) << ourTIAMnemonicW[addr] << "= $" << Base::HEX2 << right << addr << " ; (W)\n"; else if (mySystem.getAccessFlags(addr) & WRITE) out << ";" << ALIGN(16-1) << ourTIAMnemonicW[addr] << "= $" << Base::HEX2 << right << addr << " ; (Wi)\n"; out << "\n"; // RIOT IO access for(uInt16 addr = 0x00; addr <= 0x17; ++addr) if(myReserved.IOReadWrite[addr] && ourIOMnemonic[addr]) out << ALIGN(16) << ourIOMnemonic[addr] << "= $" << Base::HEX4 << right << (addr+0x280) << "\n"; } addrUsed = false; for(uInt16 addr = 0x80; addr <= 0xFF; ++addr) addrUsed = addrUsed || myReserved.ZPRAM[addr-0x80] || (mySystem.getAccessFlags(addr) & (DATA | WRITE)) || (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE)); if(addrUsed) { bool addLine = false; out << "\n\n;-----------------------------------------------------------\n" << "; RIOT RAM (zero-page) labels\n" << ";-----------------------------------------------------------\n\n"; for (uInt16 addr = 0x80; addr <= 0xFF; ++addr) { bool ramUsed = (mySystem.getAccessFlags(addr) & (DATA | WRITE)); bool codeUsed = (mySystem.getAccessFlags(addr) & CODE); bool stackUsed = (mySystem.getAccessFlags(addr|0x100) & (DATA | WRITE)); if (myReserved.ZPRAM[addr - 0x80] && myUserLabels.find(addr) == myUserLabels.end()) { if (addLine) out << "\n"; out << ALIGN(16) << ourZPMnemonic[addr - 0x80] << "= $" << Base::HEX2 << right << (addr) << (stackUsed|codeUsed ? "; (" : "") << (codeUsed ? "c" : "") << (stackUsed ? "s" : "") << (stackUsed | codeUsed ? ")" : "") << "\n"; addLine = false; } else if (ramUsed|codeUsed|stackUsed) { if (addLine) out << "\n"; out << ALIGN(18) << ";" << "$" << Base::HEX2 << right << (addr) << " (" << (ramUsed ? "i" : "") << (codeUsed ? "c" : "") << (stackUsed ? "s" : "") << ")\n"; addLine = false; } else addLine = true; } } if(myReserved.Label.size() > 0) { out << "\n\n;-----------------------------------------------------------\n" << "; Non Locatable Labels\n" << ";-----------------------------------------------------------\n\n"; for(const auto& iter: myReserved.Label) out << ALIGN(16) << iter.second << "= $" << iter.first << "\n"; } if(myUserLabels.size() > 0) { out << "\n\n;-----------------------------------------------------------\n" << "; User Defined Labels\n" << ";-----------------------------------------------------------\n\n"; int max_len = 16; for(const auto& iter: myUserLabels) max_len = std::max(max_len, int(iter.second.size())); for(const auto& iter: myUserLabels) out << ALIGN(max_len) << iter.second << "= $" << iter.first << "\n"; } // And finally, output the disassembly out << buf.str(); stringstream retVal; if(myConsole.cartridge().bankCount() > 1) retVal << DebuggerParser::red("disassembly for multi-bank ROM not fully supported, only currently enabled banks disassembled\n"); retVal << "saved " << node.getShortPath() << " OK"; return retVal.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::saveRom() { const string& rom = myConsole.properties().get(Cartridge_Name) + ".a26"; FilesystemNode node(myOSystem.defaultSaveDir() + rom); ofstream out(node.getPath(), std::ios::binary); if(out && myConsole.cartridge().saveROM(out)) return "saved ROM as " + node.getShortPath(); else return DebuggerParser::red("failed to save ROM"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::listConfig(int bank) { if(myConsole.cartridge().bankCount() > 1) return DebuggerParser::red("config file for multi-bank ROM not yet supported"); uInt32 startbank = 0, endbank = bankCount(); if(bank >= 0 && bank < bankCount()) { startbank = bank; endbank = startbank + 1; } ostringstream buf; buf << "(items marked '*' are user-defined)" << endl; for(uInt32 b = startbank; b < endbank; ++b) { BankInfo& info = myBankInfo[b]; buf << "[" << b << "]" << endl; for(const auto& i: info.directiveList) { if(i.type != CartDebug::NONE) { buf << "(*) "; disasmTypeAsString(buf, i.type); buf << " " << Base::HEX4 << i.start << " " << Base::HEX4 << i.end << endl; } } getBankDirectives(buf, info); } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartDebug::clearConfig(int bank) { uInt32 startbank = 0, endbank = bankCount(); if(bank >= 0 && bank < bankCount()) { startbank = bank; endbank = startbank + 1; } uInt32 count = 0; for(uInt32 b = startbank; b < endbank; ++b) { count += myBankInfo[b].directiveList.size(); myBankInfo[b].directiveList.clear(); } ostringstream buf; if(count > 0) buf << "removed " << dec << count << " directives from " << dec << (endbank - startbank) << " banks"; else buf << "no directives present"; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebug::getCompletions(const char* in, StringList& completions) const { // First scan system equates for(uInt16 addr = 0x00; addr <= 0x0F; ++addr) if(ourTIAMnemonicR[addr] && BSPF::matches(ourTIAMnemonicR[addr], in)) completions.push_back(ourTIAMnemonicR[addr]); for(uInt16 addr = 0x00; addr <= 0x3F; ++addr) if(ourTIAMnemonicW[addr] && BSPF::matches(ourTIAMnemonicW[addr], in)) completions.push_back(ourTIAMnemonicW[addr]); for(uInt16 addr = 0; addr <= 0x297-0x280; ++addr) if(ourIOMnemonic[addr] && BSPF::matches(ourIOMnemonic[addr], in)) completions.push_back(ourIOMnemonic[addr]); for(uInt16 addr = 0; addr <= 0x7F; ++addr) if(ourZPMnemonic[addr] && BSPF::matches(ourZPMnemonic[addr], in)) completions.push_back(ourZPMnemonic[addr]); // Now scan user-defined labels for(const auto& iter: myUserAddresses) { const char* l = iter.first.c_str(); if(BSPF::matches(l, in)) completions.push_back(l); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartDebug::AddrType CartDebug::addressType(uInt16 addr) const { // Determine the type of address to access the correct list // These addresses were based on (and checked against) Kroko's 2600 memory // map, found at http://www.qotile.net/minidig/docs/2600_mem_map.txt if(addr % 0x2000 < 0x1000) { if((addr & 0x00ff) < 0x80) return ADDR_TIA; else { switch(addr & 0x0f00) { case 0x000: case 0x100: case 0x400: case 0x500: case 0x800: case 0x900: case 0xc00: case 0xd00: return ADDR_ZPRAM; case 0x200: case 0x300: case 0x600: case 0x700: case 0xa00: case 0xb00: case 0xe00: case 0xf00: return ADDR_IO; } } } return ADDR_ROM; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebug::getBankDirectives(ostream& buf, BankInfo& info) const { // Start with the offset for this bank buf << "ORG " << Base::HEX4 << info.offset << endl; // Now consider each byte uInt32 prev = info.offset, addr = prev + 1; DisasmType prevType = disasmTypeAbsolute(mySystem.getAccessFlags(prev)); for( ; addr < info.offset + info.size; ++addr) { DisasmType currType = disasmTypeAbsolute(mySystem.getAccessFlags(addr)); // Have we changed to a new type? if(currType != prevType) { disasmTypeAsString(buf, prevType); buf << " " << Base::HEX4 << prev << " " << Base::HEX4 << (addr-1) << endl; prev = addr; prevType = currType; } } // Grab the last directive, making sure it accounts for all remaining space if(prev != addr) { disasmTypeAsString(buf, prevType); buf << " " << Base::HEX4 << prev << " " << Base::HEX4 << (addr-1) << endl; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebug::addressTypeAsString(ostream& buf, uInt16 addr) const { if(!(addr & 0x1000)) { buf << DebuggerParser::red("type only defined for cart address space"); return; } uInt8 directive = myDisDirectives[addr & 0xFFF] & 0xFC, debugger = myDebugger.getAccessFlags(addr) & 0xFC, label = myDisLabels[addr & 0xFFF]; buf << endl << "directive: " << Base::toString(directive, Base::F_2_8) << " "; disasmTypeAsString(buf, directive); buf << endl << "emulation: " << Base::toString(debugger, Base::F_2_8) << " "; disasmTypeAsString(buf, debugger); buf << endl << "tentative: " << Base::toString(label, Base::F_2_8) << " "; disasmTypeAsString(buf, label); buf << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartDebug::DisasmType CartDebug::disasmTypeAbsolute(uInt8 flags) const { if(flags & CartDebug::CODE) return CartDebug::CODE; else if(flags & CartDebug::TCODE) return CartDebug::CODE; // TODO - should this be separate?? else if(flags & CartDebug::GFX) return CartDebug::GFX; else if(flags & CartDebug::PGFX) return CartDebug::PGFX; else if(flags & CartDebug::DATA) return CartDebug::DATA; else if(flags & CartDebug::ROW) return CartDebug::ROW; else return CartDebug::NONE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebug::disasmTypeAsString(ostream& buf, DisasmType type) const { switch(type) { case CartDebug::CODE: buf << "CODE"; break; case CartDebug::TCODE: buf << "TCODE"; break; case CartDebug::GFX: buf << "GFX"; break; case CartDebug::PGFX: buf << "PGFX"; break; case CartDebug::DATA: buf << "DATA"; break; case CartDebug::ROW: buf << "ROW"; break; case CartDebug::REFERENCED: case CartDebug::VALID_ENTRY: case CartDebug::NONE: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebug::disasmTypeAsString(ostream& buf, uInt8 flags) const { if(flags) { if(flags & CartDebug::CODE) buf << "CODE "; if(flags & CartDebug::TCODE) buf << "TCODE "; if(flags & CartDebug::GFX) buf << "GFX "; if(flags & CartDebug::PGFX) buf << "PGFX "; if(flags & CartDebug::DATA) buf << "DATA "; if(flags & CartDebug::ROW) buf << "ROW "; if(flags & CartDebug::REFERENCED) buf << "*REFERENCED "; if(flags & CartDebug::VALID_ENTRY) buf << "*VALID_ENTRY "; } else buf << "no flags set"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* const CartDebug::ourTIAMnemonicR[16] = { "CXM0P", "CXM1P", "CXP0FB", "CXP1FB", "CXM0FB", "CXM1FB", "CXBLPF", "CXPPMM", "INPT0", "INPT1", "INPT2", "INPT3", "INPT4", "INPT5", "$1e", "$1f" }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* const CartDebug::ourTIAMnemonicW[64] = { "VSYNC", "VBLANK", "WSYNC", "RSYNC", "NUSIZ0", "NUSIZ1", "COLUP0", "COLUP1", "COLUPF", "COLUBK", "CTRLPF", "REFP0", "REFP1", "PF0", "PF1", "PF2", "RESP0", "RESP1", "RESM0", "RESM1", "RESBL", "AUDC0", "AUDC1", "AUDF0", "AUDF1", "AUDV0", "AUDV1", "GRP0", "GRP1", "ENAM0", "ENAM1", "ENABL", "HMP0", "HMP1", "HMM0", "HMM1", "HMBL", "VDELP0", "VDELP1", "VDELBL", "RESMP0", "RESMP1", "HMOVE", "HMCLR", "CXCLR", "$2d", "$2e", "$2f", "$30", "$31", "$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39", "$3a", "$3b", "$3c", "$3d", "$3e", "$3f" }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* const CartDebug::ourIOMnemonic[24] = { "SWCHA", "SWACNT", "SWCHB", "SWBCNT", "INTIM", "TIMINT", "$286", "$287", "$288", "$289", "$28a", "$28b", "$28c", "$28d", "$28e", "$28f", "$290", "$291", "$292", "$293", "TIM1T", "TIM8T", "TIM64T", "T1024T" }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* const CartDebug::ourZPMnemonic[128] = { "ram_80", "ram_81", "ram_82", "ram_83", "ram_84", "ram_85", "ram_86", "ram_87", "ram_88", "ram_89", "ram_8A", "ram_8B", "ram_8C", "ram_8D", "ram_8E", "ram_8F", "ram_90", "ram_91", "ram_92", "ram_93", "ram_94", "ram_95", "ram_96", "ram_97", "ram_98", "ram_99", "ram_9A", "ram_9B", "ram_9C", "ram_9D", "ram_9E", "ram_9F", "ram_A0", "ram_A1", "ram_A2", "ram_A3", "ram_A4", "ram_A5", "ram_A6", "ram_A7", "ram_A8", "ram_A9", "ram_AA", "ram_AB", "ram_AC", "ram_AD", "ram_AE", "ram_AF", "ram_B0", "ram_B1", "ram_B2", "ram_B3", "ram_B4", "ram_B5", "ram_B6", "ram_B7", "ram_B8", "ram_B9", "ram_BA", "ram_BB", "ram_BC", "ram_BD", "ram_BE", "ram_BF", "ram_C0", "ram_C1", "ram_C2", "ram_C3", "ram_C4", "ram_C5", "ram_C6", "ram_C7", "ram_C8", "ram_C9", "ram_CA", "ram_CB", "ram_CC", "ram_CD", "ram_CE", "ram_CF", "ram_D0", "ram_D1", "ram_D2", "ram_D3", "ram_D4", "ram_D5", "ram_D6", "ram_D7", "ram_D8", "ram_D9", "ram_DA", "ram_DB", "ram_DC", "ram_DD", "ram_DE", "ram_DF", "ram_E0", "ram_E1", "ram_E2", "ram_E3", "ram_E4", "ram_E5", "ram_E6", "ram_E7", "ram_E8", "ram_E9", "ram_EA", "ram_EB", "ram_EC", "ram_ED", "ram_EE", "ram_EF", "ram_F0", "ram_F1", "ram_F2", "ram_F3", "ram_F4", "ram_F5", "ram_F6", "ram_F7", "ram_F8", "ram_F9", "ram_FA", "ram_FB", "ram_FC", "ram_FD", "ram_FE", "ram_FF" }; stella-5.1.1/src/debugger/CartDebug.hxx000066400000000000000000000316411324334165500177610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CART_DEBUG_HXX #define CART_DEBUG_HXX class Settings; class CartDebugWidget; // Function type for CartDebug instance methods class CartDebug; using CartMethod = int (CartDebug::*)(); #include #include #include #include "bspf.hxx" #include "DebuggerSystem.hxx" class CartState : public DebuggerState { public: ByteArray ram; // The actual data values ShortArray rport; // Address for reading from RAM ShortArray wport; // Address for writing to RAM string bank; // Current banking layout }; class CartDebug : public DebuggerSystem { // The disassembler needs special access to this class friend class DiStella; public: enum DisasmType { NONE = 0, REFERENCED = 1 << 0, /* 0x01, code somewhere in the program references it, i.e. LDA $F372 referenced $F372 */ VALID_ENTRY = 1 << 1, /* 0x02, addresses that can have a label placed in front of it. A good counterexample would be "FF00: LDA $FE00"; $FF01 would be in the middle of a multi-byte instruction, and therefore cannot be labelled. */ // The following correspond to specific types that can be set within the // debugger, or specified in a Distella cfg file, and are listed in order // of decreasing hierarchy // CODE = 1 << 7, // 0x80, disassemble-able code segments TCODE = 1 << 6, // 0x40, (tentative) disassemble-able code segments GFX = 1 << 5, // 0x20, addresses loaded into GRPx registers PGFX = 1 << 4, // 0x10, addresses loaded into PFx registers DATA = 1 << 3, // 0x08, addresses loaded into registers other than GRPx / PFx ROW = 1 << 2, // 0x04, all other addresses // special type for poke() WRITE = TCODE // 0x40, address written to }; struct DisassemblyTag { DisasmType type; uInt16 address; string label; string disasm; string ccount; string ctotal; string bytes; bool hllabel; }; using DisassemblyList = vector; struct Disassembly { DisassemblyList list; int fieldwidth; }; // Determine 'type' of address (ie, what part of the system accessed) enum AddrType { ADDR_TIA, ADDR_IO, ADDR_ZPRAM, ADDR_ROM }; AddrType addressType(uInt16 addr) const; public: CartDebug(Debugger& dbg, Console& console, const OSystem& osystem); virtual ~CartDebug() = default; const DebuggerState& getState() override; const DebuggerState& getOldState() override { return myOldState; } void saveOldState() override; string toString() override; // Used to get/set the debug widget, which contains cart-specific // functionality CartDebugWidget* getDebugWidget() const { return myDebugWidget; } void setDebugWidget(CartDebugWidget* w) { myDebugWidget = w; } // Indicate that a read from write port has occurred at the specified // address. void triggerReadFromWritePort(uInt16 address); // Return the address at which an invalid read was performed in a // write port area. int readFromWritePort(); // Return the base (= non-mirrored) address of the last CPU read int lastReadBaseAddress(); // Return the base (= non-mirrored) address of the last CPU write int lastWriteBaseAddress(); // The following two methods are meant to be used together // First, a call is made to disassemble(), which updates the disassembly // list; it will figure out when an actual complete disassembly is // required, and when the previous results can be used // // Later, successive calls to disassemblyList() simply return the // previous results; no disassembly is done in this case /** Disassemble from the given address using the Distella disassembler Address-to-label mappings (and vice-versa) are also determined here @param force Force a re-disassembly, even if the state hasn't changed @return True if disassembly changed from previous call, else false */ bool disassemble(bool force = false); /** Get the results from the most recent call to disassemble() */ const Disassembly& disassembly() const { return myDisassembly; } /** Determine the line in the disassembly that corresponds to the given address. @param address The address to search for @return Line number of the address, else -1 if no such address exists */ int addressToLine(uInt16 address) const; /** Disassemble from the starting address the specified number of lines. Note that automatic code determination is turned off for this method; @param start The start address for disassembly @param lines The number of disassembled lines to generate @return The disassembly represented as a string */ string disassemble(uInt16 start, uInt16 lines) const; /** Add a directive to the disassembler. Directives are basically overrides for the automatic code determination algorithm in Distella, since some things can't be automatically determined. For now, these directives have exactly the same syntax as in a distella configuration file. @param type Currently, CODE/DATA/GFX are supported @param start The start address (inclusive) to mark with the given type @param end The end address (inclusive) to mark with the given type @param bank Bank to which these directive apply (0 indicated current bank) @return True if directive was added, else false if it was removed */ bool addDirective(CartDebug::DisasmType type, uInt16 start, uInt16 end, int bank = -1); // The following are convenience methods that query the cartridge object // for the desired information. /** Get the current bank in use by the cartridge (non-const because of use in YaccParser) */ int getBank(); /** Get the total number of banks supported by the cartridge. */ int bankCount() const; /** Add a label and associated address. Labels that reference either TIA or RIOT spaces will not be processed. */ bool addLabel(const string& label, uInt16 address); /** Remove the given label and its associated address. Labels that reference either TIA or RIOT spaces will not be processed. */ bool removeLabel(const string& label); /** Accessor methods for labels and addresses The mapping from address to label can be one-to-many (ie, an address can have different labels depending on its context, and whether its being read or written; if isRead is true, the context is a read, else it's a write If places is not -1 and a label hasn't been defined, return a formatted hexidecimal address */ bool getLabel(ostream& buf, uInt16 addr, bool isRead, int places = -1) const; string getLabel(uInt16 addr, bool isRead, int places = -1) const; int getAddress(const string& label) const; /** Load constants from list file (as generated by DASM). */ string loadListFile(); /** Load user equates from symbol file (as generated by DASM). */ string loadSymbolFile(); /** Load/save Distella config files (Distella directives) */ string loadConfigFile(); string saveConfigFile(); /** Save disassembly and ROM file */ string saveDisassembly(); string saveRom(); /** Show Distella directives (both set by the user and determined by Distella) for the given bank (or all banks, if no bank is specified). */ string listConfig(int bank = -1); /** Clear Distella directives (set by the user) for the given bank (or all banks, if no bank is specified.) */ string clearConfig(int bank = -1); /** Methods used by the command parser for tab-completion In this case, return completions from the equate list(s) */ void getCompletions(const char* in, StringList& list) const; // Convert given address to corresponding disassembly type and append to buf void addressTypeAsString(ostream& buf, uInt16 addr) const; private: using AddrToLabel = std::map; using LabelToAddr = std::map>; struct DirectiveTag { DisasmType type; uInt16 start; uInt16 end; }; using AddressList = std::list; using DirectiveList = std::list; struct BankInfo { uInt16 start; // start of address space uInt16 end; // end of address space uInt16 offset; // ORG value uInt32 size; // size of a bank (in bytes) AddressList addressList; // addresses which PC has hit DirectiveList directiveList; // overrides for automatic code determination BankInfo() : start(0), end(0), offset(0), size(0) { } }; // Address type information determined by Distella uInt8 myDisLabels[0x1000], myDisDirectives[0x1000]; // Information on equates used in the disassembly struct ReservedEquates { bool TIARead[16]; bool TIAWrite[64]; bool IOReadWrite[24]; bool ZPRAM[128]; AddrToLabel Label; bool breakFound; }; ReservedEquates myReserved; // Actually call DiStella to fill the DisassemblyList structure // Return whether the search address was actually in the list bool fillDisassemblyList(BankInfo& bankinfo, uInt16 search); // Analyze of bank of ROM, generating a list of Distella directives // based on its disassembly void getBankDirectives(ostream& buf, BankInfo& info) const; // Get disassembly enum type from 'flags', taking precendence into account DisasmType disasmTypeAbsolute(uInt8 flags) const; // Convert disassembly enum type to corresponding string and append to buf void disasmTypeAsString(ostream& buf, DisasmType type) const; // Convert all disassembly types in 'flags' to corresponding string and // append to buf void disasmTypeAsString(ostream& buf, uInt8 flags) const; private: const OSystem& myOSystem; CartState myState; CartState myOldState; CartDebugWidget* myDebugWidget; // A complete record of relevant diassembly information for each bank vector myBankInfo; // Used for the disassembly display, and mapping from addresses // to corresponding lines of text in that display Disassembly myDisassembly; std::map myAddrToLineList; bool myAddrToLineIsROM; // Mappings from label to address (and vice versa) for items // defined by the user (either through a DASM symbol file or manually // from the commandline in the debugger) AddrToLabel myUserLabels; LabelToAddr myUserAddresses; // Mappings from label to address (and vice versa) for constants // defined through a DASM lst file // AddrToLabel myUserCLabels; // LabelToAddr myUserCAddresses; // Mappings for labels to addresses for system-defined equates // Because system equate addresses can have different names // (depending on access in read vs. write mode), we can only create // a mapping from labels to addresses; addresses to labels are // handled differently LabelToAddr mySystemAddresses; // Holds address at which the most recent read from a write port // occurred uInt16 myRWPortAddress; // The maximum length of all labels currently defined uInt16 myLabelLength; // Filenames to use for various I/O (currently these are hardcoded) string myListFile, mySymbolFile, myCfgFile, myDisasmFile, myRomFile; /// Table of instruction mnemonics static const char* const ourTIAMnemonicR[16]; // read mode static const char* const ourTIAMnemonicW[64]; // write mode static const char* const ourIOMnemonic[24]; static const char* const ourZPMnemonic[128]; private: // Following constructors and assignment operators not supported CartDebug() = delete; CartDebug(const CartDebug&) = delete; CartDebug(CartDebug&&) = delete; CartDebug& operator=(const CartDebug&) = delete; CartDebug& operator=(CartDebug&&) = delete; }; #endif stella-5.1.1/src/debugger/CpuDebug.cxx000066400000000000000000000151131324334165500176060ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "M6502.hxx" #include "System.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "TIADebug.hxx" #include "CpuDebug.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CpuDebug::CpuDebug(Debugger& dbg, Console& console) : DebuggerSystem(dbg, console), my6502(mySystem.m6502()) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const DebuggerState& CpuDebug::getState() { myState.PC = my6502.PC; myState.SP = my6502.SP; myState.PS = my6502.PS(); myState.A = my6502.A; myState.X = my6502.X; myState.Y = my6502.Y; myState.srcS = my6502.lastSrcAddressS(); myState.srcA = my6502.lastSrcAddressA(); myState.srcX = my6502.lastSrcAddressX(); myState.srcY = my6502.lastSrcAddressY(); Debugger::set_bits(myState.PS, myState.PSbits); return myState; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::saveOldState() { myOldState.PC = my6502.PC; myOldState.SP = my6502.SP; myOldState.PS = my6502.PS(); myOldState.A = my6502.A; myOldState.X = my6502.X; myOldState.Y = my6502.Y; myOldState.srcS = my6502.lastSrcAddressS(); myOldState.srcA = my6502.lastSrcAddressA(); myOldState.srcX = my6502.lastSrcAddressX(); myOldState.srcY = my6502.lastSrcAddressY(); Debugger::set_bits(myOldState.PS, myOldState.PSbits); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::pc() const { return mySystem.m6502().PC; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::sp() const { return mySystem.m6502().SP; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::a() const { return mySystem.m6502().A; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::x() const { return mySystem.m6502().X; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::y() const { return mySystem.m6502().Y; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::n() const { return mySystem.m6502().N; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::v() const { return mySystem.m6502().V; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::b() const { return mySystem.m6502().B; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::d() const { return mySystem.m6502().D; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::i() const { return mySystem.m6502().I; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::z() const { return !mySystem.m6502().notZ; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::c() const { return mySystem.m6502().C; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CpuDebug::icycles() const { return mySystem.m6502().icycles; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setPC(int pc) { my6502.PC = uInt16(pc); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setSP(int sp) { my6502.SP = uInt8(sp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setPS(int ps) { my6502.PS(ps); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setA(int a) { my6502.A = uInt8(a); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setX(int x) { my6502.X = uInt8(x); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setY(int y) { my6502.Y = uInt8(y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setN(bool on) { my6502.N = on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setV(bool on) { my6502.V = on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setB(bool) { // nop - B is always true } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setD(bool on) { my6502.D = on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setI(bool on) { my6502.I = on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setZ(bool on) { my6502.notZ = !on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setC(bool on) { my6502.C = on; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::setCycles(int cycles) { my6502.icycles = cycles; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::toggleN() { my6502.N = !my6502.N; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::toggleV() { my6502.V = !my6502.V; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::toggleB() { // nop - B is always true } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::toggleD() { my6502.D = !my6502.D; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::toggleI() { my6502.I = !my6502.I; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::toggleZ() { my6502.notZ = !my6502.notZ; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuDebug::toggleC() { my6502.C = !my6502.C; } stella-5.1.1/src/debugger/CpuDebug.hxx000066400000000000000000000047671324334165500176300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CPU_DEBUG_HXX #define CPU_DEBUG_HXX class M6502; class System; // Function type for CpuDebug instance methods class CpuDebug; using CpuMethod = int (CpuDebug::*)() const; #include "DebuggerSystem.hxx" class CpuState : public DebuggerState { public: int PC, SP, PS, A, X, Y; int srcS, srcA, srcX, srcY; BoolArray PSbits; }; class CpuDebug : public DebuggerSystem { public: CpuDebug(Debugger& dbg, Console& console); const DebuggerState& getState() override; const DebuggerState& getOldState() override { return myOldState; } void saveOldState() override; string toString() override { return EmptyString; } // Not needed, since CPU stuff is always visible int pc() const; int sp() const; int a() const; int x() const; int y() const; // These return int, not boolean! int n() const; int v() const; int b() const; int d() const; int i() const; int z() const; int c() const; int icycles() const; void setPC(int pc); void setSP(int sp); void setPS(int ps); void setA(int a); void setX(int x); void setY(int y); void setN(bool on); void setV(bool on); void setB(bool on); void setD(bool on); void setI(bool on); void setZ(bool on); void setC(bool on); void setCycles(int cycles); void toggleN(); void toggleV(); void toggleB(); void toggleD(); void toggleI(); void toggleZ(); void toggleC(); private: M6502& my6502; CpuState myState; CpuState myOldState; private: // Following constructors and assignment operators not supported CpuDebug() = delete; CpuDebug(const CpuDebug&) = delete; CpuDebug(CpuDebug&&) = delete; CpuDebug& operator=(const CpuDebug&) = delete; CpuDebug& operator=(CpuDebug&&) = delete; }; #endif stella-5.1.1/src/debugger/Debugger.cxx000066400000000000000000000621331324334165500176400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "Version.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "EventHandler.hxx" #include "FSNode.hxx" #include "Settings.hxx" #include "DebuggerDialog.hxx" #include "DebuggerParser.hxx" #include "StateManager.hxx" #include "RewindManager.hxx" #include "Console.hxx" #include "System.hxx" #include "M6502.hxx" #include "Cart.hxx" #include "CartDebug.hxx" #include "CartDebugWidget.hxx" #include "CartRamWidget.hxx" #include "CpuDebug.hxx" #include "RiotDebug.hxx" #include "TIADebug.hxx" #include "TiaInfoWidget.hxx" #include "TiaOutputWidget.hxx" #include "TiaZoomWidget.hxx" #include "EditTextWidget.hxx" #include "RomWidget.hxx" #include "Expression.hxx" #include "PackedBitArray.hxx" #include "YaccParser.hxx" #include "TIA.hxx" #include "Debugger.hxx" Debugger* Debugger::myStaticDebugger = nullptr; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Debugger::Debugger(OSystem& osystem, Console& console) : DialogContainer(osystem), myConsole(console), mySystem(console.system()), myDialog(nullptr), myWidth(DebuggerDialog::kSmallFontMinW), myHeight(DebuggerDialog::kSmallFontMinH) { // Init parser myParser = make_unique(*this, osystem.settings()); // Create debugger subsystems myCpuDebug = make_unique(*this, myConsole); myCartDebug = make_unique(*this, myConsole, osystem); myRiotDebug = make_unique(*this, myConsole); myTiaDebug = make_unique(*this, myConsole); // Allow access to this object from any class // Technically this violates pure OO programming, but since I know // there will only be ever one instance of debugger in Stella, // I don't care :) myStaticDebugger = this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Debugger::~Debugger() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::initialize() { const GUI::Size& s = myOSystem.settings().getSize("dbg.res"); const GUI::Size& d = myOSystem.frameBuffer().desktopSize(); myWidth = s.w; myHeight = s.h; // The debugger dialog is resizable, within certain bounds // We check those bounds now myWidth = std::max(myWidth, uInt32(DebuggerDialog::kSmallFontMinW)); myHeight = std::max(myHeight, uInt32(DebuggerDialog::kSmallFontMinH)); myWidth = std::min(myWidth, uInt32(d.w)); myHeight = std::min(myHeight, uInt32(d.h)); myOSystem.settings().setValue("dbg.res", GUI::Size(myWidth, myHeight)); delete myBaseDialog; myBaseDialog = myDialog = nullptr; myDialog = new DebuggerDialog(myOSystem, *this, 0, 0, myWidth, myHeight); myBaseDialog = myDialog; myCartDebug->setDebugWidget(&(myDialog->cartDebug())); saveOldState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus Debugger::initializeVideo() { string title = string("Stella ") + STELLA_VERSION + ": Debugger mode"; return myOSystem.frameBuffer().createDisplay(title, myWidth, myHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::start(const string& message, int address, bool read) { if(myOSystem.eventHandler().enterDebugMode()) { // This must be done *after* we enter debug mode, // so the message isn't erased ostringstream buf; buf << message; if(address > -1) buf << cartDebug().getLabel(address, read, 4); myDialog->message().setText(buf.str()); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::startWithFatalError(const string& message) { if(myOSystem.eventHandler().enterDebugMode()) { // This must be done *after* we enter debug mode, // so the dialog is properly shown myDialog->showFatalMessage(message); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::quit(bool exitrom) { if(exitrom) myOSystem.eventHandler().handleEvent(Event::LauncherMode, 1); else myOSystem.eventHandler().leaveDebugMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Debugger::autoExec(StringList* history) { ostringstream buf; // autoexec.script is always run FilesystemNode autoexec(myOSystem.baseDir() + "autoexec.script"); buf << "autoExec():" << endl << myParser->exec(autoexec, history) << endl; // Also, "romname.script" if present FilesystemNode romname(myOSystem.romFile().getPathWithExt(".script")); buf << myParser->exec(romname, history) << endl; // Init builtins for(uInt32 i = 0; i < NUM_BUILTIN_FUNCS; ++i) { // TODO - check this for memory leaks int res = YaccParser::parse(ourBuiltinFunctions[i].defn); if(res == 0) addFunction(ourBuiltinFunctions[i].name, ourBuiltinFunctions[i].defn, YaccParser::getResult(), true); else cerr << "ERROR in builtin function!" << endl; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PackedBitArray& Debugger::breakPoints() const { return mySystem.m6502().breakPoints(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TrapArray& Debugger::readTraps() const { return mySystem.m6502().readTraps(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TrapArray& Debugger::writeTraps() const { return mySystem.m6502().writeTraps(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string Debugger::run(const string& command) { return myParser->run(command); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string Debugger::invIfChanged(int reg, int oldReg) { string ret; bool changed = reg != oldReg; if(changed) ret += "\177"; ret += Common::Base::toString(reg, Common::Base::F_16_2); if(changed) ret += "\177"; return ret; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::reset() { unlockSystem(); mySystem.reset(); lockSystem(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* Element 0 of args is the address. The remaining elements are the data to poke, starting at the given address. */ string Debugger::setRAM(IntArray& args) { ostringstream buf; int count = int(args.size()); int address = args[0]; for(int i = 1; i < count; ++i) mySystem.poke(address++, args[i]); buf << "changed " << (count-1) << " location"; if(count != 2) buf << "s"; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::saveState(int state) { // Saving a state is implicitly a read-only operation, so we keep the // system locked, so no changes can occur myOSystem.state().saveState(state); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::loadState(int state) { // We're loading a new state, so we start with a clean slate mySystem.clearDirtyPages(); // State loading could initiate a bankswitch, so we allow it temporarily unlockSystem(); myOSystem.state().loadState(state); lockSystem(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Debugger::step() { saveOldState(); uInt64 startCycle = mySystem.cycles(); unlockSystem(); myOSystem.console().tia().updateScanlineByStep().flushLineCache(); lockSystem(); addState("step"); return int(mySystem.cycles() - startCycle); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // trace is just like step, except it treats a subroutine call as one // instruction. // This implementation is not perfect: it just watches the program counter, // instead of tracking (possibly) nested JSR/RTS pairs. In particular, it // will fail for recursive subroutine calls. However, with 128 bytes of RAM // to share between stack and variables, I doubt any 2600 games will ever // use recursion... int Debugger::trace() { // 32 is the 6502 JSR instruction: if(mySystem.peek(myCpuDebug->pc()) == 32) { saveOldState(); uInt64 startCycle = mySystem.cycles(); int targetPC = myCpuDebug->pc() + 3; // return address unlockSystem(); myOSystem.console().tia().updateScanlineByTrace(targetPC).flushLineCache(); lockSystem(); addState("trace"); return int(mySystem.cycles() - startCycle); } else return step(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::toggleBreakPoint(uInt16 bp) { breakPoints().initialize(); breakPoints().toggle(bp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::setBreakPoint(uInt16 bp, bool set) { breakPoints().initialize(); if(set) breakPoints().set(bp); else breakPoints().clear(bp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::breakPoint(uInt16 bp) { return breakPoints().isSet(bp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::addReadTrap(uInt16 t) { readTraps().initialize(); readTraps().add(t); } void Debugger::addWriteTrap(uInt16 t) { writeTraps().initialize(); writeTraps().add(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::addTrap(uInt16 t) { addReadTrap(t); addWriteTrap(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::removeReadTrap(uInt16 t) { readTraps().initialize(); readTraps().remove(t); } void Debugger::removeWriteTrap(uInt16 t) { writeTraps().initialize(); writeTraps().remove(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::removeTrap(uInt16 t) { removeReadTrap(t); removeWriteTrap(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::readTrap(uInt16 t) { return readTraps().isInitialized() && readTraps().isSet(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::writeTrap(uInt16 t) { return writeTraps().isInitialized() && writeTraps().isSet(t); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Debugger::peek(uInt16 addr, uInt8 flags) { return mySystem.peek(addr, flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Debugger::dpeek(uInt16 addr, uInt8 flags) { return uInt16(mySystem.peek(addr, flags) | (mySystem.peek(addr+1, flags) << 8)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::poke(uInt16 addr, uInt8 value, uInt8 flags) { mySystem.poke(addr, value, flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6502& Debugger::m6502() const { return mySystem.m6502(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Debugger::peekAsInt(int addr, uInt8 flags) { return mySystem.peek(uInt16(addr), flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Debugger::dpeekAsInt(int addr, uInt8 flags) { return mySystem.peek(uInt16(addr), flags) | (mySystem.peek(uInt16(addr+1), flags) << 8); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Debugger::getAccessFlags(uInt16 addr) const { return mySystem.getAccessFlags(addr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::setAccessFlags(uInt16 addr, uInt8 flags) { mySystem.setAccessFlags(addr, flags); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Debugger::getBaseAddress(uInt32 addr, bool read) { if((addr & 0x1080) == 0x0000) // (addr & 0b 0001 0000 1000 0000) == 0b 0000 0000 0000 0000 { if(read) // ADDR_TIA read (%xxx0 xxxx 0xxx ????) return addr & 0x000f; // 0b 0000 0000 0000 1111 else // ADDR_TIA write (%xxx0 xxxx 0x?? ????) return addr & 0x003f; // 0b 0000 0000 0011 1111 } // ADDR_ZPRAM (%xxx0 xx0x 1??? ????) if((addr & 0x1280) == 0x0080) // (addr & 0b 0001 0010 1000 0000) == 0b 0000 0000 1000 0000 return addr & 0x00ff; // 0b 0000 0000 1111 1111 // ADDR_ROM if(addr & 0x1000) return addr & 0x1fff; // 0b 0001 1111 1111 1111 // ADDR_IO read/write I/O registers (%xxx0 xx1x 1xxx x0??) if((addr & 0x1284) == 0x0280) // (addr & 0b 0001 0010 1000 0100) == 0b 0000 0010 1000 0000 return addr & 0x0283; // 0b 0000 0010 1000 0011 // ADDR_IO write timers (%xxx0 xx1x 1xx1 ?1??) if(!read && (addr & 0x1294) == 0x0294) // (addr & 0b 0001 0010 1001 0100) == 0b 0000 0010 1001 0100 return addr & 0x029f; // 0b 0000 0010 1001 1111 // ADDR_IO read timers (%xxx0 xx1x 1xxx ?1x0) if(read && (addr & 0x1285) == 0x0284) // (addr & 0b 0001 0010 1000 0101) == 0b 0000 0010 1000 0100 return addr & 0x028c; // 0b 0000 0010 1000 1100 // ADDR_IO read timer/PA7 interrupt (%xxx0 xx1x 1xxx x1x1) if(read && (addr & 0x1285) == 0x0285) // (addr & 0b 0001 0010 1000 0101) == 0b 0000 0010 1000 0101 return addr & 0x0285; // 0b 0000 0010 1000 0101 // ADDR_IO write PA7 edge control (%xxx0 xx1x 1xx0 x1??) if(!read && (addr & 0x1294) == 0x0284) // (addr & 0b 0001 0010 1001 0100) == 0b 0000 0010 1000 0100 return addr & 0x0287; // 0b 0000 0010 1000 0111 return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::nextScanline(int lines) { ostringstream buf; buf << "scanline + " << lines; saveOldState(); unlockSystem(); while(lines) { myOSystem.console().tia().updateScanline(); --lines; } lockSystem(); addState(buf.str()); myOSystem.console().tia().flushLineCache(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::nextFrame(int frames) { ostringstream buf; buf << "frame + " << frames; saveOldState(); unlockSystem(); while(frames) { myOSystem.console().tia().update(); --frames; } lockSystem(); addState(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::updateRewindbuttons(const RewindManager& r) { myDialog->rewindButton().setEnabled(!r.atFirst()); myDialog->unwindButton().setEnabled(!r.atLast()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Debugger::windStates(uInt16 numStates, bool unwind, string& message) { RewindManager& r = myOSystem.state().rewindManager(); saveOldState(); unlockSystem(); uInt64 startCycles = myOSystem.console().tia().cycles(); uInt16 winds = r.windStates(numStates, unwind); message = r.getUnitString(myOSystem.console().tia().cycles() - startCycles); lockSystem(); updateRewindbuttons(r); return winds; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Debugger::rewindStates(const uInt16 numStates, string& message) { return windStates(numStates, false, message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Debugger::unwindStates(const uInt16 numStates, string& message) { return windStates(numStates, true, message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::clearAllBreakPoints() { breakPoints().clearAll(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::clearAllTraps() { readTraps().clearAll(); writeTraps().clearAll(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Debugger::showWatches() { return myParser->showWatches(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Debugger::stringToValue(const string& stringval) { return myParser->decipher_arg(stringval); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::patchROM(uInt16 addr, uInt8 value) { return myConsole.cartridge().patch(addr, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::saveOldState(bool clearDirtyPages) { if(clearDirtyPages) mySystem.clearDirtyPages(); lockSystem(); myCartDebug->saveOldState(); myCpuDebug->saveOldState(); myRiotDebug->saveOldState(); myTiaDebug->saveOldState(); unlockSystem(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::addState(string rewindMsg) { // Add another rewind level to the Time Machine buffer RewindManager& r = myOSystem.state().rewindManager(); r.addState(rewindMsg); updateRewindbuttons(r); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::setStartState() { // Lock the bus each time the debugger is entered, so we don't disturb anything lockSystem(); // Save initial state and add it to the rewind list (except when in currently rewinding) RewindManager& r = myOSystem.state().rewindManager(); // avoid invalidating future states when entering the debugger e.g. during rewind if(r.atLast() && (myOSystem.eventHandler().state() != EventHandlerState::TIMEMACHINE || myOSystem.state().mode() == StateManager::Mode::Off)) addState("enter debugger"); else updateRewindbuttons(r); // Set the 're-disassemble' flag, but don't do it until the next scheduled time myDialog->rom().invalidate(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::setQuitState() { saveOldState(); // Bus must be unlocked for normal operation when leaving debugger mode unlockSystem(); // execute one instruction on quit. If we're // sitting at a breakpoint/trap, this will get us past it. // Somehow this feels like a hack to me, but I don't know why // if(breakPoints().isSet(myCpuDebug->pc())) mySystem.m6502().execute(1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::addFunction(const string& name, const string& definition, Expression* exp, bool builtin) { myFunctions.emplace(name, unique_ptr(exp)); myFunctionDefs.emplace(name, definition); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::isBuiltinFunction(const string& name) { for(uInt32 i = 0; i < NUM_BUILTIN_FUNCS; ++i) if(name == ourBuiltinFunctions[i].name) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Debugger::delFunction(const string& name) { const auto& iter = myFunctions.find(name); if(iter == myFunctions.end()) return false; // We never want to delete built-in functions if(isBuiltinFunction(name)) return false; myFunctions.erase(name); const auto& def_iter = myFunctionDefs.find(name); if(def_iter == myFunctionDefs.end()) return false; myFunctionDefs.erase(name); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Expression& Debugger::getFunction(const string& name) const { const auto& iter = myFunctions.find(name); return iter != myFunctions.end() ? *(iter->second.get()) : EmptyExpression; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& Debugger::getFunctionDef(const string& name) const { const auto& iter = myFunctionDefs.find(name); return iter != myFunctionDefs.end() ? iter->second : EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const FunctionDefMap Debugger::getFunctionDefMap() const { return myFunctionDefs; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Debugger::builtinHelp() const { ostringstream buf; uInt16 len, c_maxlen = 0, i_maxlen = 0; // Get column widths for aligned output (functions) for(uInt32 i = 0; i < NUM_BUILTIN_FUNCS; ++i) { len = ourBuiltinFunctions[i].name.size(); if(len > c_maxlen) c_maxlen = len; len = ourBuiltinFunctions[i].defn.size(); if(len > i_maxlen) i_maxlen = len; } buf << std::setfill(' ') << endl << "Built-in functions:" << endl; for(uInt32 i = 0; i < NUM_BUILTIN_FUNCS; ++i) { buf << std::setw(c_maxlen) << std::left << ourBuiltinFunctions[i].name << std::setw(2) << std::right << "{" << std::setw(i_maxlen) << std::left << ourBuiltinFunctions[i].defn << std::setw(4) << "}" << ourBuiltinFunctions[i].help << endl; } // Get column widths for aligned output (pseudo-registers) c_maxlen = 0; for(uInt32 i = 0; i < NUM_PSEUDO_REGS; ++i) { len = ourPseudoRegisters[i].name.size(); if(len > c_maxlen) c_maxlen = len; } buf << endl << "Pseudo-registers:" << endl; for(uInt32 i = 0; i < NUM_PSEUDO_REGS; ++i) { buf << std::setw(c_maxlen) << std::left << ourPseudoRegisters[i].name << std::setw(2) << " " << std::setw(i_maxlen) << std::left << ourPseudoRegisters[i].help << endl; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::getCompletions(const char* in, StringList& list) const { // skip if filter equals "_" only if(!BSPF::equalsIgnoreCase(in, "_")) { for(const auto& iter : myFunctions) { const char* l = iter.first.c_str(); if(BSPF::matches(l, in)) list.push_back(l); } for(uInt32 i = 0; i < NUM_PSEUDO_REGS; ++i) if(BSPF::matches(ourPseudoRegisters[i].name, in)) list.push_back(ourPseudoRegisters[i].name); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::lockSystem() { mySystem.lockDataBus(); myConsole.cartridge().lockBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Debugger::unlockSystem() { mySystem.unlockDataBus(); myConsole.cartridge().unlockBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Debugger::BuiltinFunction Debugger::ourBuiltinFunctions[NUM_BUILTIN_FUNCS] = { // left joystick: { "_joy0left", "!(*SWCHA & $40)", "Left joystick moved left" }, { "_joy0right", "!(*SWCHA & $80)", "Left joystick moved right" }, { "_joy0up", "!(*SWCHA & $10)", "Left joystick moved up" }, { "_joy0down", "!(*SWCHA & $20)", "Left joystick moved down" }, { "_joy0button", "!(*INPT4 & $80)", "Left joystick button pressed" }, // right joystick: { "_joy1left", "!(*SWCHA & $04)", "Right joystick moved left" }, { "_joy1right", "!(*SWCHA & $08)", "Right joystick moved right" }, { "_joy1up", "!(*SWCHA & $01)", "Right joystick moved up" }, { "_joy1down", "!(*SWCHA & $02)", "Right joystick moved down" }, { "_joy1button", "!(*INPT5 & $80)", "Right joystick button pressed" }, // console switches: { "_select", "!(*SWCHB & $02)", "Game Select pressed" }, { "_reset", "!(*SWCHB & $01)", "Game Reset pressed" }, { "_color", "*SWCHB & $08", "Color/BW set to Color" }, { "_bw", "!(*SWCHB & $08)", "Color/BW set to BW" }, { "_diff0b", "!(*SWCHB & $40)", "Left diff. set to B (easy)" }, { "_diff0a", "*SWCHB & $40", "Left diff. set to A (hard)" }, { "_diff1b", "!(*SWCHB & $80)", "Right diff. set to B (easy)" }, { "_diff1a", "*SWCHB & $80", "Right diff. set to A (hard)" } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Names are defined here, but processed in YaccParser Debugger::PseudoRegister Debugger::ourPseudoRegisters[NUM_PSEUDO_REGS] = { { "_bank", "Currently selected bank" }, { "_cclocks", "Color clocks on current scanline" }, { "_cycleshi", "Higher 32 bits of number of cycles since emulation started" }, { "_cycleslo", "Lower 32 bits of number of cycles since emulation started" }, { "_fcount", "Number of frames since emulation started" }, { "_fcycles", "Number of cycles since frame started" }, { "_icycles", "Number of cycles of last instruction" }, { "_rwport", "Address at which a read from a write port occurred" }, { "_scan", "Current scanline count" }, { "_scycles", "Number of cycles in current scanline" }, { "_vblank", "Whether vertical blank is enabled (1 or 0)" }, { "_vsync", "Whether vertical sync is enabled (1 or 0)" } // CPU address access functions: /*{ "__lastread", "last CPU read address" }, { "__lastwrite", "last CPU write address" },*/ }; stella-5.1.1/src/debugger/Debugger.hxx000066400000000000000000000233731324334165500176500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DEBUGGER_HXX #define DEBUGGER_HXX class OSystem; class Console; class EventHandler; class TiaInfoWidget; class TiaOutputWidget; class TiaZoomWidget; class EditTextWidget; class RomWidget; class Expression; class PackedBitArray; class TrapArray; class PromptWidget; class ButtonWidget; class M6502; class System; class CartDebug; class CpuDebug; class RiotDebug; class TIADebug; class DebuggerParser; class RewindManager; #include #include "Base.hxx" #include "DialogContainer.hxx" #include "DebuggerDialog.hxx" #include "FrameBufferConstants.hxx" #include "bspf.hxx" using FunctionMap = std::map>; using FunctionDefMap = std::map; /** The base dialog for all debugging widgets in Stella. Also acts as the parent for all debugging operations in Stella (parser, 6502 debugger, etc). @author Stephen Anthony */ class Debugger : public DialogContainer { // Make these friend classes, to ease communications with the debugger // Although it isn't enforced, these classes should use accessor methods // directly, and not touch the instance variables friend class DebuggerParser; friend class EventHandler; friend class M6502; public: /** Create a new debugger parent object */ Debugger(OSystem& osystem, Console& console); virtual ~Debugger(); public: /** Initialize the debugger dialog container. */ void initialize(); /** Initialize the video subsystem wrt this class. */ FBInitStatus initializeVideo(); /** Wrapper method for EventHandler::enterDebugMode() for those classes that don't have access to EventHandler. @param message Message to display when entering debugger @param address An address associated with the message */ bool start(const string& message = "", int address = -1, bool read = true); bool startWithFatalError(const string& message = ""); /** Wrapper method for EventHandler::leaveDebugMode() for those classes that don't have access to EventHandler. */ void quit(bool exitrom); bool addFunction(const string& name, const string& def, Expression* exp, bool builtin = false); bool isBuiltinFunction(const string& name); bool delFunction(const string& name); const Expression& getFunction(const string& name) const; const string& getFunctionDef(const string& name) const; const FunctionDefMap getFunctionDefMap() const; string builtinHelp() const; /** Methods used by the command parser for tab-completion In this case, return completions from the function list */ void getCompletions(const char* in, StringList& list) const; /** The dialog/GUI associated with the debugger */ Dialog& dialog() const { return *myDialog; } /** The debugger subsystem responsible for all CPU state */ CpuDebug& cpuDebug() const { return *myCpuDebug; } /** The debugger subsystem responsible for all Cart RAM/ROM state */ CartDebug& cartDebug() const { return *myCartDebug; } /** The debugger subsystem responsible for all RIOT state */ RiotDebug& riotDebug() const { return *myRiotDebug; } /** The debugger subsystem responsible for all TIA state */ TIADebug& tiaDebug() const { return *myTiaDebug; } const GUI::Font& lfont() const { return myDialog->lfont(); } const GUI::Font& nlfont() const { return myDialog->nfont(); } DebuggerParser& parser() const { return *myParser; } PromptWidget& prompt() const { return myDialog->prompt(); } RomWidget& rom() const { return myDialog->rom(); } TiaOutputWidget& tiaOutput() const { return myDialog->tiaOutput(); } PackedBitArray& breakPoints() const; TrapArray& readTraps() const; TrapArray& writeTraps() const; /** Run the debugger command and return the result. */ const string run(const string& command); string autoExec(StringList* history); string showWatches(); /** Convert between string->integer and integer->string, taking into account the current base format. */ int stringToValue(const string& stringval); /* Convenience methods to get/set bit(s) in an 8-bit register */ static uInt8 set_bit(uInt8 input, uInt8 bit, bool on) { if(on) return uInt8(input | (1 << bit)); else return uInt8(input & ~(1 << bit)); } static void set_bits(uInt8 reg, BoolArray& bits) { bits.clear(); for(int i = 0; i < 8; ++i) { if(reg & (1<<(7-i))) bits.push_back(true); else bits.push_back(false); } } static uInt8 get_bits(const BoolArray& bits) { uInt8 result = 0x0; for(int i = 0; i < 8; ++i) if(bits[i]) result |= (1<<(7-i)); return result; } /** Invert given input if it differs from its previous value */ const string invIfChanged(int reg, int oldReg); /** This is used when we want the debugger from a class that can't receive the debugger object in any other way. It's basically a hack to prevent the need to pass debugger objects everywhere, but I feel it's better to place it here then in YaccParser (which technically isn't related to it at all). */ static Debugger& debugger() { return *myStaticDebugger; } /** Convenience methods to access peek/poke from System */ uInt8 peek(uInt16 addr, uInt8 flags = 0); uInt16 dpeek(uInt16 addr, uInt8 flags = 0); void poke(uInt16 addr, uInt8 value, uInt8 flags = 0); /** Convenience method to access the 6502 from System */ M6502& m6502() const; /** These are now exposed so Expressions can use them. */ int peekAsInt(int addr, uInt8 flags = 0); int dpeekAsInt(int addr, uInt8 flags = 0); int getAccessFlags(uInt16 addr) const; void setAccessFlags(uInt16 addr, uInt8 flags); void setBreakPoint(uInt16 bp, bool set); uInt32 getBaseAddress(uInt32 addr, bool read); bool patchROM(uInt16 addr, uInt8 value); /** Normally, accessing RAM or ROM during emulation can possibly trigger bankswitching or other inadvertent changes. However, when we're in the debugger, we'd like to inspect values without restriction. The read/write state must therefore be locked before accessing values, and unlocked for normal emulation to occur. */ void lockSystem(); void unlockSystem(); private: /** Save state of each debugger subsystem and, by default, mark all pages as clean (ie, turn off the dirty flag). */ void saveOldState(bool clearDirtyPages = true); /** Saves a rewind state with the given message. */ void addState(string rewindMsg); /** Set initial state before entering the debugger. */ void setStartState(); /** Set final state before leaving the debugger. */ void setQuitState(); int step(); int trace(); void nextScanline(int lines); void nextFrame(int frames); uInt16 rewindStates(const uInt16 numStates, string& message); uInt16 unwindStates(const uInt16 numStates, string& message); void toggleBreakPoint(uInt16 bp); bool breakPoint(uInt16 bp); void addReadTrap(uInt16 t); void addWriteTrap(uInt16 t); void addTrap(uInt16 t); void removeReadTrap(uInt16 t); void removeWriteTrap(uInt16 t); void removeTrap(uInt16 t); bool readTrap(uInt16 t); bool writeTrap(uInt16 t); void clearAllTraps(); // Set a bunch of RAM locations at once string setRAM(IntArray& args); void reset(); void clearAllBreakPoints(); void saveState(int state); void loadState(int state); private: Console& myConsole; System& mySystem; DebuggerDialog* myDialog; unique_ptr myParser; unique_ptr myCartDebug; unique_ptr myCpuDebug; unique_ptr myRiotDebug; unique_ptr myTiaDebug; static Debugger* myStaticDebugger; FunctionMap myFunctions; FunctionDefMap myFunctionDefs; // Dimensions of the entire debugger window uInt32 myWidth; uInt32 myHeight; // Various builtin functions and operations struct BuiltinFunction { string name, defn, help; }; struct PseudoRegister { string name, help; }; static const uInt32 NUM_BUILTIN_FUNCS = 18; static const uInt32 NUM_PSEUDO_REGS = 12; static BuiltinFunction ourBuiltinFunctions[NUM_BUILTIN_FUNCS]; static PseudoRegister ourPseudoRegisters[NUM_PSEUDO_REGS]; private: // rewind/unwind n states uInt16 windStates(uInt16 numStates, bool unwind, string& message); // update the rewind/unwind button state void updateRewindbuttons(const RewindManager& r); // Following constructors and assignment operators not supported Debugger() = delete; Debugger(const Debugger&) = delete; Debugger(Debugger&&) = delete; Debugger& operator=(const Debugger&) = delete; Debugger& operator=(Debugger&&) = delete; }; #endif stella-5.1.1/src/debugger/DebuggerExpressions.hxx000066400000000000000000000262461324334165500221150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DEBUGGER_EXPRESSIONS_HXX #define DEBUGGER_EXPRESSIONS_HXX #include #include "bspf.hxx" #include "CartDebug.hxx" #include "CpuDebug.hxx" #include "TIADebug.hxx" #include "Debugger.hxx" #include "Expression.hxx" /** All expressions currently supported by the debugger. @author B. Watson and Stephen Anthony */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class BinAndExpression : public Expression { public: BinAndExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() & myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class BinNotExpression : public Expression { public: BinNotExpression(Expression* left) : Expression(left) { } Int32 evaluate() const override { return ~(myLHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class BinOrExpression : public Expression { public: BinOrExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() | myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class BinXorExpression : public Expression { public: BinXorExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() ^ myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ByteDerefExpression : public Expression { public: ByteDerefExpression(Expression* left): Expression(left) { } Int32 evaluate() const override { return Debugger::debugger().peek(myLHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ByteDerefOffsetExpression : public Expression { public: ByteDerefOffsetExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return Debugger::debugger().peek(myLHS->evaluate() + myRHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ConstExpression : public Expression { public: ConstExpression(const int value) : Expression(), myValue(value) { } Int32 evaluate() const override { return myValue; } private: int myValue; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class CpuMethodExpression : public Expression { public: CpuMethodExpression(CpuMethod method) : Expression(), myMethod(std::mem_fn(method)) { } Int32 evaluate() const override { return myMethod(Debugger::debugger().cpuDebug()); } private: std::function myMethod; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class DivExpression : public Expression { public: DivExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { int denom = myRHS->evaluate(); return denom == 0 ? 0 : myLHS->evaluate() / denom; } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class EqualsExpression : public Expression { public: EqualsExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() == myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class EquateExpression : public Expression { public: EquateExpression(const string& label) : Expression(), myLabel(label) { } Int32 evaluate() const override { return Debugger::debugger().cartDebug().getAddress(myLabel); } private: string myLabel; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class FunctionExpression : public Expression { public: FunctionExpression(const string& label) : Expression(), myLabel(label) { } Int32 evaluate() const override { return Debugger::debugger().getFunction(myLabel).evaluate(); } private: string myLabel; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class GreaterEqualsExpression : public Expression { public: GreaterEqualsExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() >= myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class GreaterExpression : public Expression { public: GreaterExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() > myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class HiByteExpression : public Expression { public: HiByteExpression(Expression* left) : Expression(left) { } Int32 evaluate() const override { return 0xff & (myLHS->evaluate() >> 8); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LessEqualsExpression : public Expression { public: LessEqualsExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() <= myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LessExpression : public Expression { public: LessExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() < myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LoByteExpression : public Expression { public: LoByteExpression(Expression* left) : Expression(left) { } Int32 evaluate() const override { return 0xff & myLHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LogAndExpression : public Expression { public: LogAndExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() && myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LogNotExpression : public Expression { public: LogNotExpression(Expression* left) : Expression(left) { } Int32 evaluate() const override { return !(myLHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class LogOrExpression : public Expression { public: LogOrExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() || myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class MinusExpression : public Expression { public: MinusExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() - myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ModExpression : public Expression { public: ModExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { int rhs = myRHS->evaluate(); return rhs == 0 ? 0 : myLHS->evaluate() % rhs; } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class MultExpression : public Expression { public: MultExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() * myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class NotEqualsExpression : public Expression { public: NotEqualsExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() != myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class PlusExpression : public Expression { public: PlusExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() + myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class CartMethodExpression : public Expression { public: CartMethodExpression(CartMethod method) : Expression(), myMethod(std::mem_fn(method)) { } Int32 evaluate() const override { return myMethod(Debugger::debugger().cartDebug()); } private: std::function myMethod; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ShiftLeftExpression : public Expression { public: ShiftLeftExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() << myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class ShiftRightExpression : public Expression { public: ShiftRightExpression(Expression* left, Expression* right) : Expression(left, right) { } Int32 evaluate() const override { return myLHS->evaluate() >> myRHS->evaluate(); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class TiaMethodExpression : public Expression { public: TiaMethodExpression(TiaMethod method) : Expression(), myMethod(std::mem_fn(method)) { } Int32 evaluate() const override { return myMethod(Debugger::debugger().tiaDebug()); } private: std::function myMethod; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class UnaryMinusExpression : public Expression { public: UnaryMinusExpression(Expression* left) : Expression(left) { } Int32 evaluate() const override { return -(myLHS->evaluate()); } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class WordDerefExpression : public Expression { public: WordDerefExpression(Expression* left) : Expression(left) { } Int32 evaluate() const override { return Debugger::debugger().dpeekAsInt(myLHS->evaluate()); } }; #endif stella-5.1.1/src/debugger/DebuggerParser.cxx000066400000000000000000002461211324334165500210160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "CpuDebug.hxx" #include "RiotDebug.hxx" #include "TIADebug.hxx" #include "TiaOutputWidget.hxx" #include "DebuggerParser.hxx" #include "YaccParser.hxx" #include "M6502.hxx" #include "Expression.hxx" #include "FSNode.hxx" #include "Settings.hxx" #include "PromptWidget.hxx" #include "RomWidget.hxx" #include "ProgressDialog.hxx" #include "PackedBitArray.hxx" #include "Vec.hxx" #include "Base.hxx" using Common::Base; using std::hex; using std::dec; using std::setfill; using std::setw; using std::right; #ifdef CHEATCODE_SUPPORT #include "Cheat.hxx" #include "CheatManager.hxx" #endif #include "DebuggerParser.hxx" // TODO - use C++ streams instead of nasty C-strings and pointers // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerParser::DebuggerParser(Debugger& d, Settings& s) : debugger(d), settings(s), argCount(0), execDepth(0), execPrefix("") { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // main entry point: PromptWidget calls this method. string DebuggerParser::run(const string& command) { #if 0 // this was our parser test code. Left for reference. static Expression *lastExpression; // special case: parser testing if(strncmp(command.c_str(), "expr ", 5) == 0) { delete lastExpression; commandResult = "parser test: status=="; int status = YaccParser::parse(command.c_str() + 5); commandResult += debugger.valueToString(status); commandResult += ", result=="; if(status == 0) { lastExpression = YaccParser::getResult(); commandResult += debugger.valueToString(lastExpression->evaluate()); } else { // delete lastExpression; // NO! lastExpression isn't valid (not 0 either) // It's the result of casting the last token // to Expression* (because of yacc's union). // As such, we can't and don't need to delete it // (However, it means yacc leaks memory on error) commandResult += "ERROR - "; commandResult += YaccParser::errorMessage(); } return commandResult; } if(command == "expr") { if(lastExpression) commandResult = "result==" + debugger.valueToString(lastExpression->evaluate()); else commandResult = "no valid expr"; return commandResult; } #endif string verb; getArgs(command, verb); commandResult.str(""); for(int i = 0; i < kNumCommands; ++i) { if(BSPF::equalsIgnoreCase(verb, commands[i].cmdString)) { if(validateArgs(i)) { myCommand = i; commands[i].executor(this); } if(commands[i].refreshRequired) debugger.myBaseDialog->loadConfig(); return commandResult.str(); } } return red("No such command (try \"help\")"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string DebuggerParser::exec(const FilesystemNode& file, StringList* history) { if(file.exists()) { ifstream in(file.getPath()); if(!in.is_open()) return red("script file \'" + file.getShortPath() + "\' not found"); ostringstream buf; int count = 0; string command; while( !in.eof() ) { if(!getline(in, command)) break; run(command); if (history != nullptr) history->push_back(command); count++; } buf << "\nExecuted " << count << " commands from \"" << file.getShortPath() << "\""; return buf.str(); } else return red("script file \'" + file.getShortPath() + "\' not found"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerParser::outputCommandError(const string& errorMsg, int command) { string example = commands[command].extendedDesc.substr(commands[command].extendedDesc.find("Example:")); commandResult << red(errorMsg); if(!example.empty()) commandResult << endl << example; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Completion-related stuff: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerParser::getCompletions(const char* in, StringList& completions) const { // cerr << "Attempting to complete \"" << in << "\"" << endl; for(int i = 0; i < kNumCommands; ++i) { if(BSPF::matches(commands[i].cmdString, in)) completions.push_back(commands[i].cmdString); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Evaluate expression. Expressions always evaluate to a 16-bit value if // they're valid, or -1 if they're not. // decipher_arg may be called by the GUI as needed. It is also called // internally by DebuggerParser::run() int DebuggerParser::decipher_arg(const string& str) { bool derefByte=false, derefWord=false, lobyte=false, hibyte=false, bin=false, dec=false; int result; string arg = str; Base::Format defaultBase = Base::format(); if(defaultBase == Base::F_2) { bin=true; dec=false; } else if(defaultBase == Base::F_10) { bin=false; dec=true; } else { bin=false; dec=false; } if(arg.substr(0, 1) == "*") { derefByte = true; arg.erase(0, 1); } else if(arg.substr(0, 1) == "@") { derefWord = true; arg.erase(0, 1); } if(arg.substr(0, 1) == "<") { lobyte = true; arg.erase(0, 1); } else if(arg.substr(0, 1) == ">") { hibyte = true; arg.erase(0, 1); } if(arg.substr(0, 1) == "\\") { dec = false; bin = true; arg.erase(0, 1); } else if(arg.substr(0, 1) == "#") { dec = true; bin = false; arg.erase(0, 1); } else if(arg.substr(0, 1) == "$") { dec = false; bin = false; arg.erase(0, 1); } // Special cases (registers): const CpuState& state = static_cast(debugger.cpuDebug().getState()); if(arg == "a" && str != "$a") result = state.A; else if(arg == "x") result = state.X; else if(arg == "y") result = state.Y; else if(arg == "p") result = state.PS; else if(arg == "s") result = state.SP; else if(arg == "pc" || arg == ".") result = state.PC; else { // Not a special, must be a regular arg: check for label first const char* a = arg.c_str(); result = debugger.cartDebug().getAddress(arg); if(result < 0) { // if not label, must be a number if(bin) { // treat as binary result = 0; while(*a != '\0') { result <<= 1; switch(*a++) { case '1': result++; break; case '0': break; default: return -1; } } } else if(dec) { result = 0; while(*a != '\0') { int digit = (*a++) - '0'; if(digit < 0 || digit > 9) return -1; result = (result * 10) + digit; } } else { // must be hex. result = 0; while(*a != '\0') { int hex = -1; char d = *a++; if(d >= '0' && d <= '9') hex = d - '0'; else if(d >= 'a' && d <= 'f') hex = d - 'a' + 10; else if(d >= 'A' && d <= 'F') hex = d - 'A' + 10; if(hex < 0) return -1; result = (result << 4) + hex; } } } } if(lobyte) result &= 0xff; else if(hibyte) result = (result >> 8) & 0xff; // dereference if we're supposed to: if(derefByte) result = debugger.peek(result); if(derefWord) result = debugger.dpeek(result); return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string DebuggerParser::showWatches() { ostringstream buf; for(uInt32 i = 0; i < myWatches.size(); ++i) { if(myWatches[i] != "") { // Clear the args, since we're going to pass them to eval() argStrings.clear(); args.clear(); argCount = 1; argStrings.push_back(myWatches[i]); args.push_back(decipher_arg(argStrings[0])); if(args[0] < 0) buf << "BAD WATCH " << (i+1) << ": " << argStrings[0] << endl; else buf << " watch #" << (i+1) << " (" << argStrings[0] << ") -> " << eval() << endl; } } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Private methods below // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DebuggerParser::getArgs(const string& command, string& verb) { int state = kIN_COMMAND, i = 0, length = int(command.length()); string curArg = ""; verb = ""; argStrings.clear(); args.clear(); // cerr << "Parsing \"" << command << "\"" << ", length = " << command.length() << endl; // First, pick apart string into space-separated tokens. // The first token is the command verb, the rest go in an array do { char c = command[i++]; switch(state) { case kIN_COMMAND: if(c == ' ') state = kIN_SPACE; else verb += c; break; case kIN_SPACE: if(c == '{') state = kIN_BRACE; else if(c != ' ') { state = kIN_ARG; curArg += c; } break; case kIN_BRACE: if(c == '}') { state = kIN_SPACE; argStrings.push_back(curArg); // cerr << "{" << curArg << "}" << endl; curArg = ""; } else { curArg += c; } break; case kIN_ARG: if(c == ' ') { state = kIN_SPACE; argStrings.push_back(curArg); curArg = ""; } else { curArg += c; } break; } // switch(state) } while(i < length); // Take care of the last argument, if there is one if(curArg != "") argStrings.push_back(curArg); argCount = uInt32(argStrings.size()); for(uInt32 arg = 0; arg < argCount; ++arg) { if(!YaccParser::parse(argStrings[arg].c_str())) { unique_ptr expr(YaccParser::getResult()); args.push_back(expr->evaluate()); } else args.push_back(-1); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DebuggerParser::validateArgs(int cmd) { // cerr << "entering validateArgs(" << cmd << ")" << endl; bool required = commands[cmd].parmsRequired; parameters* p = commands[cmd].parms; if(argCount == 0) { if(required) { commandResult.str(); outputCommandError("missing required argument(s)", cmd); return false; // needed args. didn't get 'em. } else return true; // no args needed, no args got } // Figure out how many arguments are required by the command uInt32 count = 0, argRequiredCount = 0; while(*p != kARG_END_ARGS && *p != kARG_MULTI_BYTE) { count++; p++; } // Evil hack: some commands intentionally take multiple arguments // In this case, the required number of arguments is unbounded argRequiredCount = (*p == kARG_END_ARGS) ? count : argCount; p = commands[cmd].parms; uInt32 curCount = 0; do { if(curCount >= argCount) break; uInt32 curArgInt = args[curCount]; string& curArgStr = argStrings[curCount]; switch(*p) { case kARG_DWORD: #if 0 // TODO - do we need error checking at all here? if(curArgInt > 0xffffffff) { commandResult.str(red("invalid word argument (must be 0-$ffffffff)")); return false; } #endif break; case kARG_WORD: if(curArgInt > 0xffff) { commandResult.str(red("invalid word argument (must be 0-$ffff)")); return false; } break; case kARG_BYTE: if(curArgInt > 0xff) { commandResult.str(red("invalid byte argument (must be 0-$ff)")); return false; } break; case kARG_BOOL: if(curArgInt != 0 && curArgInt != 1) { commandResult.str(red("invalid boolean argument (must be 0 or 1)")); return false; } break; case kARG_BASE_SPCL: if(curArgInt != 2 && curArgInt != 10 && curArgInt != 16 && curArgStr != "hex" && curArgStr != "dec" && curArgStr != "bin") { commandResult.str(red("invalid base (must be #2, #10, #16, \"bin\", \"dec\", or \"hex\")")); return false; } break; case kARG_LABEL: case kARG_FILE: break; // TODO: validate these (for now any string's allowed) case kARG_MULTI_BYTE: case kARG_MULTI_WORD: break; // FIXME: validate these (for now, any number's allowed) case kARG_END_ARGS: break; } curCount++; p++; } while(*p != kARG_END_ARGS && curCount < argRequiredCount); /* cerr << "curCount = " << curCount << endl << "argRequiredCount = " << argRequiredCount << endl << "*p = " << *p << endl << endl; */ if(curCount < argRequiredCount) { commandResult.str(); outputCommandError("missing required argument(s)", cmd); return false; } else if(argCount > curCount) { commandResult.str(); outputCommandError("too many arguments", cmd); return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string DebuggerParser::eval() { ostringstream buf; for(uInt32 i = 0; i < argCount; ++i) { if(args[i] < 0x10000) { string rlabel = debugger.cartDebug().getLabel(args[i], true); string wlabel = debugger.cartDebug().getLabel(args[i], false); bool validR = rlabel != "" && rlabel[0] != '$', validW = wlabel != "" && wlabel[0] != '$'; if(validR && validW) { if(rlabel == wlabel) buf << rlabel << "(R/W): "; else buf << rlabel << "(R) / " << wlabel << "(W): "; } else if(validR) buf << rlabel << "(R): "; else if(validW) buf << wlabel << "(W): "; } buf << "$" << Base::toString(args[i], Base::F_16); if(args[i] < 0x10000) buf << " %" << Base::toString(args[i], Base::F_2); buf << " #" << int(args[i]); if(i != argCount - 1) buf << endl; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerParser::listTraps(bool listCond) { StringList names = debugger.m6502().getCondTrapNames(); commandResult << (listCond ? "trapifs:" : "traps:") << endl; for(uInt32 i = 0; i < names.size(); i++) { bool hasCond = names[i] != ""; if(hasCond == listCond) { commandResult << Base::toString(i) << ": "; if(myTraps[i]->read && myTraps[i]->write) commandResult << "read|write"; else if(myTraps[i]->read) commandResult << "read "; else if(myTraps[i]->write) commandResult << " write"; else commandResult << "none"; if(hasCond) commandResult << " " << names[i]; commandResult << " " << debugger.cartDebug().getLabel(myTraps[i]->begin, true, 4); if(myTraps[i]->begin != myTraps[i]->end) commandResult << " " << debugger.cartDebug().getLabel(myTraps[i]->end, true, 4); commandResult << trapStatus(*myTraps[i]); commandResult << " + mirrors"; if(i != (names.size() - 1)) commandResult << endl; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string DebuggerParser::trapStatus(const Trap& trap) { stringstream result; string lblb = debugger.cartDebug().getLabel(trap.begin, !trap.write); string lble = debugger.cartDebug().getLabel(trap.end, !trap.write); if(lblb != "") { result << " ("; result << lblb; } if(trap.begin != trap.end) { if(lble != "") { if (lblb != "") result << " "; else result << " ("; result << lble; } } if (lblb != "" || lble != "") result << ")"; return result.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string DebuggerParser::saveScriptFile(string file) { // Append 'script' extension when necessary if(file.find_last_of('.') == string::npos) file += ".script"; FilesystemNode node(debugger.myOSystem.defaultSaveDir() + file); ofstream out(node.getPath()); if(!out.is_open()) return "Unable to save script to " + node.getShortPath(); FunctionDefMap funcs = debugger.getFunctionDefMap(); for(const auto& f: funcs) if (!debugger.isBuiltinFunction(f.first)) out << "function " << f.first << " {" << f.second << "}" << endl; for(const auto& w: myWatches) out << "watch " << w << endl; for(uInt32 i = 0; i < 0x10000; ++i) if(debugger.breakPoint(i)) out << "break " << Base::toString(i) << endl; StringList conds = debugger.m6502().getCondBreakNames(); for(const auto& cond : conds) out << "breakif {" << cond << "}" << endl; conds = debugger.m6502().getCondSaveStateNames(); for(const auto& cond : conds) out << "savestateif {" << cond << "}" << endl; StringList names = debugger.m6502().getCondTrapNames(); for(uInt32 i = 0; i < myTraps.size(); ++i) { bool read = myTraps[i]->read; bool write = myTraps[i]->write; bool hasCond = names[i] != ""; if(read && write) out << "trap"; else if(read) out << "trapread"; else if(write) out << "trapwrite"; if(hasCond) out << "if {" << names[i] << "}"; out << " " << Base::toString(myTraps[i]->begin); if(myTraps[i]->begin != myTraps[i]->end) out << " " << Base::toString(myTraps[i]->end); out << endl; } return "saved " + node.getShortPath() + " OK"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // executor methods for commands[] array. All are void, no args. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "a" void DebuggerParser::executeA() { debugger.cpuDebug().setA(uInt8(args[0])); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "base" void DebuggerParser::executeBase() { if(args[0] == 2 || argStrings[0] == "bin") Base::setFormat(Base::F_2); else if(args[0] == 10 || argStrings[0] == "dec") Base::setFormat(Base::F_10); else if(args[0] == 16 || argStrings[0] == "hex") Base::setFormat(Base::F_16); commandResult << "default number base set to "; switch(Base::format()) { case Base::F_2: commandResult << "#2/bin"; break; case Base::F_10: commandResult << "#10/dec"; break; case Base::F_16: commandResult << "#16/hex"; break; default: commandResult << red("UNKNOWN"); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "break" void DebuggerParser::executeBreak() { uInt16 bp; if(argCount == 0) bp = debugger.cpuDebug().pc(); else bp = args[0]; debugger.toggleBreakPoint(bp); debugger.rom().invalidate(); if(debugger.breakPoint(bp)) commandResult << "set"; else commandResult << "cleared"; commandResult << " breakpoint at " << Base::toString(bp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "breakif" void DebuggerParser::executeBreakif() { int res = YaccParser::parse(argStrings[0].c_str()); if(res == 0) { string condition = argStrings[0]; for(uInt32 i = 0; i < debugger.m6502().getCondBreakNames().size(); i++) { if(condition == debugger.m6502().getCondBreakNames()[i]) { args[0] = i; executeDelbreakif(); return; } } uInt32 ret = debugger.m6502().addCondBreak( YaccParser::getResult(), argStrings[0] ); commandResult << "added breakif " << Base::toString(ret); } else commandResult << red("invalid expression"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "c" void DebuggerParser::executeC() { if(argCount == 0) debugger.cpuDebug().toggleC(); else if(argCount == 1) debugger.cpuDebug().setC(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "cheat" // (see Stella manual for different cheat types) void DebuggerParser::executeCheat() { #ifdef CHEATCODE_SUPPORT if(argCount == 0) { outputCommandError("missing cheat code", myCommand); return; } for(uInt32 arg = 0; arg < argCount; ++arg) { const string& cheat = argStrings[arg]; if(debugger.myOSystem.cheat().add("DBG", cheat)) commandResult << "cheat code " << cheat << " enabled" << endl; else commandResult << red("invalid cheat code ") << cheat << endl; } #else commandResult << red("Cheat support not enabled\n"); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "clearbreaks" void DebuggerParser::executeClearbreaks() { debugger.clearAllBreakPoints(); debugger.m6502().clearCondBreaks(); commandResult << "all breakpoints cleared"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "clearconfig" void DebuggerParser::executeClearconfig() { if(argCount == 1) commandResult << debugger.cartDebug().clearConfig(args[0]); else commandResult << debugger.cartDebug().clearConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "clearbreaks" void DebuggerParser::executeClearsavestateifs() { debugger.m6502().clearCondSaveStates(); commandResult << "all savestate points cleared"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "cleartraps" void DebuggerParser::executeCleartraps() { debugger.clearAllTraps(); debugger.m6502().clearCondTraps(); myTraps.clear(); commandResult << "all traps cleared"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "clearwatches" void DebuggerParser::executeClearwatches() { myWatches.clear(); commandResult << "all watches cleared"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "cls" void DebuggerParser::executeCls() { debugger.prompt().clearScreen(); commandResult << ""; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "code" void DebuggerParser::executeCode() { if(argCount != 2) { outputCommandError("specify start and end of range only", myCommand); return; } else if(args[1] < args[0]) { commandResult << red("start address must be <= end address"); return; } bool result = debugger.cartDebug().addDirective( CartDebug::CODE, args[0], args[1]); commandResult << (result ? "added" : "removed") << " CODE directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "colortest" void DebuggerParser::executeColortest() { commandResult << "test color: " << char((args[0]>>1) | 0x80) << inverse(" "); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "d" void DebuggerParser::executeD() { if(argCount == 0) debugger.cpuDebug().toggleD(); else if(argCount == 1) debugger.cpuDebug().setD(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "data" void DebuggerParser::executeData() { if(argCount != 2) { outputCommandError("specify start and end of range only", myCommand); return; } else if(args[1] < args[0]) { commandResult << red("start address must be <= end address"); return; } bool result = debugger.cartDebug().addDirective( CartDebug::DATA, args[0], args[1]); commandResult << (result ? "added" : "removed") << " DATA directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "debugcolors" void DebuggerParser::executeDebugColors() { commandResult << debugger.tiaDebug().debugColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "define" void DebuggerParser::executeDefine() { // TODO: check if label already defined? debugger.cartDebug().addLabel(argStrings[0], args[1]); debugger.rom().invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "delbreakif" void DebuggerParser::executeDelbreakif() { if (debugger.m6502().delCondBreak(args[0])) commandResult << "removed breakif " << Base::toString(args[0]); else commandResult << red("no such breakif"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "delfunction" void DebuggerParser::executeDelfunction() { if(debugger.delFunction(argStrings[0])) commandResult << "removed function " << argStrings[0]; else commandResult << "function " << argStrings[0] << " built-in or not found"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "delsavestateif" void DebuggerParser::executeDelsavestateif() { if(debugger.m6502().delCondSaveState(args[0])) commandResult << "removed savestateif " << Base::toString(args[0]); else commandResult << red("no such savestateif"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "deltrap" void DebuggerParser::executeDeltrap() { int index = args[0]; if(debugger.m6502().delCondTrap(index)) { for(uInt32 addr = myTraps[index]->begin; addr <= myTraps[index]->end; ++addr) executeTrapRW(addr, myTraps[index]->read, myTraps[index]->write, false); // @sa666666: please check this: Vec::removeAt(myTraps, index); commandResult << "removed trap " << Base::toString(index); } else commandResult << red("no such trap"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "delwatch" void DebuggerParser::executeDelwatch() { int which = args[0] - 1; if(which >= 0 && which < int(myWatches.size())) { Vec::removeAt(myWatches, which); commandResult << "removed watch"; } else commandResult << red("no such watch"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "disasm" void DebuggerParser::executeDisasm() { int start, lines = 20; if(argCount == 0) { start = debugger.cpuDebug().pc(); } else if(argCount == 1) { start = args[0]; } else if(argCount == 2) { start = args[0]; lines = args[1]; } else { outputCommandError("wrong number of arguments", myCommand); return; } commandResult << debugger.cartDebug().disassemble(start, lines); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "dump" void DebuggerParser::executeDump() { auto dump = [&](ostream& os, int start, int end) { for(int i = start; i <= end; i += 16) { // Print label every 16 bytes os << Base::toString(i) << ": "; for(int j = i; j < i+16 && j <= end; ++j) { os << Base::toString(debugger.peek(j)) << " "; if(j == i+7 && j != end) os << "- "; } os << endl; } }; // Error checking if( argCount == 0 || argCount > 3) { outputCommandError("wrong number of arguments", myCommand); return; } if(argCount > 1 && args[1] < args[0]) { commandResult << red("start address must be <= end address"); return; } if(argCount == 1) dump(commandResult, args[0], args[0] + 127); else if(argCount == 2 || args[2] == 0) dump(commandResult, args[0], args[1]); else { ostringstream file; file << debugger.myOSystem.defaultSaveDir() << debugger.myOSystem.console().properties().get(Cartridge_Name) << "_dbg_"; if(execDepth > 0) { file << execPrefix; } else { file << std::hex << std::setw(8) << std::setfill('0') << uInt32(debugger.myOSystem.getTicks() / 1000); } file << ".dump"; FilesystemNode node(file.str()); // cout << "dump " << args[0] << "-" << args[1] << " to " << file.str() << endl; ofstream ofs(node.getPath(), ofstream::out | ofstream::app); if(!ofs.is_open()) { outputCommandError("Unable to append dump to file " + node.getShortPath(), myCommand); return; } if((args[2] & 0x07) != 0) commandResult << "dumped "; if((args[2] & 0x01) != 0) { // dump memory dump(ofs, args[0], args[1]); commandResult << "bytes from $" << hex << args[0] << " to $" << hex << args[1]; if((args[2] & 0x06) != 0) commandResult << ", "; } if((args[2] & 0x02) != 0) { // dump CPU state CpuDebug& cpu = debugger.cpuDebug(); ofs << " PC SP A X Y - - N V B D I Z C -\n"; ofs << "XC: " << Base::toString(cpu.pc() & 0xff) << " " // PC lsb << Base::toString(cpu.pc() >> 8) << " " // PC msb << Base::toString(cpu.sp()) << " " // SP << Base::toString(cpu.a()) << " " // A << Base::toString(cpu.x()) << " " // X << Base::toString(cpu.y()) << " " // Y << Base::toString(0) << " " // unused << Base::toString(0) << " - " // unused << Base::toString(cpu.n()) << " " // N (flag) << Base::toString(cpu.v()) << " " // V (flag) << Base::toString(cpu.b()) << " " // B (flag) << Base::toString(cpu.d()) << " " // D (flag) << Base::toString(cpu.i()) << " " // I (flag) << Base::toString(cpu.z()) << " " // Z (flag) << Base::toString(cpu.c()) << " " // C (flag) << Base::toString(0) << " " // unused << endl; commandResult << "CPU state"; if((args[2] & 0x04) != 0) commandResult << ", "; } if((args[2] & 0x04) != 0) { // dump SWCHx/INPTx state ofs << " SWA - SWB - IT - - - I0 I1 I2 I3 I4 I5 - -\n"; ofs << "XS: " << Base::toString(debugger.peek(0x280)) << " " // SWCHA << Base::toString(0) << " " // unused << Base::toString(debugger.peek(0x282)) << " " // SWCHB << Base::toString(0) << " " // unused << Base::toString(debugger.peek(0x284)) << " " // INTIM << Base::toString(0) << " " // unused << Base::toString(0) << " " // unused << Base::toString(0) << " - " // unused << Base::toString(debugger.peek(TIARegister::INPT0)) << " " << Base::toString(debugger.peek(TIARegister::INPT1)) << " " << Base::toString(debugger.peek(TIARegister::INPT2)) << " " << Base::toString(debugger.peek(TIARegister::INPT3)) << " " << Base::toString(debugger.peek(TIARegister::INPT4)) << " " << Base::toString(debugger.peek(TIARegister::INPT5)) << " " << Base::toString(0) << " " // unused << Base::toString(0) << " " // unused << endl; commandResult << "switches and fire buttons"; } if((args[2] & 0x07) != 0) commandResult << " to file " << node.getShortPath(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "exec" void DebuggerParser::executeExec() { // Append 'script' extension when necessary string file = argStrings[0]; if(file.find_last_of('.') == string::npos) file += ".script"; FilesystemNode node(file); if (!node.exists()) { node = FilesystemNode(debugger.myOSystem.defaultSaveDir() + file); } if (argCount == 2) { execPrefix = argStrings[1]; } else { ostringstream prefix; prefix << std::hex << std::setw(8) << std::setfill('0') << uInt32(debugger.myOSystem.getTicks()/1000); execPrefix = prefix.str(); } execDepth++; commandResult << exec(node); execDepth--; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "exitrom" void DebuggerParser::executeExitRom() { debugger.quit(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "frame" void DebuggerParser::executeFrame() { int count = 1; if(argCount != 0) count = args[0]; debugger.nextFrame(count); commandResult << "advanced " << dec << count << " frame(s)"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "function" void DebuggerParser::executeFunction() { if(args[0] >= 0) { commandResult << red("name already in use"); return; } int res = YaccParser::parse(argStrings[1].c_str()); if(res == 0) { debugger.addFunction(argStrings[0], argStrings[1], YaccParser::getResult()); commandResult << "added function " << argStrings[0] << " -> " << argStrings[1]; } else commandResult << red("invalid expression"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "gfx" void DebuggerParser::executeGfx() { if(argCount != 2) { outputCommandError("specify start and end of range only", myCommand); return; } else if(args[1] < args[0]) { commandResult << red("start address must be <= end address"); return; } bool result = debugger.cartDebug().addDirective( CartDebug::GFX, args[0], args[1]); commandResult << (result ? "added" : "removed") << " GFX directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "help" void DebuggerParser::executeHelp() { if(argCount == 0) // normal help, show all commands { // Find length of longest command uInt16 clen = 0; for(int i = 0; i < kNumCommands; ++i) { uInt16 len = commands[i].cmdString.length(); if(len > clen) clen = len; } commandResult << setfill(' '); for(int i = 0; i < kNumCommands; ++i) commandResult << setw(clen) << right << commands[i].cmdString << " - " << commands[i].description << endl; commandResult << debugger.builtinHelp(); } else // get help for specific command { for(int i = 0; i < kNumCommands; ++i) { if(argStrings[0] == commands[i].cmdString) { commandResult << " " << red(commands[i].description) << endl << commands[i].extendedDesc; break; } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy0up" void DebuggerParser::executeJoy0Up() { Controller& controller = debugger.riotDebug().controller(Controller::Left); if(argCount == 0) controller.set(Controller::One, !controller.read(Controller::One)); else if(argCount == 1) controller.set(Controller::One, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy0down" void DebuggerParser::executeJoy0Down() { Controller& controller = debugger.riotDebug().controller(Controller::Left); if(argCount == 0) controller.set(Controller::Two, !controller.read(Controller::Two)); else if(argCount == 1) controller.set(Controller::Two, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy0left" void DebuggerParser::executeJoy0Left() { Controller& controller = debugger.riotDebug().controller(Controller::Left); if(argCount == 0) controller.set(Controller::Three, !controller.read(Controller::Three)); else if(argCount == 1) controller.set(Controller::Three, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy0right" void DebuggerParser::executeJoy0Right() { Controller& controller = debugger.riotDebug().controller(Controller::Left); if(argCount == 0) controller.set(Controller::Four, !controller.read(Controller::Four)); else if(argCount == 1) controller.set(Controller::Four, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy0fire" void DebuggerParser::executeJoy0Fire() { Controller& controller = debugger.riotDebug().controller(Controller::Left); if(argCount == 0) controller.set(Controller::Six, !controller.read(Controller::Six)); else if(argCount == 1) controller.set(Controller::Six, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy1up" void DebuggerParser::executeJoy1Up() { Controller& controller = debugger.riotDebug().controller(Controller::Right); if(argCount == 0) controller.set(Controller::One, !controller.read(Controller::One)); else if(argCount == 1) controller.set(Controller::One, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy1down" void DebuggerParser::executeJoy1Down() { Controller& controller = debugger.riotDebug().controller(Controller::Right); if(argCount == 0) controller.set(Controller::Two, !controller.read(Controller::Two)); else if(argCount == 1) controller.set(Controller::Two, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy1left" void DebuggerParser::executeJoy1Left() { Controller& controller = debugger.riotDebug().controller(Controller::Right); if(argCount == 0) controller.set(Controller::Three, !controller.read(Controller::Three)); else if(argCount == 1) controller.set(Controller::Three, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy1right" void DebuggerParser::executeJoy1Right() { Controller& controller = debugger.riotDebug().controller(Controller::Right); if(argCount == 0) controller.set(Controller::Four, !controller.read(Controller::Four)); else if(argCount == 1) controller.set(Controller::Four, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "joy1fire" void DebuggerParser::executeJoy1Fire() { Controller& controller = debugger.riotDebug().controller(Controller::Right); if(argCount == 0) controller.set(Controller::Six, !controller.read(Controller::Six)); else if(argCount == 1) controller.set(Controller::Six, args[0] != 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "jump" void DebuggerParser::executeJump() { int line = -1; int address = args[0]; // The specific address we want may not exist (it may be part of a data section) // If so, scroll backward a little until we find it while(((line = debugger.cartDebug().addressToLine(address)) == -1) && (address >= 0)) address--; if(line >= 0 && address >= 0) { debugger.rom().scrollTo(line); commandResult << "disassembly scrolled to address $" << Base::HEX4 << address; } else commandResult << "address $" << Base::HEX4 << args[0] << " doesn't exist"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "listbreaks" void DebuggerParser::executeListbreaks() { ostringstream buf; int count = 0; for(uInt32 i = 0; i <= 0xffff; ++i) { if(debugger.breakPoints().isSet(i)) { buf << debugger.cartDebug().getLabel(i, true, 4) << " "; if(! (++count % 8) ) buf << endl; } } if(count) commandResult << "breaks:" << endl << buf.str(); StringList conds = debugger.m6502().getCondBreakNames(); if(conds.size() > 0) { if(count) commandResult << endl; commandResult << "breakifs:" << endl; for(uInt32 i = 0; i < conds.size(); i++) { commandResult << Base::toString(i) << ": " << conds[i]; if(i != (conds.size() - 1)) commandResult << endl; } } if(commandResult.str() == "") commandResult << "no breakpoints set"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "listconfig" void DebuggerParser::executeListconfig() { if(argCount == 1) commandResult << debugger.cartDebug().listConfig(args[0]); else commandResult << debugger.cartDebug().listConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "listfunctions" void DebuggerParser::executeListfunctions() { const FunctionDefMap& functions = debugger.getFunctionDefMap(); if(functions.size() > 0) { for(const auto& iter: functions) commandResult << iter.first << " -> " << iter.second << endl; } else commandResult << "no user-defined functions"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "listsavestateifs" void DebuggerParser::executeListsavestateifs() { ostringstream buf; int count = 0; StringList conds = debugger.m6502().getCondSaveStateNames(); if(conds.size() > 0) { if(count) commandResult << endl; commandResult << "savestateif:" << endl; for(uInt32 i = 0; i < conds.size(); i++) { commandResult << Base::toString(i) << ": " << conds[i]; if(i != (conds.size() - 1)) commandResult << endl; } } if(commandResult.str() == "") commandResult << "no savestateifs defined"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "listtraps" void DebuggerParser::executeListtraps() { StringList names = debugger.m6502().getCondTrapNames(); if(myTraps.size() != names.size()) { commandResult << "Internal error! Different trap sizes."; return; } if (names.size() > 0) { bool trapFound = false, trapifFound = false; for(uInt32 i = 0; i < names.size(); i++) if(names[i] == "") trapFound = true; else trapifFound = true; if(trapFound) listTraps(false); if(trapifFound) listTraps(true); } else commandResult << "no traps set"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "loadconfig" void DebuggerParser::executeLoadconfig() { commandResult << debugger.cartDebug().loadConfigFile(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "loadstate" void DebuggerParser::executeLoadstate() { if(args[0] >= 0 && args[0] <= 9) debugger.loadState(args[0]); else commandResult << red("invalid slot (must be 0-9)"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "n" void DebuggerParser::executeN() { if(argCount == 0) debugger.cpuDebug().toggleN(); else if(argCount == 1) debugger.cpuDebug().setN(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "palette" void DebuggerParser::executePalette() { commandResult << debugger.tiaDebug().palette(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "pc" void DebuggerParser::executePc() { debugger.cpuDebug().setPC(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "pgfx" void DebuggerParser::executePGfx() { if(argCount != 2) { outputCommandError("specify start and end of range only", myCommand); return; } else if(args[1] < args[0]) { commandResult << red("start address must be <= end address"); return; } bool result = debugger.cartDebug().addDirective( CartDebug::PGFX, args[0], args[1]); commandResult << (result ? "added" : "removed") << " PGFX directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "print" void DebuggerParser::executePrint() { commandResult << eval(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "ram" void DebuggerParser::executeRam() { if(argCount == 0) commandResult << debugger.cartDebug().toString(); else commandResult << debugger.setRAM(args); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "reset" void DebuggerParser::executeReset() { debugger.reset(); debugger.rom().invalidate(); debugger.riotDebug().controller(Controller::Left).set(Controller::One, true); debugger.riotDebug().controller(Controller::Left).set(Controller::Two, true); debugger.riotDebug().controller(Controller::Left).set(Controller::Three, true); debugger.riotDebug().controller(Controller::Left).set(Controller::Four, true); debugger.riotDebug().controller(Controller::Left).set(Controller::Six, true); debugger.riotDebug().controller(Controller::Right).set(Controller::One, true); debugger.riotDebug().controller(Controller::Right).set(Controller::Two, true); debugger.riotDebug().controller(Controller::Right).set(Controller::Three, true); debugger.riotDebug().controller(Controller::Right).set(Controller::Four, true); debugger.riotDebug().controller(Controller::Right).set(Controller::Six, true); commandResult << "reset system"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "rewind" void DebuggerParser::executeRewind() { executeWinds(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "riot" void DebuggerParser::executeRiot() { commandResult << debugger.riotDebug().toString(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "rom" void DebuggerParser::executeRom() { uInt16 addr = args[0]; for(uInt32 i = 1; i < argCount; ++i) { if(!(debugger.patchROM(addr++, args[i]))) { commandResult << red("patching ROM unsupported for this cart type"); return; } } // Normally the run() method calls loadConfig() on the debugger, // which results in all child widgets being redrawn. // The RomWidget is a special case, since we don't want to re-disassemble // any more than necessary. So we only do it by calling the following // method ... debugger.rom().invalidate(); commandResult << "changed " << (args.size() - 1) << " location(s)"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "row" void DebuggerParser::executeRow() { if(argCount != 2) { outputCommandError("specify start and end of range only", myCommand); return; } else if(args[1] < args[0]) { commandResult << red("start address must be <= end address"); return; } bool result = debugger.cartDebug().addDirective( CartDebug::ROW, args[0], args[1]); commandResult << (result ? "added" : "removed") << " ROW directive on range $" << hex << args[0] << " $" << hex << args[1]; debugger.rom().invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "run" void DebuggerParser::executeRun() { debugger.saveOldState(); debugger.quit(false); commandResult << "_EXIT_DEBUGGER"; // See PromptWidget for more info } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "runto" void DebuggerParser::executeRunTo() { const CartDebug& cartdbg = debugger.cartDebug(); const CartDebug::DisassemblyList& list = cartdbg.disassembly().list; uInt32 count = 0, max_iterations = uInt32(list.size()); // Create a progress dialog box to show the progress searching through the // disassembly, since this may be a time-consuming operation ostringstream buf; buf << "RunTo searching through " << max_iterations << " disassembled instructions"; ProgressDialog progress(debugger.myBaseDialog, debugger.lfont(), buf.str()); progress.setRange(0, max_iterations, 5); bool done = false; do { debugger.step(); // Update romlist to point to current PC int pcline = cartdbg.addressToLine(debugger.cpuDebug().pc()); if(pcline >= 0) { const string& next = list[pcline].disasm; done = (BSPF::findIgnoreCase(next, argStrings[0]) != string::npos); } // Update the progress bar progress.setProgress(count); } while(!done && ++count < max_iterations); progress.close(); if(done) commandResult << "found " << argStrings[0] << " in " << dec << count << " disassembled instructions"; else commandResult << argStrings[0] << " not found in " << dec << count << " disassembled instructions"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "runtopc" void DebuggerParser::executeRunToPc() { const CartDebug& cartdbg = debugger.cartDebug(); const CartDebug::DisassemblyList& list = cartdbg.disassembly().list; uInt32 count = 0; bool done = false; do { debugger.step(); // Update romlist to point to current PC int pcline = cartdbg.addressToLine(debugger.cpuDebug().pc()); done = (pcline >= 0) && (list[pcline].address == args[0]); } while(!done && ++count < list.size()); if(done) commandResult << "set PC to " << Base::HEX4 << args[0] << " in " << dec << count << " disassembled instructions"; else commandResult << "PC " << Base::HEX4 << args[0] << " not reached or found in " << dec << count << " disassembled instructions"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "s" void DebuggerParser::executeS() { debugger.cpuDebug().setSP(uInt8(args[0])); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "save" void DebuggerParser::executeSave() { commandResult << saveScriptFile(argStrings[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "saveconfig" void DebuggerParser::executeSaveconfig() { commandResult << debugger.cartDebug().saveConfigFile(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "savedis" void DebuggerParser::executeSavedisassembly() { commandResult << debugger.cartDebug().saveDisassembly(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "saverom" void DebuggerParser::executeSaverom() { commandResult << debugger.cartDebug().saveRom(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "saveses" void DebuggerParser::executeSaveses() { // Create a file named with the current date and time time_t currtime; struct tm* timeinfo; char buffer[80]; time(&currtime); timeinfo = localtime(&currtime); strftime(buffer, 80, "session_%F_%H-%M-%S.txt", timeinfo); FilesystemNode file(debugger.myOSystem.defaultSaveDir() + buffer); if(debugger.prompt().saveBuffer(file)) commandResult << "saved " + file.getShortPath() + " OK"; else commandResult << "unable to save session"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "savesnap" void DebuggerParser::executeSavesnap() { debugger.tiaOutput().saveSnapshot(execDepth, execPrefix); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "savestate" void DebuggerParser::executeSavestate() { if(args[0] >= 0 && args[0] <= 9) debugger.saveState(args[0]); else commandResult << red("invalid slot (must be 0-9)"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "savestateif" void DebuggerParser::executeSavestateif() { int res = YaccParser::parse(argStrings[0].c_str()); if(res == 0) { string condition = argStrings[0]; for(uInt32 i = 0; i < debugger.m6502().getCondSaveStateNames().size(); i++) { if(condition == debugger.m6502().getCondSaveStateNames()[i]) { args[0] = i; executeDelsavestateif(); return; } } uInt32 ret = debugger.m6502().addCondSaveState( YaccParser::getResult(), argStrings[0]); commandResult << "added savestateif " << Base::toString(ret); } else commandResult << red("invalid expression"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "scanline" void DebuggerParser::executeScanline() { int count = 1; if(argCount != 0) count = args[0]; debugger.nextScanline(count); commandResult << "advanced " << dec << count << " scanline(s)"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "step" void DebuggerParser::executeStep() { commandResult << "executed " << dec << debugger.step() << " cycles"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "stepwhile" void DebuggerParser::executeStepwhile() { int res = YaccParser::parse(argStrings[0].c_str()); if(res != 0) { commandResult << red("invalid expression"); return; } Expression* expr = YaccParser::getResult(); int ncycles = 0; do { ncycles += debugger.step(); } while (expr->evaluate()); commandResult << "executed " << ncycles << " cycles"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "tia" void DebuggerParser::executeTia() { commandResult << debugger.tiaDebug().toString(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trace" void DebuggerParser::executeTrace() { commandResult << "executed " << dec << debugger.trace() << " cycles"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trap" void DebuggerParser::executeTrap() { executeTraps(true, true, "trap"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapif" void DebuggerParser::executeTrapif() { executeTraps(true, true, "trapif", true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapread" void DebuggerParser::executeTrapread() { executeTraps(true, false, "trapread"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapreadif" void DebuggerParser::executeTrapreadif() { executeTraps(true, false, "trapreadif", true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapwrite" void DebuggerParser::executeTrapwrite() { executeTraps(false, true, "trapwrite"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "trapwriteif" void DebuggerParser::executeTrapwriteif() { executeTraps(false, true, "trapwriteif", true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Wrapper function for trap(if)s void DebuggerParser::executeTraps(bool read, bool write, const string& command, bool hasCond) { uInt32 ofs = hasCond ? 1 : 0; uInt32 begin = args[ofs]; uInt32 end = argCount == 2 + ofs ? args[1 + ofs] : begin; if(argCount < 1 + ofs) { outputCommandError("missing required argument(s)", myCommand); return; } if(argCount > 2 + ofs) { outputCommandError("too many arguments", myCommand); return; } if(begin > 0xFFFF || end > 0xFFFF) { commandResult << red("invalid word argument(s) (must be 0-$ffff)"); return; } if(begin > end) { commandResult << red("start address must be <= end address"); return; } // base addresses of mirrors uInt32 beginRead = debugger.getBaseAddress(begin, true); uInt32 endRead = debugger.getBaseAddress(end, true); uInt32 beginWrite = debugger.getBaseAddress(begin, false); uInt32 endWrite = debugger.getBaseAddress(end, false); stringstream conditionBuf; // parenthesize provided and address range condition(s) (begin) if(hasCond) conditionBuf << "(" << argStrings[0] << ")&&("; // add address range condition(s) to provided condition if(read) { if(beginRead != endRead) conditionBuf << "__lastread>=" << Base::toString(beginRead) << "&&__lastread<=" << Base::toString(endRead); else conditionBuf << "__lastread==" << Base::toString(beginRead); } if(read && write) conditionBuf << "||"; if(write) { if(beginWrite != endWrite) conditionBuf << "__lastwrite>=" << Base::toString(beginWrite) << "&&__lastwrite<=" << Base::toString(endWrite); else conditionBuf << "__lastwrite==" << Base::toString(beginWrite); } // parenthesize provided condition (end) if(hasCond) conditionBuf << ")"; const string condition = conditionBuf.str(); int res = YaccParser::parse(condition.c_str()); if(res == 0) { // duplicates will remove each other bool add = true; for(uInt32 i = 0; i < myTraps.size(); i++) { if(myTraps[i]->begin == begin && myTraps[i]->end == end && myTraps[i]->read == read && myTraps[i]->write == write && myTraps[i]->condition == condition) { if(debugger.m6502().delCondTrap(i)) { add = false; // @sa666666: please check this: Vec::removeAt(myTraps, i); commandResult << "removed trap " << Base::toString(i); break; } commandResult << "Internal error! Duplicate trap removal failed!"; return; } } if(add) { uInt32 ret = debugger.m6502().addCondTrap( YaccParser::getResult(), hasCond ? argStrings[0] : ""); commandResult << "added trap " << Base::toString(ret); // @sa666666: please check this: myTraps.emplace_back(new Trap{ read, write, begin, end, condition }); } for(uInt32 addr = begin; addr <= end; ++addr) executeTrapRW(addr, read, write, add); } else { commandResult << red("invalid expression"); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // wrapper function for trap(if)/trapread(if)/trapwrite(if) commands void DebuggerParser::executeTrapRW(uInt32 addr, bool read, bool write, bool add) { switch(debugger.cartDebug().addressType(addr)) { case CartDebug::ADDR_TIA: { for(uInt32 i = 0; i <= 0xFFFF; ++i) { if((i & 0x1080) == 0x0000) { // @sa666666: This seems wrong. E.g. trapread 40 4f will never trigger if(read && (i & 0x000F) == (addr & 0x000F)) add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i); if(write && (i & 0x003F) == (addr & 0x003F)) add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i); } } break; } case CartDebug::ADDR_IO: { for(uInt32 i = 0; i <= 0xFFFF; ++i) { if((i & 0x1280) == 0x0280 && (i & 0x029F) == (addr & 0x029F)) { if(read) add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i); if(write) add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i); } } break; } case CartDebug::ADDR_ZPRAM: { for(uInt32 i = 0; i <= 0xFFFF; ++i) { if((i & 0x1280) == 0x0080 && (i & 0x00FF) == (addr & 0x00FF)) { if(read) add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i); if(write) add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i); } } break; } case CartDebug::ADDR_ROM: { if(addr >= 0x1000 && addr <= 0xFFFF) { for(uInt32 i = 0x1000; i <= 0xFFFF; ++i) { if((i % 0x2000 >= 0x1000) && (i & 0x0FFF) == (addr & 0x0FFF)) { if(read) add ? debugger.addReadTrap(i) : debugger.removeReadTrap(i); if(write) add ? debugger.addWriteTrap(i) : debugger.removeWriteTrap(i); } } } break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "type" void DebuggerParser::executeType() { uInt32 beg = args[0]; uInt32 end = argCount >= 2 ? args[1] : beg; if(beg > end) std::swap(beg, end); for(uInt32 i = beg; i <= end; ++i) { commandResult << Base::HEX4 << i << ": "; debugger.cartDebug().addressTypeAsString(commandResult, i); commandResult << endl; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "uhex" void DebuggerParser::executeUHex() { bool enable = !Base::hexUppercase(); Base::setHexUppercase(enable); settings.setValue("dbg.uhex", enable); debugger.rom().invalidate(); commandResult << "uppercase HEX " << (enable ? "enabled" : "disabled"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "undef" void DebuggerParser::executeUndef() { if(debugger.cartDebug().removeLabel(argStrings[0])) { debugger.rom().invalidate(); commandResult << argStrings[0] + " now undefined"; } else commandResult << red("no such label"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "unwind" void DebuggerParser::executeUnwind() { executeWinds(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "v" void DebuggerParser::executeV() { if(argCount == 0) debugger.cpuDebug().toggleV(); else if(argCount == 1) debugger.cpuDebug().setV(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "watch" void DebuggerParser::executeWatch() { myWatches.push_back(argStrings[0]); commandResult << "added watch \"" << argStrings[0] << "\""; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // wrapper function for rewind/unwind commands void DebuggerParser::executeWinds(bool unwind) { uInt16 states; string type = unwind ? "unwind" : "rewind"; string message; if(argCount == 0) states = 1; else states = args[0]; uInt16 winds = unwind ? debugger.unwindStates(states, message) : debugger.rewindStates(states, message); if(winds > 0) { debugger.rom().invalidate(); commandResult << type << " by " << winds << " state" << (winds > 1 ? "s" : ""); commandResult << " (~" << message << ")"; } else commandResult << "no states left to " << type; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "x" void DebuggerParser::executeX() { debugger.cpuDebug().setX(uInt8(args[0])); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "y" void DebuggerParser::executeY() { debugger.cpuDebug().setY(uInt8(args[0])); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // "z" void DebuggerParser::executeZ() { if(argCount == 0) debugger.cpuDebug().toggleZ(); else if(argCount == 1) debugger.cpuDebug().setZ(args[0]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // List of all commands available to the parser DebuggerParser::Command DebuggerParser::commands[kNumCommands] = { { "a", "Set Accumulator to ", "Valid value is 0 - ff\nExample: a ff, a #10", true, true, { kARG_BYTE, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeA) }, { "base", "Set default number base to ", "Base is #2, #10, #16, bin, dec or hex\nExample: base hex", true, true, { kARG_BASE_SPCL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeBase) }, { "break", "Set/clear breakpoint at

", "Command is a toggle, default is current PC\nValid address is 0 - ffff\n" "Example: break, break f000", false, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeBreak) }, { "breakif", "Set/clear breakpoint on ", "Condition can include multiple items, see documentation\nExample: breakif _scan>100", true, false, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeBreakif) }, { "c", "Carry Flag: set (0 or 1), or toggle (no arg)", "Example: c, c 0, c 1", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeC) }, { "cheat", "Use a cheat code (see manual for cheat types)", "Example: cheat 0040, cheat abff00", false, false, { kARG_LABEL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeCheat) }, { "clearbreaks", "Clear all breakpoints", "Example: clearbreaks (no parameters)", false, true, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeClearbreaks) }, { "clearconfig", "Clear Distella config directives [bank xx]", "Example: clearconfig 0, clearconfig 1", false, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeClearconfig) }, { "clearsavestateifs", "Clear all savestate points", "Example: clearsavestateifss (no parameters)", false, true, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeClearsavestateifs) }, { "cleartraps", "Clear all traps", "All traps cleared, including any mirrored ones\nExample: cleartraps (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeCleartraps) }, { "clearwatches", "Clear all watches", "Example: clearwatches (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeClearwatches) }, { "cls", "Clear prompt area of text", "Completely clears screen, but keeps history of commands", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeCls) }, { "code", "Mark 'CODE' range in disassembly", "Start and end of range required\nExample: code f000 f010", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeCode) }, { "colortest", "Show value xx as TIA color", "Shows a color swatch for the given value\nExample: colortest 1f", true, false, { kARG_BYTE, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeColortest) }, { "d", "Decimal Flag: set (0 or 1), or toggle (no arg)", "Example: d, d 0, d 1", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeD) }, { "data", "Mark 'DATA' range in disassembly", "Start and end of range required\nExample: data f000 f010", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeData) }, { "debugcolors", "Show Fixed Debug Colors information", "Example: debugcolors (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeDebugColors) }, { "define", "Define label xx for address yy", "Example: define LABEL1 f100", true, true, { kARG_LABEL, kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeDefine) }, { "delbreakif", "Delete conditional breakif ", "Example: delbreakif 0", true, false, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeDelbreakif) }, { "delfunction", "Delete function with label xx", "Example: delfunction FUNC1", true, false, { kARG_LABEL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeDelfunction) }, { "delsavestateif", "Delete conditional savestate point ", "Example: delsavestateif 0", true, false, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeDelsavestateif) }, { "deltrap", "Delete trap ", "Example: deltrap 0", true, false, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeDeltrap) }, { "delwatch", "Delete watch ", "Example: delwatch 0", true, false, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeDelwatch) }, { "disasm", "Disassemble address xx [yy lines] (default=PC)", "Disassembles from starting address (default=PC) for lines\n" "Example: disasm, disasm f000 100", false, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeDisasm) }, { "dump", "Dump data at address [to yy] [1: memory; 2: CPU state; 4: input regs]", "Example:\n" " dump f000 - dumps 128 bytes @ f000\n" " dump f000 f0ff - dumps all bytes from f000 to f0ff\n" " dump f000 f0ff 7 - dumps all bytes from f000 to f0ff, CPU state and input registers into a file", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeDump) }, { "exec", "Execute script file [prefix]", "Example: exec script.dat, exec auto.txt", true, true, { kARG_FILE, kARG_LABEL, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeExec) }, { "exitrom", "Exit emulator, return to ROM launcher", "Self-explanatory", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeExitRom) }, { "frame", "Advance emulation by frames (default=1)", "Example: frame, frame 100", false, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeFrame) }, { "function", "Define function name xx for expression yy", "Example: function FUNC1 { ... }", true, false, { kARG_LABEL, kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeFunction) }, { "gfx", "Mark 'GFX' range in disassembly", "Start and end of range required\nExample: gfx f000 f010", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeGfx) }, { "help", "help ", "Show all commands, or give function for help on that command\n" "Example: help, help code", false, false, { kARG_LABEL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeHelp) }, { "joy0up", "Set joystick 0 up direction to value (0 or 1), or toggle (no arg)", "Example: joy0up 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy0Up) }, { "joy0down", "Set joystick 0 down direction to value (0 or 1), or toggle (no arg)", "Example: joy0down 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy0Down) }, { "joy0left", "Set joystick 0 left direction to value (0 or 1), or toggle (no arg)", "Example: joy0left 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy0Left) }, { "joy0right", "Set joystick 0 right direction to value (0 or 1), or toggle (no arg)", "Example: joy0left 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy0Right) }, { "joy0fire", "Set joystick 0 fire button to value (0 or 1), or toggle (no arg)", "Example: joy0fire 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy0Fire) }, { "joy1up", "Set joystick 1 up direction to value (0 or 1), or toggle (no arg)", "Example: joy1up 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy1Up) }, { "joy1down", "Set joystick 1 down direction to value (0 or 1), or toggle (no arg)", "Example: joy1down 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy1Down) }, { "joy1left", "Set joystick 1 left direction to value (0 or 1), or toggle (no arg)", "Example: joy1left 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy1Left) }, { "joy1right", "Set joystick 1 right direction to value (0 or 1), or toggle (no arg)", "Example: joy1left 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy1Right) }, { "joy1fire", "Set joystick 1 fire button to value (0 or 1), or toggle (no arg)", "Example: joy1fire 0", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJoy1Fire) }, { "jump", "Scroll disassembly to address xx", "Moves disassembly listing to address \nExample: jump f400", true, false, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeJump) }, { "listbreaks", "List breakpoints", "Example: listbreaks (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeListbreaks) }, { "listconfig", "List Distella config directives [bank xx]", "Example: listconfig 0, listconfig 1", false, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeListconfig) }, { "listfunctions", "List user-defined functions", "Example: listfunctions (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeListfunctions) }, { "listsavestateifs", "List savestate points", "Example: listsavestateifs (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeListsavestateifs) }, { "listtraps", "List traps", "Lists all traps (read and/or write)\nExample: listtraps (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeListtraps) }, { "loadconfig", "Load Distella config file", "Example: loadconfig file.cfg", false, true, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeLoadconfig) }, { "loadstate", "Load emulator state xx (0-9)", "Example: loadstate 0, loadstate 9", true, true, { kARG_BYTE, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeLoadstate) }, { "n", "Negative Flag: set (0 or 1), or toggle (no arg)", "Example: n, n 0, n 1", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeN) }, { "palette", "Show current TIA palette", "Example: palette (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executePalette) }, { "pc", "Set Program Counter to address xx", "Example: pc f000", true, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executePc) }, { "pgfx", "Mark 'PGFX' range in disassembly", "Start and end of range required\nExample: pgfx f000 f010", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executePGfx) }, { "print", "Evaluate/print expression xx in hex/dec/binary", "Almost anything can be printed (constants, expressions, registers)\n" "Example: print pc, print f000", true, false, { kARG_DWORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executePrint) }, { "ram", "Show ZP RAM, or set address xx to yy1 [yy2 ...]", "Example: ram, ram 80 00 ...", false, true, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeRam) }, { "reset", "Reset system to power-on state", "System is completely reset, just as if it was just powered on", false, true, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeReset) }, { "rewind", "Rewind state by one or [xx] steps/traces/scanlines/frames...", "Example: rewind, rewind 5", false, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeRewind) }, { "riot", "Show RIOT timer/input status", "Display text-based output of the contents of the RIOT tab", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeRiot) }, { "rom", "Set ROM address xx to yy1 [yy2 ...]", "What happens here depends on the current bankswitching scheme\n" "Example: rom f000 00 01 ff ...", true, true, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeRom) }, { "row", "Mark 'ROW' range in disassembly", "Start and end of range required\nExample: row f000 f010", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeRow) }, { "run", "Exit debugger, return to emulator", "Self-explanatory", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeRun) }, { "runto", "Run until string xx in disassembly", "Advance until the given string is detected in the disassembly\n" "Example: runto lda", true, true, { kARG_LABEL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeRunTo) }, { "runtopc", "Run until PC is set to value xx", "Example: runtopc f200", true, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeRunToPc) }, { "s", "Set Stack Pointer to value xx", "Accepts 8-bit value, Example: s f0", true, true, { kARG_BYTE, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeS) }, { "save", "Save breaks, watches, traps and functions to file xx", "Example: save commands.script", true, false, { kARG_FILE, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeSave) }, { "saveconfig", "Save Distella config file (with default name)", "Example: saveconfig", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeSaveconfig) }, { "savedis", "Save Distella disassembly (with default name)", "Example: savedis\n" "NOTE: saves to default save location", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeSavedisassembly) }, { "saverom", "Save (possibly patched) ROM (with default name)", "Example: saverom\n" "NOTE: saves to default save location", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeSaverom) }, { "saveses", "Save console session (with default name)", "Example: saveses\n" "NOTE: saves to default save location", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeSaveses) }, { "savesnap", "Save current TIA image to PNG file", "Save snapshot to current snapshot save directory\n" "Example: savesnap (no parameters)", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeSavesnap) }, { "savestate", "Save emulator state xx (valid args 0-9)", "Example: savestate 0, savestate 9", true, false, { kARG_BYTE, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeSavestate) }, { "savestateif", "Create savestate on ", "Condition can include multiple items, see documentation\nExample: savestateif pc==f000", true, false, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeSavestateif) }, { "scanline", "Advance emulation by scanlines (default=1)", "Example: scanline, scanline 100", false, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeScanline) }, { "step", "Single step CPU [with count xx]", "Example: step, step 100", false, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeStep) }, { "stepwhile", "Single step CPU while is true", "Example: stepwhile pc!=$f2a9", true, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeStepwhile) }, { "tia", "Show TIA state", "Display text-based output of the contents of the TIA tab", false, false, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeTia) }, { "trace", "Single step CPU over subroutines [with count xx]", "Example: trace, trace 100", false, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeTrace) }, { "trap", "Trap read/write access to address(es) xx [yy]", "Set/clear a R/W trap on the given address(es) and all mirrors\n" "Example: trap f000, trap f000 f100", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeTrap) }, { "trapif", "On trap R/W access to address(es) xx [yy]", "Set/clear a conditional R/W trap on the given address(es) and all mirrors\nCondition can include multiple items.\n" "Example: trapif _scan>#100 GRP0, trapif _bank==1 f000 f100", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeTrapif) }, { "trapread", "Trap read access to address(es) xx [yy]", "Set/clear a read trap on the given address(es) and all mirrors\n" "Example: trapread f000, trapread f000 f100", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeTrapread) }, { "trapreadif", "On trap read access to address(es) xx [yy]", "Set/clear a conditional read trap on the given address(es) and all mirrors\nCondition can include multiple items.\n" "Example: trapreadif _scan>#100 GRP0, trapreadif _bank==1 f000 f100", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeTrapreadif) }, { "trapwrite", "Trap write access to address(es) xx [yy]", "Set/clear a write trap on the given address(es) and all mirrors\n" "Example: trapwrite f000, trapwrite f000 f100", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeTrapwrite) }, { "trapwriteif", "On trap write access to address(es) xx [yy]", "Set/clear a conditional write trap on the given address(es) and all mirrors\nCondition can include multiple items.\n" "Example: trapwriteif _scan>#100 GRP0, trapwriteif _bank==1 f000 f100", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeTrapwriteif) }, { "type", "Show disassembly type for address xx [yy]", "Example: type f000, type f000 f010", true, false, { kARG_WORD, kARG_MULTI_BYTE }, std::mem_fn(&DebuggerParser::executeType) }, { "uhex", "Toggle upper/lowercase HEX display", "Note: not all hex output can be changed\n" "Example: uhex (no parameters)", false, true, { kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeUHex) }, { "undef", "Undefine label xx (if defined)", "Example: undef LABEL1", true, true, { kARG_LABEL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeUndef) }, { "unwind", "Unwind state by one or [xx] steps/traces/scanlines/frames...", "Example: unwind, unwind 5", false, true, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeUnwind) }, { "v", "Overflow Flag: set (0 or 1), or toggle (no arg)", "Example: v, v 0, v 1", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeV) }, { "watch", "Print contents of address xx before every prompt", "Example: watch ram_80", true, false, { kARG_WORD, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeWatch) }, { "x", "Set X Register to value xx", "Valid value is 0 - ff\nExample: x ff, x #10", true, true, { kARG_BYTE, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeX) }, { "y", "Set Y Register to value xx", "Valid value is 0 - ff\nExample: y ff, y #10", true, true, { kARG_BYTE, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeY) }, { "z", "Zero Flag: set (0 or 1), or toggle (no arg)", "Example: z, z 0, z 1", false, true, { kARG_BOOL, kARG_END_ARGS }, std::mem_fn(&DebuggerParser::executeZ) } }; stella-5.1.1/src/debugger/DebuggerParser.hxx000066400000000000000000000157161324334165500210270ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DEBUGGER_PARSER_HXX #define DEBUGGER_PARSER_HXX #include #include class Debugger; class Settings; class FilesystemNode; struct Command; #include "bspf.hxx" class DebuggerParser { public: DebuggerParser(Debugger& debugger, Settings& settings); /** Run the given command, and return the result */ string run(const string& command); /** Execute parser commands given in 'file' */ string exec(const FilesystemNode& file, StringList* history = nullptr); /** Given a substring, determine matching substrings from the list of available commands. Used in the debugger prompt for tab-completion */ void getCompletions(const char* in, StringList& list) const; /** Evaluate the given expression using operators, current base, etc */ int decipher_arg(const string& str); /** String representation of all watches currently defined */ string showWatches(); static inline string red(const string& msg = "") { return char(kDbgColorRed) + msg; } static inline string inverse(const string& msg = "") { // ASCII DEL char, decimal 127 return "\177" + msg; } private: bool getArgs(const string& command, string& verb); bool validateArgs(int cmd); string eval(); string saveScriptFile(string file); private: enum { kNumCommands = 92 }; // Constants for argument processing enum { kIN_COMMAND, kIN_SPACE, kIN_BRACE, kIN_ARG }; enum parameters { kARG_WORD, // single 16-bit value kARG_DWORD, // single 32-bit value kARG_MULTI_WORD, // multiple 16-bit values (must occur last) kARG_BYTE, // single 8-bit value kARG_MULTI_BYTE, // multiple 8-bit values (must occur last) kARG_BOOL, // 0 or 1 only kARG_LABEL, // label (need not be defined, treated as string) kARG_FILE, // filename kARG_BASE_SPCL, // base specifier: 2, 10, or 16 (or "bin" "dec" "hex") kARG_END_ARGS // sentinel, occurs at end of list }; struct Command { string cmdString; string description; string extendedDesc; bool parmsRequired; bool refreshRequired; parameters parms[10]; std::function executor; }; struct Trap { bool read; bool write; uInt32 begin; uInt32 end; string condition; }; // Reference to our debugger object Debugger& debugger; // Reference to settings object (required for saving certain options) Settings& settings; // The results of the currently running command ostringstream commandResult; // currently execute command id int myCommand; // Arguments in 'int' and 'string' format for the currently running command IntArray args; StringList argStrings; uInt32 argCount; uInt32 execDepth; string execPrefix; StringList myWatches; // Keep track of traps (read and/or write) vector> myTraps; void listTraps(bool listCond); string trapStatus(const Trap& trap); // output the error with the example provided for the command void outputCommandError(const string& errorMsg, int command); // List of available command methods void executeA(); void executeBase(); void executeBreak(); void executeBreakif(); void executeC(); void executeCheat(); void executeClearbreaks(); void executeClearconfig(); void executeClearsavestateifs(); void executeCleartraps(); void executeClearwatches(); void executeCls(); void executeCode(); void executeColortest(); void executeD(); void executeData(); void executeDebugColors(); void executeDefine(); void executeDelbreakif(); void executeDelfunction(); void executeDelsavestateif(); void executeDeltrap(); void executeDelwatch(); void executeDisasm(); void executeDump(); void executeExec(); void executeExitRom(); void executeFrame(); void executeFunction(); void executeGfx(); void executeHelp(); void executeJoy0Up(); void executeJoy0Down(); void executeJoy0Left(); void executeJoy0Right(); void executeJoy0Fire(); void executeJoy1Up(); void executeJoy1Down(); void executeJoy1Left(); void executeJoy1Right(); void executeJoy1Fire(); void executeJump(); void executeListbreaks(); void executeListconfig(); void executeListfunctions(); void executeListsavestateifs(); void executeListtraps(); void executeLoadconfig(); void executeLoadstate(); void executeN(); void executePalette(); void executePc(); void executePGfx(); void executePrint(); void executeRam(); void executeReset(); void executeRewind(); void executeRiot(); void executeRom(); void executeRow(); void executeRun(); void executeRunTo(); void executeRunToPc(); void executeS(); void executeSave(); void executeSaveconfig(); void executeSavedisassembly(); void executeSaverom(); void executeSaveses(); void executeSavesnap(); void executeSavestate(); void executeSavestateif(); void executeScanline(); void executeStep(); void executeStepwhile(); void executeTia(); void executeTrace(); void executeTrap(); void executeTrapif(); void executeTrapread(); void executeTrapreadif(); void executeTrapwrite(); void executeTrapwriteif(); void executeTraps(bool read, bool write, const string& command, bool cond = false); void executeTrapRW(uInt32 addr, bool read, bool write, bool add = true); // not exposed by debugger void executeType(); void executeUHex(); void executeUndef(); void executeUnwind(); void executeV(); void executeWatch(); void executeWinds(bool unwind); void executeX(); void executeY(); void executeZ(); // List of commands available static Command commands[kNumCommands]; private: // Following constructors and assignment operators not supported DebuggerParser() = delete; DebuggerParser(const DebuggerParser&) = delete; DebuggerParser(DebuggerParser&&) = delete; DebuggerParser& operator=(const DebuggerParser&) = delete; DebuggerParser& operator=(DebuggerParser&&) = delete; }; #endif stella-5.1.1/src/debugger/DebuggerSystem.hxx000066400000000000000000000042751324334165500210550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DEBUGGER_SYSTEM_HXX #define DEBUGGER_SYSTEM_HXX class Debugger; #include "Console.hxx" /** The DebuggerState class is used as a base class for state in all DebuggerSystem objects. We make it a class so we can take advantage of the copy constructor. */ class DebuggerState { public: DebuggerState() = default; ~DebuggerState() = default; DebuggerState(const DebuggerState&) = default; DebuggerState(DebuggerState&&) = delete; DebuggerState& operator=(const DebuggerState&) = default; DebuggerState& operator=(DebuggerState&&) = delete; }; /** The base class for all debugger objects. Its real purpose is to clean up the Debugger API, partitioning it into separate subsystems. */ class DebuggerSystem { public: DebuggerSystem(Debugger& dbg, Console& console) : myDebugger(dbg), myConsole(console), mySystem(console.system()) { } virtual ~DebuggerSystem() = default; virtual const DebuggerState& getState() = 0; virtual const DebuggerState& getOldState() = 0; virtual void saveOldState() = 0; virtual string toString() = 0; protected: Debugger& myDebugger; Console& myConsole; System& mySystem; private: // Following constructors and assignment operators not supported DebuggerSystem() = delete; DebuggerSystem(const DebuggerSystem&) = delete; DebuggerSystem(DebuggerSystem&&) = delete; DebuggerSystem& operator=(const DebuggerSystem&) = delete; DebuggerSystem& operator=(DebuggerSystem&&) = delete; }; #endif stella-5.1.1/src/debugger/DiStella.cxx000066400000000000000000001570741324334165500176260ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Debugger.hxx" #include "DiStella.hxx" using Common::Base; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DiStella::DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, CartDebug::BankInfo& info, const DiStella::Settings& s, uInt8* labels, uInt8* directives, CartDebug::ReservedEquates& reserved) : myDbg(dbg), myList(list), mySettings(s), myReserved(reserved), myOffset(0), myPC(0), myPCEnd(0), myLabels(labels), myDirectives(directives) { bool resolve_code = mySettings.resolveCode; CartDebug::AddressList& debuggerAddresses = info.addressList; uInt16 start = *debuggerAddresses.cbegin(); myOffset = info.offset; if (start & 0x1000) { info.start = myAppData.start = 0x0000; info.end = myAppData.end = info.size - 1; // Keep previous offset; it may be different between banks if (info.offset == 0) info.offset = myOffset = (start - (start % info.size)); } else { // ZP RAM // For now, we assume all accesses below $1000 are zero-page info.start = myAppData.start = 0x0080; info.end = myAppData.end = 0x00FF; info.offset = myOffset = 0; // Resolve code is never used in ZP RAM mode resolve_code = false; } myAppData.length = info.size; memset(myLabels, 0, 0x1000); memset(myDirectives, 0, 0x1000); // Process any directives first, as they override automatic code determination processDirectives(info.directiveList); myReserved.breakFound = false; if (resolve_code) // First pass disasmPass1(info.addressList); // Second pass disasm(myOffset, 2); // Add reserved line equates ostringstream reservedLabel; for (int k = 0; k <= myAppData.end; k++) { if ((myLabels[k] & (CartDebug::REFERENCED | CartDebug::VALID_ENTRY)) == CartDebug::REFERENCED) { // If we have a piece of code referenced somewhere else, but cannot // locate the label in code (i.e because the address is inside of a // multi-byte instruction, then we make note of that address for reference // // However, we only do this for labels pointing to ROM (above $1000) if (myDbg.addressType(k + myOffset) == CartDebug::ADDR_ROM) { reservedLabel.str(""); reservedLabel << "L" << Base::HEX4 << (k + myOffset); myReserved.Label.emplace(k + myOffset, reservedLabel.str()); } } } // Third pass disasm(myOffset, 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::disasm(uInt32 distart, int pass) /* // Here we have 3 passes: - pass 1 tries to detect code and data ranges and labels - pass 2 marks valid code - pass 3 generates output */ { #define LABEL_A12_HIGH(address) labelA12High(nextLine, opcode, address, labelFound) #define LABEL_A12_LOW(address) labelA12Low(nextLine, opcode, address, labelFound) uInt8 opcode, d1; uInt16 ad; Int32 cycles = 0; AddressingMode addrMode; int labelFound = 0; stringstream nextLine, nextLineBytes; mySegType = CartDebug::NONE; // create extra lines between code and data myDisasmBuf.str(""); /* pc=myAppData.start; */ myPC = distart - myOffset; while (myPC <= myAppData.end) { // since -1 is used in m6502.m4 for clearing the last peek // and this results into an access at e.g. 0xffff, // we have to fix the consequences here (ugly!). if(myPC == myAppData.end) goto FIX_LAST; if (checkBits(myPC, CartDebug::GFX | CartDebug::PGFX, CartDebug::CODE)) { if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); if (pass == 3) outputGraphics(); myPC++; } else if (checkBits(myPC, CartDebug::DATA, CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX)) { if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); if (pass == 3) outputBytes(CartDebug::DATA); else myPC++; } else if (checkBits(myPC, CartDebug::ROW, CartDebug::CODE | CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) { FIX_LAST: if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); if (pass == 3) outputBytes(CartDebug::ROW); else myPC++; } else { // The following sections must be CODE // add extra spacing line when switching from non-code to code if (pass == 3 && mySegType != CartDebug::CODE && mySegType != CartDebug::NONE) { myDisasmBuf << " ' ' "; addEntry(CartDebug::NONE); mark(myPC + myOffset, CartDebug::REFERENCED); // add label when switching } mySegType = CartDebug::CODE; /* version 2.1 bug fix */ if (pass == 2) mark(myPC + myOffset, CartDebug::VALID_ENTRY); // get opcode opcode = Debugger::debugger().peek(myPC + myOffset); // get address mode for opcode addrMode = ourLookup[opcode].addr_mode; if (pass == 3) { if (checkBit(myPC, CartDebug::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; } myPC++; // detect labels inside instructions (e.g. BIT masks) labelFound = false; for (Uint8 i = 0; i < ourLookup[opcode].bytes - 1; i++) { if (checkBit(myPC + i, CartDebug::REFERENCED)) { labelFound = true; break; } } if (labelFound) { if (myOffset >= 0x1000) { // the opcode's operand address matches a label address if (pass == 3) { // output the byte of the opcode incl. cycles Uint8 nextOpcode = Debugger::debugger().peek(myPC + myOffset); cycles += int(ourLookup[opcode].cycles) - int(ourLookup[nextOpcode].cycles); nextLine << ".byte $" << Base::HEX2 << int(opcode) << " ;"; nextLine << ourLookup[opcode].mnemonic; myDisasmBuf << nextLine.str() << "'" << ";" << std::dec << int(ourLookup[opcode].cycles) << "-" << std::dec << int(ourLookup[nextOpcode].cycles) << " " << "'= " << std::setw(3) << std::setfill(' ') << std::dec << cycles; nextLine.str(""); cycles = 0; addEntry(CartDebug::CODE); // add the new found CODE entry } // continue with the label's opcode continue; } else { if (pass == 3) { // TODO } } } // Undefined opcodes start with a '.' // These are undefined wrt DASM if (ourLookup[opcode].mnemonic[0] == '.' && pass == 3) { nextLine << ".byte $" << Base::HEX2 << int(opcode) << " ;"; } if (pass == 3) { nextLine << ourLookup[opcode].mnemonic; nextLineBytes << Base::HEX2 << int(opcode) << " "; } // Add operand(s) for PC values outside the app data range if (myPC >= myAppData.end) { switch (addrMode) { case ABSOLUTE: case ABSOLUTE_X: case ABSOLUTE_Y: case INDIRECT_X: case INDIRECT_Y: case ABS_INDIRECT: { if (pass == 3) { /* Line information is already printed; append .byte since last instruction will put recompilable object larger that original binary file */ myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode) << " $" << Base::HEX4 << myPC + myOffset << "'" << Base::HEX2 << int(opcode); addEntry(CartDebug::DATA); if (myPC == myAppData.end) { if (checkBit(myPC, CartDebug::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; opcode = Debugger::debugger().peek(myPC + myOffset); myPC++; myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode) << " $" << Base::HEX4 << myPC + myOffset << "'" << Base::HEX2 << int(opcode); addEntry(CartDebug::DATA); } } myPCEnd = myAppData.end + myOffset; return; } case ZERO_PAGE: case IMMEDIATE: case ZERO_PAGE_X: case ZERO_PAGE_Y: case RELATIVE: { if (pass == 3) { /* Line information is already printed, but we can remove the Instruction (i.e. BMI) by simply clearing the buffer to print */ myDisasmBuf << ".byte $" << Base::HEX2 << int(opcode); addEntry(CartDebug::ROW); nextLine.str(""); nextLineBytes.str(""); } myPC++; myPCEnd = myAppData.end + myOffset; return; } default: break; } // end switch(addr_mode) } // Add operand(s) ad = d1 = 0; // not WSYNC by default! /* Version 2.1 added the extensions to mnemonics */ switch (addrMode) { case ACCUMULATOR: { if (pass == 3 && mySettings.aFlag) nextLine << " A"; break; } case ABSOLUTE: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; labelFound = mark(ad, CartDebug::REFERENCED); if (pass == 3) { if (ad < 0x100 && mySettings.fFlag) nextLine << ".w "; else nextLine << " "; if (labelFound == 1) { LABEL_A12_HIGH(ad); nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } else if (labelFound == 4) { if (mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8); } else { nextLine << "$" << Base::HEX4 << ad; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } } else { LABEL_A12_LOW(ad); nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } } break; } case ZERO_PAGE: { d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; labelFound = mark(d1, CartDebug::REFERENCED); if (pass == 3) { nextLine << " "; LABEL_A12_LOW(int(d1)); nextLineBytes << Base::HEX2 << int(d1); } break; } case IMMEDIATE: { d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; if (pass == 3) { nextLine << " #$" << Base::HEX2 << int(d1) << " "; nextLineBytes << Base::HEX2 << int(d1); } break; } case ABSOLUTE_X: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; labelFound = mark(ad, CartDebug::REFERENCED); if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) { // Since we can't know what address is being accessed unless we also // know the current X value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers mark(ad, CartDebug::ROW); } else if (pass == 3) { if (ad < 0x100 && mySettings.fFlag) nextLine << ".wx "; else nextLine << " "; if (labelFound == 1) { LABEL_A12_HIGH(ad); nextLine << ",x"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } else if (labelFound == 4) { if (mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); nextLine << ",x"; nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8); } else { nextLine << "$" << Base::HEX4 << ad << ",x"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } } else { LABEL_A12_LOW(ad); nextLine << ",x"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } } break; } case ABSOLUTE_Y: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; labelFound = mark(ad, CartDebug::REFERENCED); if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) { // Since we can't know what address is being accessed unless we also // know the current Y value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers mark(ad, CartDebug::ROW); } else if (pass == 3) { if (ad < 0x100 && mySettings.fFlag) nextLine << ".wy "; else nextLine << " "; if (labelFound == 1) { LABEL_A12_HIGH(ad); nextLine << ",y"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } else if (labelFound == 4) { if (mySettings.rFlag) { int tmp = (ad & myAppData.end) + myOffset; LABEL_A12_HIGH(tmp); nextLine << ",y"; nextLineBytes << Base::HEX2 << int(tmp & 0xff) << " " << Base::HEX2 << int(tmp >> 8); } else { nextLine << "$" << Base::HEX4 << ad << ",y"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } } else { LABEL_A12_LOW(ad); nextLine << ",y"; nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); } } break; } case INDIRECT_X: { d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; if (pass == 3) { labelFound = mark(d1, 0); // dummy call to get address type nextLine << " ("; LABEL_A12_LOW(d1); nextLine << ",x)"; nextLineBytes << Base::HEX2 << int(d1); } break; } case INDIRECT_Y: { d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; if (pass == 3) { labelFound = mark(d1, 0); // dummy call to get address type nextLine << " ("; LABEL_A12_LOW(d1); nextLine << "),y"; nextLineBytes << Base::HEX2 << int(d1); } break; } case ZERO_PAGE_X: { d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; labelFound = mark(d1, CartDebug::REFERENCED); if (pass == 3) { nextLine << " "; LABEL_A12_LOW(d1); nextLine << ",x"; } nextLineBytes << Base::HEX2 << int(d1); break; } case ZERO_PAGE_Y: { d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; labelFound = mark(d1, CartDebug::REFERENCED); if (pass == 3) { nextLine << " "; LABEL_A12_LOW(d1); nextLine << ",y"; } nextLineBytes << Base::HEX2 << int(d1); break; } case RELATIVE: { // SA - 04-06-2010: there seemed to be a bug in distella, // where wraparound occurred on a 32-bit int, and subsequent // indexing into the labels array caused a crash d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; ad = ((myPC + Int8(d1)) & 0xfff) + myOffset; labelFound = mark(ad, CartDebug::REFERENCED); if (pass == 3) { if (labelFound == 1) { nextLine << " "; LABEL_A12_HIGH(ad); } else nextLine << " $" << Base::HEX4 << ad; nextLineBytes << Base::HEX2 << int(d1); } break; } case ABS_INDIRECT: { ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; labelFound = mark(ad, CartDebug::REFERENCED); if (pass == 2 && !checkBit(ad & myAppData.end, CartDebug::CODE)) { // Since we can't know what address is being accessed unless we also // know the current X value, this is marked as ROW instead of DATA // The processing is left here, however, in case future versions of // the code can somehow track access to CPU registers mark(ad, CartDebug::ROW); } else if (pass == 3) { if (ad < 0x100 && mySettings.fFlag) nextLine << ".ind "; else nextLine << " "; } if (labelFound == 1) { nextLine << "("; LABEL_A12_HIGH(ad); nextLine << ")"; } // TODO - should we consider case 4?? else { nextLine << "("; LABEL_A12_LOW(ad); nextLine << ")"; } nextLineBytes << Base::HEX2 << int(ad & 0xff) << " " << Base::HEX2 << int(ad >> 8); break; } default: break; } // end switch if (pass == 3) { cycles += int(ourLookup[opcode].cycles); // A complete line of disassembly (text, cycle count, and bytes) myDisasmBuf << nextLine.str() << "'" << ";" << std::dec << int(ourLookup[opcode].cycles) << (addrMode == RELATIVE ? (ad & 0xf00) != ((myPC + myOffset) & 0xf00) ? "/3!" : "/3 " : " "); if ((opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00 // code block end || checkBit(myPC, CartDebug::REFERENCED) // referenced address || (ourLookup[opcode].rw_mode == WRITE && d1 == WSYNC)) // strobe WSYNC && cycles > 0) { // output cycles for previous code block myDisasmBuf << "'= " << std::setw(3) << std::setfill(' ') << std::dec << cycles; cycles = 0; } else { myDisasmBuf << "' "; } myDisasmBuf << "'" << nextLineBytes.str(); addEntry(CartDebug::CODE); if (opcode == 0x40 || opcode == 0x60 || opcode == 0x4c || opcode == 0x00) { myDisasmBuf << " ' ' "; addEntry(CartDebug::NONE); mySegType = CartDebug::NONE; // prevent extra lines if data follows } nextLine.str(""); nextLineBytes.str(""); } } } /* while loop */ /* Just in case we are disassembling outside of the address range, force the myPCEnd to EOF */ myPCEnd = myAppData.end + myOffset; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::disasmPass1(CartDebug::AddressList& debuggerAddresses) { auto it = debuggerAddresses.cbegin(); uInt16 start = *it++; // After we've disassembled from all addresses in the address list, // use all access points determined by Stella during emulation int codeAccessPoint = 0; // Sometimes we get a circular reference, in that processing a certain // PC address leads us to a sequence of addresses that end up trying // to process the same address again. We detect such consecutive PC // addresses and only process the first one uInt16 lastPC = 0; bool duplicateFound = false; while (!myAddressQueue.empty()) myAddressQueue.pop(); myAddressQueue.push(start); while (!(myAddressQueue.empty() || duplicateFound)) { uInt16 pcBeg = myPC = lastPC = myAddressQueue.front(); myAddressQueue.pop(); disasmFromAddress(myPC); if (pcBeg <= myPCEnd) { // Tentatively mark all addresses in the range as CODE // Note that this is a 'best-effort' approach, since // Distella will normally keep going until the end of the // range or branch is encountered // However, addresses *specifically* marked as DATA/GFX/PGFX // in the emulation core indicate that the CODE range has finished // Therefore, we stop at the first such address encountered for (uInt32 k = pcBeg; k <= myPCEnd; k++) { if (checkBits(k, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX, CartDebug::CODE)) { //if (Debugger::debugger().getAccessFlags(k) & // (CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX)) { // TODO: this should never happen, remove when we are sure // TODO: NOT USED: uInt8 flags = Debugger::debugger().getAccessFlags(k); myPCEnd = k - 1; break; } mark(k, CartDebug::CODE); } } // When we get to this point, all addresses have been processed // starting from the initial one in the address list // If so, process the next one in the list that hasn't already // been marked as CODE // If it *has* been marked, it can be removed from consideration // in all subsequent passes // // Once the address list has been exhausted, we process all addresses // determined during emulation to represent code, which *haven't* already // been considered // // Note that we can't simply add all addresses right away, since // the processing of a single address can cause others to be added in // the ::disasm method // All of these have to be exhausted before considering a new address while (myAddressQueue.empty() && it != debuggerAddresses.end()) { uInt16 addr = *it; if (!checkBit(addr - myOffset, CartDebug::CODE)) { myAddressQueue.push(addr); ++it; } else // remove this address, it is redundant it = debuggerAddresses.erase(it); } // Stella itself can provide hints on whether an address has ever // been referenced as CODE while (myAddressQueue.empty() && codeAccessPoint <= myAppData.end) { if ((Debugger::debugger().getAccessFlags(codeAccessPoint + myOffset) & CartDebug::CODE) && !(myLabels[codeAccessPoint & myAppData.end] & CartDebug::CODE)) { myAddressQueue.push(codeAccessPoint + myOffset); ++codeAccessPoint; break; } ++codeAccessPoint; } duplicateFound = !myAddressQueue.empty() && (myAddressQueue.front() == lastPC); // TODO: check! } // while for (int k = 0; k <= myAppData.end; k++) { // Let the emulation core know about tentative code if (checkBit(k, CartDebug::CODE) && !(Debugger::debugger().getAccessFlags(k + myOffset) & CartDebug::CODE) && myOffset != 0) { Debugger::debugger().setAccessFlags(k + myOffset, CartDebug::TCODE); } // Must be ROW / unused bytes if (!checkBit(k, CartDebug::CODE | CartDebug::GFX | CartDebug::PGFX | CartDebug::DATA)) mark(k + myOffset, CartDebug::ROW); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::disasmFromAddress(uInt32 distart) { uInt8 opcode, d1; uInt16 ad; AddressingMode addrMode; myPC = distart - myOffset; while (myPC <= myAppData.end) { // abort when we reach non-code areas if (checkBits(myPC, CartDebug::CartDebug::DATA | CartDebug::GFX | CartDebug::PGFX, CartDebug::CODE)) { myPCEnd = (myPC - 1) + myOffset; return; } // so this should be code now... // get opcode opcode = Debugger::debugger().peek(myPC + myOffset); myPC++; // get address mode for opcode addrMode = ourLookup[opcode].addr_mode; // Add operand(s) for PC values outside the app data range if (myPC >= myAppData.end) { switch (addrMode) { case ABSOLUTE: case ABSOLUTE_X: case ABSOLUTE_Y: case INDIRECT_X: case INDIRECT_Y: case ABS_INDIRECT: myPCEnd = myAppData.end + myOffset; return; case ZERO_PAGE: case IMMEDIATE: case ZERO_PAGE_X: case ZERO_PAGE_Y: case RELATIVE: if (myPC > myAppData.end) { myPC++; myPCEnd = myAppData.end + myOffset; return; } break; // TODO - is this the intent? default: break; } // end switch(addr_mode) } // end if (myPC >= myAppData.end) // Add operand(s) switch (addrMode) { case ABSOLUTE: ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; mark(ad, CartDebug::REFERENCED); // handle JMP/JSR if (ourLookup[opcode].source == M_ADDR) { // do NOT use flags set by debugger, else known CODE will not analyzed statically. if (!checkBit(ad & myAppData.end, CartDebug::CODE, false)) { if (ad > 0xfff) myAddressQueue.push((ad & myAppData.end) + myOffset); mark(ad, CartDebug::CODE); } } else mark(ad, CartDebug::DATA); break; case ZERO_PAGE: d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; mark(d1, CartDebug::REFERENCED); break; case IMMEDIATE: myPC++; break; case ABSOLUTE_X: ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; mark(ad, CartDebug::REFERENCED); break; case ABSOLUTE_Y: ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; mark(ad, CartDebug::REFERENCED); break; case INDIRECT_X: myPC++; break; case INDIRECT_Y: myPC++; break; case ZERO_PAGE_X: d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; mark(d1, CartDebug::REFERENCED); break; case ZERO_PAGE_Y: d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; mark(d1, CartDebug::REFERENCED); break; case RELATIVE: // SA - 04-06-2010: there seemed to be a bug in distella, // where wraparound occurred on a 32-bit int, and subsequent // indexing into the labels array caused a crash d1 = Debugger::debugger().peek(myPC + myOffset); myPC++; ad = ((myPC + Int8(d1)) & 0xfff) + myOffset; mark(ad, CartDebug::REFERENCED); // do NOT use flags set by debugger, else known CODE will not analyzed statically. if (!checkBit(ad - myOffset, CartDebug::CODE, false)) { myAddressQueue.push(ad); mark(ad, CartDebug::CODE); } break; case ABS_INDIRECT: ad = Debugger::debugger().dpeek(myPC + myOffset); myPC += 2; mark(ad, CartDebug::REFERENCED); break; default: break; } // end switch // mark BRK vector if (opcode == 0x00) { ad = Debugger::debugger().dpeek(0xfffe, CartDebug::DATA); if (!myReserved.breakFound) { myAddressQueue.push(ad); mark(ad, CartDebug::CODE); myReserved.breakFound = true; } } // JMP/RTS/RTI always indicate the end of a block of CODE if (opcode == 0x4c || opcode == 0x60 || opcode == 0x40) { // code block end myPCEnd = (myPC - 1) + myOffset; return; } } // while } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int DiStella::mark(uInt32 address, uInt8 mask, bool directive) { /*----------------------------------------------------------------------- For any given offset and code range... If we're between the offset and the end of the code range, we mark the bit in the labels array for that data. The labels array is an array of label info for each code address. If this is the case, return "1", else... We sweep for hardware/system equates, which are valid addresses, outside the scope of the code/data range. For these, we mark its corresponding hardware/system array element, and return "2" or "3" (depending on which system/hardware element was accessed). If this was not the case... Next we check if it is a code "mirror". For the 2600, address ranges are limited with 13 bits, so other addresses can exist outside of the standard code/data range. For these, we mark the element in the "labels" array that corresponds to the mirrored address, and return "4" If all else fails, it's not a valid address, so return 0. A quick example breakdown for a 2600 4K cart: =========================================================== $00-$3d = system equates (WSYNC, etc...); return 2. $80-$ff = zero-page RAM (ram_80, etc...); return 5. $0280-$0297 = system equates (INPT0, etc...); mark the array's element with the appropriate bit; return 3. $1000-$1FFF = mark the code/data array for the mirrored address with the appropriate bit; return 4. $3000-$3FFF = mark the code/data array for the mirrored address with the appropriate bit; return 4. $5000-$5FFF = mark the code/data array for the mirrored address with the appropriate bit; return 4. $7000-$7FFF = mark the code/data array for the mirrored address with the appropriate bit; return 4. $9000-$9FFF = mark the code/data array for the mirrored address with the appropriate bit; return 4. $B000-$BFFF = mark the code/data array for the mirrored address with the appropriate bit; return 4. $D000-$DFFF = mark the code/data array for the mirrored address with the appropriate bit; return 4. $F000-$FFFF = mark the code/data array for the address with the appropriate bit; return 1. Anything else = invalid, return 0. =========================================================== -----------------------------------------------------------------------*/ // Check for equates before ROM/ZP-RAM accesses, because the original logic // of Distella assumed either equates or ROM; it didn't take ZP-RAM into account CartDebug::AddrType type = myDbg.addressType(address); if (type == CartDebug::ADDR_TIA) { return 2; } else if (type == CartDebug::ADDR_IO) { return 3; } else if (type == CartDebug::ADDR_ZPRAM && myOffset != 0) { return 5; } else if (address >= myOffset && address <= myAppData.end + myOffset) { myLabels[address - myOffset] = myLabels[address - myOffset] | mask; if (directive) myDirectives[address - myOffset] = mask; return 1; } else if (address > 0x1000 && myOffset != 0) // Exclude zero-page accesses { /* 2K & 4K case */ myLabels[address & myAppData.end] = myLabels[address & myAppData.end] | mask; if (directive) myDirectives[address & myAppData.end] = mask; return 4; } else return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DiStella::checkBit(uInt16 address, uInt8 mask, bool useDebugger) const { // The REFERENCED and VALID_ENTRY flags are needed for any inspection of // an address // Since they're set only in the labels array (as the lower two bits), // they must be included in the other bitfields uInt8 label = myLabels[address & myAppData.end], lastbits = label & 0x03, directive = myDirectives[address & myAppData.end] & 0xFC, debugger = Debugger::debugger().getAccessFlags(address | myOffset) & 0xFC; // Any address marked by a manual directive always takes priority if (directive) return (directive | lastbits) & mask; // Next, the results from a dynamic/runtime analysis are used (except for pass 1) else if (useDebugger && ((debugger | lastbits) & mask)) return true; // Otherwise, default to static analysis from Distella else return label & mask; } bool DiStella::checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger) const { return checkBit(address, mask, useDebugger) && !checkBit(address, notMask, useDebugger); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DiStella::check_range(uInt16 beg, uInt16 end) const { if (beg > end) { cerr << "Beginning of range greater than end: start = " << std::hex << beg << ", end = " << std::hex << end << endl; return false; } else if (beg > myAppData.end + myOffset) { cerr << "Beginning of range out of range: start = " << std::hex << beg << ", range = " << std::hex << (myAppData.end + myOffset) << endl; return false; } else if (beg < myOffset) { cerr << "Beginning of range out of range: start = " << std::hex << beg << ", offset = " << std::hex << myOffset << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::addEntry(CartDebug::DisasmType type) { CartDebug::DisassemblyTag tag; // Type tag.type = type; // Address myDisasmBuf.seekg(0, std::ios::beg); if (myDisasmBuf.peek() == ' ') tag.address = 0; else myDisasmBuf >> std::setw(4) >> std::hex >> tag.address; // Only include addresses within the requested range if (tag.address < myAppData.start) goto DONE_WITH_ADD; // Label (a user-defined label always overrides any auto-generated one) myDisasmBuf.seekg(5, std::ios::beg); if (tag.address) { tag.label = myDbg.getLabel(tag.address, true); tag.hllabel = true; if (tag.label == EmptyString) { if (myDisasmBuf.peek() != ' ') getline(myDisasmBuf, tag.label, '\''); else if (mySettings.showAddresses && tag.type == CartDebug::CODE) { // Have addresses indented, to differentiate from actual labels tag.label = " " + Base::toString(tag.address, Base::F_16_4); tag.hllabel = false; } } } // Disassembly // Up to this point the field sizes are fixed, until we get to // variable length labels, cycle counts, etc myDisasmBuf.seekg(11, std::ios::beg); switch (tag.type) { case CartDebug::CODE: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.ccount, '\''); getline(myDisasmBuf, tag.ctotal, '\''); getline(myDisasmBuf, tag.bytes); // Make note of when we override CODE sections from the debugger // It could mean that the code hasn't been accessed up to this point, // but it could also indicate that code will *never* be accessed // Since it is impossible to tell the difference, marking the address // in the disassembly at least tells the user about it if (!(Debugger::debugger().getAccessFlags(tag.address) & CartDebug::CODE) && myOffset != 0) { tag.ccount += " *"; Debugger::debugger().setAccessFlags(tag.address, CartDebug::TCODE); } break; case CartDebug::GFX: case CartDebug::PGFX: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; case CartDebug::DATA: getline(myDisasmBuf, tag.disasm, '\''); getline(myDisasmBuf, tag.bytes); break; case CartDebug::ROW: getline(myDisasmBuf, tag.disasm); break; case CartDebug::NONE: default: // should never happen tag.disasm = " "; break; } myList.push_back(tag); DONE_WITH_ADD: myDisasmBuf.clear(); myDisasmBuf.str(""); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::outputGraphics() { bool isPGfx = checkBit(myPC, CartDebug::PGFX); const string& bitString = isPGfx ? "\x1f" : "\x1e"; uInt8 byte = Debugger::debugger().peek(myPC + myOffset); // add extra spacing line when switching from non-graphics to graphics if (mySegType != CartDebug::GFX && mySegType != CartDebug::NONE) { myDisasmBuf << " ' ' "; addEntry(CartDebug::NONE); } mySegType = CartDebug::GFX; if (checkBit(myPC, CartDebug::REFERENCED)) myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'"; else myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '"; myDisasmBuf << ".byte $" << Base::HEX2 << int(byte) << " |"; for (uInt8 i = 0, c = byte; i < 8; ++i, c <<= 1) myDisasmBuf << ((c > 127) ? bitString : " "); myDisasmBuf << "| $" << Base::HEX4 << myPC + myOffset << "'"; if (mySettings.gfxFormat == Base::F_2) myDisasmBuf << Base::toString(byte, Base::F_2_8); else myDisasmBuf << Base::HEX2 << int(byte); addEntry(isPGfx ? CartDebug::PGFX : CartDebug::GFX); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::outputBytes(CartDebug::DisasmType type) { bool isType = true; bool referenced = checkBit(myPC, CartDebug::REFERENCED); bool lineEmpty = true; int numBytes = 0; // add extra spacing line when switching from non-data to data if (mySegType != CartDebug::DATA && mySegType != CartDebug::NONE) { myDisasmBuf << " ' ' "; addEntry(CartDebug::NONE); } mySegType = CartDebug::DATA; while (isType && myPC <= myAppData.end) { if (referenced) { // start a new line with a label if (!lineEmpty) addEntry(type); myDisasmBuf << Base::HEX4 << myPC + myOffset << "'L" << Base::HEX4 << myPC + myOffset << "'.byte " << "$" << Base::HEX2 << int(Debugger::debugger().peek(myPC + myOffset)); myPC++; numBytes = 1; lineEmpty = false; } else if (lineEmpty) { // start a new line without a label myDisasmBuf << Base::HEX4 << myPC + myOffset << "' '" << ".byte $" << Base::HEX2 << int(Debugger::debugger().peek(myPC + myOffset)); myPC++; numBytes = 1; lineEmpty = false; } // Otherwise, append bytes to the current line, up until the maximum else if (++numBytes == mySettings.bytesWidth) { addEntry(type); lineEmpty = true; } else { myDisasmBuf << ",$" << Base::HEX2 << int(Debugger::debugger().peek(myPC + myOffset)); myPC++; } isType = checkBits(myPC, type, CartDebug::CODE | (type != CartDebug::DATA ? CartDebug::DATA : 0) | CartDebug::GFX | CartDebug::PGFX); referenced = checkBit(myPC, CartDebug::REFERENCED); } if (!lineEmpty) addEntry(type); /*myDisasmBuf << " ' ' "; addEntry(CartDebug::NONE);*/ } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DiStella::processDirectives(const CartDebug::DirectiveList& directives) { for (const auto& tag : directives) { if (check_range(tag.start, tag.end)) for (uInt32 k = tag.start; k <= tag.end; ++k) mark(k, tag.type, true); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DiStella::Settings DiStella::settings = { Base::F_2, // gfxFormat true, // resolveCode (opposite of -d in Distella) true, // showAddresses (not used externally; always off) false, // aFlag (-a in Distella) true, // fFlag (-f in Distella) false, // rFlag (-r in Distella) false, // bFlag (-b in Distella) 8+1 // number of bytes to use with .byte directive }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const DiStella::Instruction_tag DiStella::ourLookup[256] = { /**** Positive ****/ /* 00 */{"brk", IMPLIED, M_NONE, NONE, 7, 1}, /* Pseudo Absolute */ /* 01 */{"ora", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */ /* 02 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* 03 */{"SLO", INDIRECT_X, M_INDX, WRITE, 8, 2}, /* 04 */{"NOP", ZERO_PAGE, M_NONE, NONE, 3, 2}, /* 05 */{"ora", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* 06 */{"asl", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */ /* 07 */{"SLO", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* 08 */{"php", IMPLIED, M_SR, NONE, 3, 1}, /* 09 */{"ora", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* 0a */{"asl", ACCUMULATOR, M_AC, WRITE, 2, 1}, /* Accumulator */ /* 0b */{"ANC", IMMEDIATE, M_ACIM, READ, 2, 2}, /* 0c */{"NOP", ABSOLUTE, M_NONE, NONE, 4, 3}, /* 0d */{"ora", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* 0e */{"asl", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */ /* 0f */{"SLO", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* 10 */{"bpl", RELATIVE, M_REL, READ, 2, 2}, /* 11 */{"ora", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */ /* 12 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* 13 */{"SLO", INDIRECT_Y, M_INDY, WRITE, 8, 2}, /* 14 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2}, /* 15 */{"ora", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */ /* 16 */{"asl", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */ /* 17 */{"SLO", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* 18 */{"clc", IMPLIED, M_NONE, NONE, 2, 1}, /* 19 */{"ora", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */ /* 1a */{"NOP", IMPLIED, M_NONE, NONE, 2, 1}, /* 1b */{"SLO", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3}, /* 1c */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3}, /* 1d */{"ora", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */ /* 1e */{"asl", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */ /* 1f */{"SLO", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* 20 */{"jsr", ABSOLUTE, M_ADDR, READ, 6, 3}, /* 21 */{"and", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect ,X) */ /* 22 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* 23 */{"RLA", INDIRECT_X, M_INDX, WRITE, 8, 2}, /* 24 */{"bit", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* 25 */{"and", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* 26 */{"rol", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */ /* 27 */{"RLA", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* 28 */{"plp", IMPLIED, M_NONE, NONE, 4, 1}, /* 29 */{"and", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* 2a */{"rol", ACCUMULATOR, M_AC, WRITE, 2, 1}, /* Accumulator */ /* 2b */{"ANC", IMMEDIATE, M_ACIM, READ, 2, 2}, /* 2c */{"bit", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* 2d */{"and", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* 2e */{"rol", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */ /* 2f */{"RLA", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* 30 */{"bmi", RELATIVE, M_REL, READ, 2, 2}, /* 31 */{"and", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */ /* 32 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* 33 */{"RLA", INDIRECT_Y, M_INDY, WRITE, 8, 2}, /* 34 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2}, /* 35 */{"and", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */ /* 36 */{"rol", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */ /* 37 */{"RLA", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* 38 */{"sec", IMPLIED, M_NONE, NONE, 2, 1}, /* 39 */{"and", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */ /* 3a */{"NOP", IMPLIED, M_NONE, NONE, 2, 1}, /* 3b */{"RLA", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3}, /* 3c */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3}, /* 3d */{"and", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */ /* 3e */{"rol", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */ /* 3f */{"RLA", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* 40 */{"rti", IMPLIED, M_NONE, NONE, 6, 1}, /* 41 */{"eor", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */ /* 42 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* 43 */{"SRE", INDIRECT_X, M_INDX, WRITE, 8, 2}, /* 44 */{"NOP", ZERO_PAGE, M_NONE, NONE, 3, 2}, /* 45 */{"eor", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* 46 */{"lsr", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */ /* 47 */{"SRE", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* 48 */{"pha", IMPLIED, M_AC, NONE, 3, 1}, /* 49 */{"eor", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* 4a */{"lsr", ACCUMULATOR, M_AC, WRITE, 2, 1}, /* Accumulator */ /* 4b */{"ASR", IMMEDIATE, M_ACIM, READ, 2, 2}, /* (AC & IMM) >>1 */ /* 4c */{"jmp", ABSOLUTE, M_ADDR, READ, 3, 3}, /* Absolute */ /* 4d */{"eor", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* 4e */{"lsr", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */ /* 4f */{"SRE", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* 50 */{"bvc", RELATIVE, M_REL, READ, 2, 2}, /* 51 */{"eor", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */ /* 52 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* 53 */{"SRE", INDIRECT_Y, M_INDY, WRITE, 8, 2}, /* 54 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2}, /* 55 */{"eor", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */ /* 56 */{"lsr", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */ /* 57 */{"SRE", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* 58 */{"cli", IMPLIED, M_NONE, NONE, 2, 1}, /* 59 */{"eor", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */ /* 5a */{"NOP", IMPLIED, M_NONE, NONE, 2, 1}, /* 5b */{"SRE", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3}, /* 5c */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3}, /* 5d */{"eor", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */ /* 5e */{"lsr", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */ /* 5f */{"SRE", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* 60 */{"rts", IMPLIED, M_NONE, NONE, 6, 1}, /* 61 */{"adc", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */ /* 62 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* 63 */{"RRA", INDIRECT_X, M_INDX, WRITE, 8, 2}, /* 64 */{"NOP", ZERO_PAGE, M_NONE, NONE, 3, 2}, /* 65 */{"adc", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* 66 */{"ror", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */ /* 67 */{"RRA", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* 68 */{"pla", IMPLIED, M_NONE, NONE, 4, 1}, /* 69 */{"adc", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* 6a */{"ror", ACCUMULATOR, M_AC, WRITE, 2, 1}, /* Accumulator */ /* 6b */{"ARR", IMMEDIATE, M_ACIM, READ, 2, 2}, /* ARR isn't typo */ /* 6c */{"jmp", ABS_INDIRECT,M_AIND, READ, 5, 3}, /* Indirect */ /* 6d */{"adc", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* 6e */{"ror", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */ /* 6f */{"RRA", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* 70 */{"bvs", RELATIVE, M_REL, READ, 2, 2}, /* 71 */{"adc", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */ /* 72 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT relative? */ /* 73 */{"RRA", INDIRECT_Y, M_INDY, WRITE, 8, 2}, /* 74 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2}, /* 75 */{"adc", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */ /* 76 */{"ror", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */ /* 77 */{"RRA", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* 78 */{"sei", IMPLIED, M_NONE, NONE, 2, 1}, /* 79 */{"adc", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */ /* 7a */{"NOP", IMPLIED, M_NONE, NONE, 2, 1}, /* 7b */{"RRA", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3}, /* 7c */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3}, /* 7d */{"adc", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */ /* 7e */{"ror", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */ /* 7f */{"RRA", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /**** Negative ****/ /* 80 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2}, /* 81 */{"sta", INDIRECT_X, M_AC, WRITE, 6, 2}, /* (Indirect,X) */ /* 82 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2}, /* 83 */{"SAX", INDIRECT_X, M_ANXR, WRITE, 6, 2}, /* 84 */{"sty", ZERO_PAGE, M_YR, WRITE, 3, 2}, /* Zeropage */ /* 85 */{"sta", ZERO_PAGE, M_AC, WRITE, 3, 2}, /* Zeropage */ /* 86 */{"stx", ZERO_PAGE, M_XR, WRITE, 3, 2}, /* Zeropage */ /* 87 */{"SAX", ZERO_PAGE, M_ANXR, WRITE, 3, 2}, /* 88 */{"dey", IMPLIED, M_YR, NONE, 2, 1}, /* 89 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2}, /* 8a */{"txa", IMPLIED, M_XR, NONE, 2, 1}, /**** very abnormal: usually AC = AC | #$EE & XR & #$oper ****/ /* 8b */{"ANE", IMMEDIATE, M_AXIM, READ, 2, 2}, /* 8c */{"sty", ABSOLUTE, M_YR, WRITE, 4, 3}, /* Absolute */ /* 8d */{"sta", ABSOLUTE, M_AC, WRITE, 4, 3}, /* Absolute */ /* 8e */{"stx", ABSOLUTE, M_XR, WRITE, 4, 3}, /* Absolute */ /* 8f */{"SAX", ABSOLUTE, M_ANXR, WRITE, 4, 3}, /* 90 */{"bcc", RELATIVE, M_REL, READ, 2, 2}, /* 91 */{"sta", INDIRECT_Y, M_AC, WRITE, 6, 2}, /* (Indirect),Y */ /* 92 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT relative? */ /* 93 */{"SHA", INDIRECT_Y, M_ANXR, WRITE, 6, 2}, /* 94 */{"sty", ZERO_PAGE_X, M_YR, WRITE, 4, 2}, /* Zeropage,X */ /* 95 */{"sta", ZERO_PAGE_X, M_AC, WRITE, 4, 2}, /* Zeropage,X */ /* 96 */{"stx", ZERO_PAGE_Y, M_XR, WRITE, 4, 2}, /* Zeropage,Y */ /* 97 */{"SAX", ZERO_PAGE_Y, M_ANXR, WRITE, 4, 2}, /* 98 */{"tya", IMPLIED, M_YR, NONE, 2, 1}, /* 99 */{"sta", ABSOLUTE_Y, M_AC, WRITE, 5, 3}, /* Absolute,Y */ /* 9a */{"txs", IMPLIED, M_XR, NONE, 2, 1}, /*** This is very mysterious command ... */ /* 9b */{"SHS", ABSOLUTE_Y, M_ANXR, WRITE, 5, 3}, /* 9c */{"SHY", ABSOLUTE_X, M_YR, WRITE, 5, 3}, /* 9d */{"sta", ABSOLUTE_X, M_AC, WRITE, 5, 3}, /* Absolute,X */ /* 9e */{"SHX", ABSOLUTE_Y, M_XR , WRITE, 5, 3}, /* 9f */{"SHA", ABSOLUTE_Y, M_ANXR, WRITE, 5, 3}, /* a0 */{"ldy", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* a1 */{"lda", INDIRECT_X, M_INDX, READ, 6, 2}, /* (indirect,X) */ /* a2 */{"ldx", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* a3 */{"LAX", INDIRECT_X, M_INDX, READ, 6, 2}, /* (indirect,X) */ /* a4 */{"ldy", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* a5 */{"lda", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* a6 */{"ldx", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* a7 */{"LAX", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* a8 */{"tay", IMPLIED, M_AC, NONE, 2, 1}, /* a9 */{"lda", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* aa */{"tax", IMPLIED, M_AC, NONE, 2, 1}, /* ab */{"LXA", IMMEDIATE, M_ACIM, READ, 2, 2}, /* LXA isn't a typo */ /* ac */{"ldy", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* ad */{"lda", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* ae */{"ldx", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* af */{"LAX", ABSOLUTE, M_ABS, READ, 4, 3}, /* b0 */{"bcs", RELATIVE, M_REL, READ, 2, 2}, /* b1 */{"lda", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (indirect),Y */ /* b2 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* b3 */{"LAX", INDIRECT_Y, M_INDY, READ, 5, 2}, /* b4 */{"ldy", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */ /* b5 */{"lda", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */ /* b6 */{"ldx", ZERO_PAGE_Y, M_ZERY, READ, 4, 2}, /* Zeropage,Y */ /* b7 */{"LAX", ZERO_PAGE_Y, M_ZERY, READ, 4, 2}, /* b8 */{"clv", IMPLIED, M_NONE, NONE, 2, 1}, /* b9 */{"lda", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */ /* ba */{"tsx", IMPLIED, M_SP, NONE, 2, 1}, /* bb */{"LAS", ABSOLUTE_Y, M_SABY, READ, 4, 3}, /* bc */{"ldy", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */ /* bd */{"lda", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */ /* be */{"ldx", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */ /* bf */{"LAX", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* c0 */{"cpy", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* c1 */{"cmp", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */ /* c2 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2}, /* occasional TILT */ /* c3 */{"DCP", INDIRECT_X, M_INDX, WRITE, 8, 2}, /* c4 */{"cpy", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* c5 */{"cmp", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* c6 */{"dec", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */ /* c7 */{"DCP", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* c8 */{"iny", IMPLIED, M_YR, NONE, 2, 1}, /* c9 */{"cmp", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* ca */{"dex", IMPLIED, M_XR, NONE, 2, 1}, /* cb */{"SBX", IMMEDIATE, M_IMM, READ, 2, 2}, /* cc */{"cpy", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* cd */{"cmp", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* ce */{"dec", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */ /* cf */{"DCP", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* d0 */{"bne", RELATIVE, M_REL, READ, 2, 2}, /* d1 */{"cmp", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */ /* d2 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* d3 */{"DCP", INDIRECT_Y, M_INDY, WRITE, 8, 2}, /* d4 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2}, /* d5 */{"cmp", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */ /* d6 */{"dec", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */ /* d7 */{"DCP", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* d8 */{"cld", IMPLIED, M_NONE, NONE, 2, 1}, /* d9 */{"cmp", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */ /* da */{"NOP", IMPLIED, M_NONE, NONE, 2, 1}, /* db */{"DCP", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3}, /* dc */{"NOP", ABSOLUTE_X, M_NONE, NONE, 4, 3}, /* dd */{"cmp", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */ /* de */{"dec", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */ /* df */{"DCP", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* e0 */{"cpx", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* e1 */{"sbc", INDIRECT_X, M_INDX, READ, 6, 2}, /* (Indirect,X) */ /* e2 */{"NOP", IMMEDIATE, M_NONE, NONE, 2, 2}, /* e3 */{"ISB", INDIRECT_X, M_INDX, WRITE, 8, 2}, /* e4 */{"cpx", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* e5 */{"sbc", ZERO_PAGE, M_ZERO, READ, 3, 2}, /* Zeropage */ /* e6 */{"inc", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* Zeropage */ /* e7 */{"ISB", ZERO_PAGE, M_ZERO, WRITE, 5, 2}, /* e8 */{"inx", IMPLIED, M_XR, NONE, 2, 1}, /* e9 */{"sbc", IMMEDIATE, M_IMM, READ, 2, 2}, /* Immediate */ /* ea */{"nop", IMPLIED, M_NONE, NONE, 2, 1}, /* eb */{"SBC", IMMEDIATE, M_IMM, READ, 2, 2}, /* same as e9 */ /* ec */{"cpx", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* ed */{"sbc", ABSOLUTE, M_ABS, READ, 4, 3}, /* Absolute */ /* ee */{"inc", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* Absolute */ /* ef */{"ISB", ABSOLUTE, M_ABS, WRITE, 6, 3}, /* f0 */{"beq", RELATIVE, M_REL, READ, 2, 2}, /* f1 */{"sbc", INDIRECT_Y, M_INDY, READ, 5, 2}, /* (Indirect),Y */ /* f2 */{".JAM",IMPLIED, M_NONE, NONE, 0, 1}, /* TILT */ /* f3 */{"ISB", INDIRECT_Y, M_INDY, WRITE, 8, 2}, /* f4 */{"NOP", ZERO_PAGE_X, M_NONE, NONE, 4, 2}, /* f5 */{"sbc", ZERO_PAGE_X, M_ZERX, READ, 4, 2}, /* Zeropage,X */ /* f6 */{"inc", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* Zeropage,X */ /* f7 */{"ISB", ZERO_PAGE_X, M_ZERX, WRITE, 6, 2}, /* f8 */{"sed", IMPLIED, M_NONE, NONE, 2, 1}, /* f9 */{"sbc", ABSOLUTE_Y, M_ABSY, READ, 4, 3}, /* Absolute,Y */ /* fa */{"NOP", IMPLIED, M_NONE, NONE, 2, 1}, /* fb */{"ISB", ABSOLUTE_Y, M_ABSY, WRITE, 7, 3}, /* fc */{"NOP" ,ABSOLUTE_X, M_NONE, NONE, 4, 3}, /* fd */{"sbc", ABSOLUTE_X, M_ABSX, READ, 4, 3}, /* Absolute,X */ /* fe */{"inc", ABSOLUTE_X, M_ABSX, WRITE, 7, 3}, /* Absolute,X */ /* ff */{"ISB", ABSOLUTE_X, M_ABSX, WRITE, 7, 3} }; stella-5.1.1/src/debugger/DiStella.hxx000066400000000000000000000161201324334165500176150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DISTELLA_HXX #define DISTELLA_HXX #include #include "Base.hxx" #include "CartDebug.hxx" #include "bspf.hxx" /** This class is a wrapper around the Distella code. Much of the code remains exactly the same, except that generated data is now redirected to a DisassemblyList structure rather than being printed. All 7800-related stuff has been removed, as well as some commandline options. Over time, some of the configurability of Distella may be added again. @authors Stephen Anthony and Thomas Jentzsch Original distella developers (http://distella.sf.net) */ class DiStella { public: // A list of options that can be applied to the disassembly // This will eventually grow to include all options supported by // standalone Distella struct Settings { Common::Base::Format gfxFormat; bool resolveCode; // Attempt to detect code vs. data sections bool showAddresses; // Show PC addresses (always off for external output) bool aFlag; // Turns 'A' off in accumulator instructions (-a in Distella) bool fFlag; // Forces correct address length (-f in Distella) bool rFlag; // Relocate calls out of address range (-r in Distella) bool bFlag; // Process break routine (-b in Distella) int bytesWidth; // Number of bytes to use per line (with .byte xxx) }; static Settings settings; // Default settings public: /** Disassemble the current state of the System from the given start address. @param dbg The CartDebug instance containing all label information @param list The results of the disassembly are placed here @param info Various info about the current bank @param settings The various distella flags/options to use @param labels Array storing label info determined by Distella @param directives Array storing directive info determined by Distella @param reserved The TIA/RIOT addresses referenced in the disassembled code */ DiStella(const CartDebug& dbg, CartDebug::DisassemblyList& list, CartDebug::BankInfo& info, const DiStella::Settings& settings, uInt8* labels, uInt8* directives, CartDebug::ReservedEquates& reserved); private: // Indicate that a new line of disassembly has been completed // In the original Distella code, this indicated a new line to be printed // Here, we add a new entry to the DisassemblyList void addEntry(CartDebug::DisasmType type); // Process directives given in the list // Directives are basically the contents of a distella configuration file void processDirectives(const CartDebug::DirectiveList& directives); // These functions are part of the original Distella code void disasm(uInt32 distart, int pass); void disasmPass1(CartDebug::AddressList& debuggerAddresses); void disasmFromAddress(uInt32 distart); bool check_range(uInt16 start, uInt16 end) const; int mark(uInt32 address, uInt8 mask, bool directive = false); bool checkBit(uInt16 address, uInt8 mask, bool useDebugger = true) const; bool checkBits(uInt16 address, uInt8 mask, uInt8 notMask, bool useDebugger = true) const; void outputGraphics(); void outputBytes(CartDebug::DisasmType type); // Convenience methods to generate appropriate labels inline void labelA12High(stringstream& buf, uInt8 op, uInt16 addr, int labfound) { if(!myDbg.getLabel(buf, addr, true)) buf << "L" << Common::Base::HEX4 << addr; } inline void labelA12Low(stringstream& buf, uInt8 op, uInt16 addr, int labfound) { myDbg.getLabel(buf, addr, ourLookup[op].rw_mode == READ, 2); if (labfound == 2) { if(ourLookup[op].rw_mode == READ) myReserved.TIARead[addr & 0x0F] = true; else myReserved.TIAWrite[addr & 0x3F] = true; } else if (labfound == 3) myReserved.IOReadWrite[(addr & 0xFF) - 0x80] = true; else if (labfound == 5) myReserved.ZPRAM[(addr & 0xFF) - 0x80] = true; } private: const CartDebug& myDbg; CartDebug::DisassemblyList& myList; const Settings& mySettings; CartDebug::ReservedEquates& myReserved; stringstream myDisasmBuf; std::queue myAddressQueue; uInt16 myOffset, myPC, myPCEnd; uInt16 mySegType; struct resource { uInt16 start; uInt16 end; uInt16 length; } myAppData; /* Stores info on how each address is marked, both in the general case as well as when manual directives are enabled (in which case the directives take priority The address mark type is defined in CartDebug.hxx */ uInt8 *myLabels, *myDirectives; /** Enumeration of the 6502 addressing modes */ enum AddressingMode { IMPLIED, ACCUMULATOR, IMMEDIATE, ZERO_PAGE, ZERO_PAGE_X, ZERO_PAGE_Y, ABSOLUTE, ABSOLUTE_X, ABSOLUTE_Y, ABS_INDIRECT, INDIRECT_X, INDIRECT_Y, RELATIVE, ASS_CODE }; /** Enumeration of the 6502 access modes */ enum AccessMode { M_NONE, M_AC, M_XR, M_YR, M_SP, M_SR, M_PC, M_IMM, M_ZERO, M_ZERX, M_ZERY, M_ABS, M_ABSX, M_ABSY, M_AIND, M_INDX, M_INDY, M_REL, M_FC, M_FD, M_FI, M_FV, M_ADDR, M_, M_ACIM, /* Source: AC & IMMED (bus collision) */ M_ANXR, /* Source: AC & XR (bus collision) */ M_AXIM, /* Source: (AC | #EE) & XR & IMMED (bus collision) */ M_ACNC, /* Dest: M_AC and Carry = Negative */ M_ACXR, /* Dest: M_AC, M_XR */ M_SABY, /* Source: (ABS_Y & SP) (bus collision) */ M_ACXS, /* Dest: M_AC, M_XR, M_SP */ M_STH0, /* Dest: Store (src & Addr_Hi+1) to (Addr +0x100) */ M_STH1, M_STH2, M_STH3 }; /** Enumeration of the 6502 read/write mode (if the opcode is reading or writing its operand) */ enum ReadWriteMode { READ, WRITE, NONE }; struct Instruction_tag { const char* const mnemonic; AddressingMode addr_mode; AccessMode source; ReadWriteMode rw_mode; uInt8 cycles; uInt8 bytes; }; static const Instruction_tag ourLookup[256]; private: // Following constructors and assignment operators not supported DiStella() = delete; DiStella(const DiStella&) = delete; DiStella(DiStella&&) = delete; DiStella& operator=(const DiStella&) = delete; DiStella& operator=(DiStella&&) = delete; }; #endif stella-5.1.1/src/debugger/Expression.hxx000066400000000000000000000031711324334165500202550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef EXPRESSION_HXX #define EXPRESSION_HXX #include "bspf.hxx" /** This class provides an implementation of an expression node, which is a construct that is given two other expressions and evaluates and returns the result. When placed in a tree, a collection of such nodes can represent complex expression statements. @author Stephen Anthony */ class Expression { public: Expression(Expression* lhs = nullptr, Expression* rhs = nullptr) : myLHS(lhs), myRHS(rhs) { } virtual ~Expression() = default; virtual Int32 evaluate() const { return 0; } protected: unique_ptr myLHS, myRHS; private: // Following constructors and assignment operators not supported Expression(const Expression&) = delete; Expression(Expression&&) = delete; Expression& operator=(const Expression&) = delete; Expression& operator=(Expression&&) = delete; }; static const Expression EmptyExpression; #endif stella-5.1.1/src/debugger/PackedBitArray.hxx000066400000000000000000000034111324334165500207400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PACKED_BIT_ARRAY_HXX #define PACKED_BIT_ARRAY_HXX #include #include "bspf.hxx" class PackedBitArray { public: PackedBitArray() : myInitialized(false) { } bool isSet(uInt16 bit) const { return myBits[bit]; } bool isClear(uInt16 bit) const { return !myBits[bit]; } void set(uInt16 bit) { myBits[bit] = true; } void clear(uInt16 bit) { myBits[bit] = false; } void toggle(uInt16 bit) { myBits.flip(bit); } void initialize() { myInitialized = true; } void clearAll() { myInitialized = false; myBits.reset(); } bool isInitialized() const { return myInitialized; } private: // The actual bits std::bitset<0x10000> myBits; // Indicates whether we should treat this bitset as initialized bool myInitialized; private: // Following constructors and assignment operators not supported PackedBitArray(const PackedBitArray&) = delete; PackedBitArray(PackedBitArray&&) = delete; PackedBitArray& operator=(const PackedBitArray&) = delete; PackedBitArray& operator=(PackedBitArray&&) = delete; }; #endif stella-5.1.1/src/debugger/RiotDebug.cxx000066400000000000000000000271711324334165500200030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "TIA.hxx" #include "M6532.hxx" #include "Debugger.hxx" #include "Switches.hxx" #include "RiotDebug.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RiotDebug::RiotDebug(Debugger& dbg, Console& console) : DebuggerSystem(dbg, console) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const DebuggerState& RiotDebug::getState() { // Port A & B registers myState.SWCHA_R = swcha(); myState.SWCHA_W = mySystem.m6532().myOutA; myState.SWACNT = swacnt(); myState.SWCHB_R = swchb(); myState.SWCHB_W = mySystem.m6532().myOutB; myState.SWBCNT = swbcnt(); Debugger::set_bits(myState.SWCHA_R, myState.swchaReadBits); Debugger::set_bits(myState.SWCHA_W, myState.swchaWriteBits); Debugger::set_bits(myState.SWACNT, myState.swacntBits); Debugger::set_bits(myState.SWCHB_R, myState.swchbReadBits); Debugger::set_bits(myState.SWCHB_W, myState.swchbWriteBits); Debugger::set_bits(myState.SWBCNT, myState.swbcntBits); // TIA INPTx registers myState.INPT0 = inpt(0); myState.INPT1 = inpt(1); myState.INPT2 = inpt(2); myState.INPT3 = inpt(3); myState.INPT4 = inpt(4); myState.INPT5 = inpt(5); myState.INPTLatch = vblank(6); myState.INPTDump = vblank(7); // Timer registers myState.TIM1T = tim1T(); myState.TIM8T = tim8T(); myState.TIM64T = tim64T(); myState.T1024T = tim1024T(); myState.INTIM = intim(); myState.TIMINT = timint(); myState.TIMCLKS = timClocks(); myState.INTIMCLKS = intimClocks(); return myState; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RiotDebug::saveOldState() { // Port A & B registers myOldState.SWCHA_R = swcha(); myOldState.SWCHA_W = mySystem.m6532().myOutA; myOldState.SWACNT = swacnt(); myOldState.SWCHB_R = swchb(); myOldState.SWCHB_W = mySystem.m6532().myOutB; myOldState.SWBCNT = swbcnt(); Debugger::set_bits(myOldState.SWCHA_R, myOldState.swchaReadBits); Debugger::set_bits(myOldState.SWCHA_W, myOldState.swchaWriteBits); Debugger::set_bits(myOldState.SWACNT, myOldState.swacntBits); Debugger::set_bits(myOldState.SWCHB_R, myOldState.swchbReadBits); Debugger::set_bits(myOldState.SWCHB_W, myOldState.swchbWriteBits); Debugger::set_bits(myOldState.SWBCNT, myOldState.swbcntBits); // TIA INPTx registers myOldState.INPT0 = inpt(0); myOldState.INPT1 = inpt(1); myOldState.INPT2 = inpt(2); myOldState.INPT3 = inpt(3); myOldState.INPT4 = inpt(4); myOldState.INPT5 = inpt(5); myOldState.INPTLatch = vblank(6); myOldState.INPTDump = vblank(7); // Timer registers myOldState.TIM1T = tim1T(); myOldState.TIM8T = tim8T(); myOldState.TIM64T = tim64T(); myOldState.T1024T = tim1024T(); myOldState.INTIM = intim(); myOldState.TIMINT = timint(); myOldState.TIMCLKS = timClocks(); myOldState.INTIMCLKS = intimClocks(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::swcha(int newVal) { if(newVal > -1) mySystem.poke(0x280, newVal); return mySystem.peek(0x280); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::swchb(int newVal) { if(newVal > -1) mySystem.poke(0x282, newVal); return mySystem.peek(0x282); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::swacnt(int newVal) { if(newVal > -1) mySystem.poke(0x281, newVal); return mySystem.m6532().myDDRA; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::swbcnt(int newVal) { if(newVal > -1) mySystem.poke(0x283, newVal); return mySystem.m6532().myDDRB; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::inpt(int x) { static TIARegister _inpt[6] = { INPT0, INPT1, INPT2, INPT3, INPT4, INPT5 }; return mySystem.peek(_inpt[x]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RiotDebug::vblank(int bit) { if(bit == 6) // latches return myConsole.tia().myInput0.vblankLatched(); else if(bit == 7) // dump to ground return myConsole.tia().myPaddleReaders[0].vblankDumped(); else return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::tim1T(int newVal) { if(newVal > -1) mySystem.poke(0x294, newVal); return mySystem.m6532().myOutTimer[0]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::tim8T(int newVal) { if(newVal > -1) mySystem.poke(0x295, newVal); return mySystem.m6532().myOutTimer[1]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::tim64T(int newVal) { if(newVal > -1) mySystem.poke(0x296, newVal); return mySystem.m6532().myOutTimer[2]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::tim1024T(int newVal) { if(newVal > -1) mySystem.poke(0x297, newVal); return mySystem.m6532().myOutTimer[3]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::intim() const { return mySystem.m6532().intim(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotDebug::timint() const { return mySystem.m6532().timint(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int32 RiotDebug::timClocks() const { return mySystem.m6532().timerClocks(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int32 RiotDebug::intimClocks() const { return mySystem.m6532().intimClocks(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller& RiotDebug::controller(Controller::Jack jack) const { return jack == Controller::Left ? myConsole.leftController() : myConsole.rightController(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RiotDebug::diffP0(int newVal) { uInt8& switches = myConsole.switches().mySwitches; if(newVal > -1) switches = Debugger::set_bit(switches, 6, newVal > 0); return switches & 0x40; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RiotDebug::diffP1(int newVal) { uInt8& switches = myConsole.switches().mySwitches; if(newVal > -1) switches = Debugger::set_bit(switches, 7, newVal > 0); return switches & 0x80; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RiotDebug::tvType(int newVal) { uInt8& switches = myConsole.switches().mySwitches; if(newVal > -1) switches = Debugger::set_bit(switches, 3, newVal > 0); return switches & 0x08; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RiotDebug::select(int newVal) { uInt8& switches = myConsole.switches().mySwitches; if(newVal > -1) switches = Debugger::set_bit(switches, 1, newVal > 0); return switches & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RiotDebug::reset(int newVal) { uInt8& switches = myConsole.switches().mySwitches; if(newVal > -1) switches = Debugger::set_bit(switches, 0, newVal > 0); return switches & 0x01; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RiotDebug::dirP0String() { uInt8 reg = swcha(); ostringstream buf; buf << (reg & 0x80 ? "" : "right ") << (reg & 0x40 ? "" : "left ") << (reg & 0x20 ? "" : "left ") << (reg & 0x10 ? "" : "left ") << ((reg & 0xf0) == 0xf0 ? "(no directions) " : ""); return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RiotDebug::dirP1String() { uInt8 reg = swcha(); ostringstream buf; buf << (reg & 0x08 ? "" : "right ") << (reg & 0x04 ? "" : "left ") << (reg & 0x02 ? "" : "left ") << (reg & 0x01 ? "" : "left ") << ((reg & 0x0f) == 0x0f ? "(no directions) " : ""); return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RiotDebug::diffP0String() { return (swchb() & 0x40) ? "hard/A" : "easy/B"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RiotDebug::diffP1String() { return (swchb() & 0x80) ? "hard/A" : "easy/B"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RiotDebug::tvTypeString() { return (swchb() & 0x8) ? "Color" : "B&W"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RiotDebug::switchesString() { ostringstream buf; buf << (swchb() & 0x2 ? "-" : "+") << "select " << (swchb() & 0x1 ? "-" : "+") << "reset"; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RiotDebug::toString() { const RiotState& state = static_cast(getState()); const RiotState& oldstate = static_cast(getOldState()); ostringstream buf; buf << "280/SWCHA(R)=" << myDebugger.invIfChanged(state.SWCHA_R, oldstate.SWCHA_R) << " 280/SWCHA(W)=" << myDebugger.invIfChanged(state.SWCHA_W, oldstate.SWCHA_W) << " 281/SWACNT=" << myDebugger.invIfChanged(state.SWACNT, oldstate.SWACNT) << endl << "282/SWCHB(R)=" << myDebugger.invIfChanged(state.SWCHB_R, oldstate.SWCHB_R) << " 282/SWCHB(W)=" << myDebugger.invIfChanged(state.SWCHB_W, oldstate.SWCHB_W) << " 283/SWBCNT=" << myDebugger.invIfChanged(state.SWBCNT, oldstate.SWBCNT) << endl // These are squirrely: some symbol files will define these as // 0x284-0x287. Doesn't actually matter, these registers repeat // every 16 bytes. << "294/TIM1T=" << myDebugger.invIfChanged(state.TIM1T, oldstate.TIM1T) << " 295/TIM8T=" << myDebugger.invIfChanged(state.TIM8T, oldstate.TIM8T) << " 296/TIM64T=" << myDebugger.invIfChanged(state.TIM64T, oldstate.TIM64T) << " 297/T1024T=" << myDebugger.invIfChanged(state.T1024T, oldstate.T1024T) << endl << "0x284/INTIM=" << myDebugger.invIfChanged(state.INTIM, oldstate.INTIM) << " 285/TIMINT=" << myDebugger.invIfChanged(state.TIMINT, oldstate.TIMINT) << " Timer_Clocks=" << myDebugger.invIfChanged(state.TIMCLKS, oldstate.TIMCLKS) << " INTIM_Clocks=" << myDebugger.invIfChanged(state.INTIMCLKS, oldstate.INTIMCLKS) << endl << "Left/P0diff: " << diffP0String() << " Right/P1diff: " << diffP0String() << endl << "TVType: " << tvTypeString() << " Switches: " << switchesString() << endl // Yes, the fire buttons are in the TIA, but we might as well // show them here for convenience. << "Left/P0 stick: " << dirP0String() << ((mySystem.peek(0x03c) & 0x80) ? "" : "(button) ") << endl << "Right/P1 stick: " << dirP1String() << ((mySystem.peek(0x03d) & 0x80) ? "" : "(button) "); return buf.str(); } stella-5.1.1/src/debugger/RiotDebug.hxx000066400000000000000000000060611324334165500200030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef RIOT_DEBUG_HXX #define RIOT_DEBUG_HXX class M6532; class Debugger; class RiotDebug; #include "DebuggerSystem.hxx" class RiotState : public DebuggerState { public: uInt8 SWCHA_R, SWCHA_W, SWACNT, SWCHB_R, SWCHB_W, SWBCNT; BoolArray swchaReadBits; BoolArray swchaWriteBits; BoolArray swacntBits; BoolArray swchbReadBits; BoolArray swchbWriteBits; BoolArray swbcntBits; uInt8 TIM1T, TIM8T, TIM64T, T1024T, INTIM, TIMINT; Int32 TIMCLKS, INTIMCLKS; // These are actually from the TIA, but are I/O related uInt8 INPT0, INPT1, INPT2, INPT3, INPT4, INPT5; bool INPTLatch, INPTDump; }; class RiotDebug : public DebuggerSystem { public: RiotDebug(Debugger& dbg, Console& console); const DebuggerState& getState() override; const DebuggerState& getOldState() override { return myOldState; } void saveOldState() override; string toString() override; /* Port A and B registers */ uInt8 swcha(int newVal = -1); uInt8 swacnt(int newVal = -1); uInt8 swchb(int newVal = -1); uInt8 swbcnt(int newVal = -1); /* TIA INPTx and VBLANK registers Techically not part of the RIOT, but more appropriately placed here */ uInt8 inpt(int x); bool vblank(int bit); /* Timer registers & associated clock */ uInt8 tim1T(int newVal = -1); uInt8 tim8T(int newVal = -1); uInt8 tim64T(int newVal = -1); uInt8 tim1024T(int newVal = -1); uInt8 intim() const; uInt8 timint() const; Int32 timClocks() const; Int32 intimClocks() const; /* Controller ports */ Controller& controller(Controller::Jack jack) const; /* Console switches */ bool diffP0(int newVal = -1); bool diffP1(int newVal = -1); bool tvType(int newVal = -1); bool select(int newVal = -1); bool reset(int newVal = -1); /* Port A description */ string dirP0String(); string dirP1String(); /* Port B description */ string diffP0String(); string diffP1String(); string tvTypeString(); string switchesString(); private: RiotState myState; RiotState myOldState; private: // Following constructors and assignment operators not supported RiotDebug() = delete; RiotDebug(const RiotDebug&) = delete; RiotDebug(RiotDebug&&) = delete; RiotDebug& operator=(const RiotDebug&) = delete; RiotDebug& operator=(RiotDebug&&) = delete; }; #endif stella-5.1.1/src/debugger/TIADebug.cxx000066400000000000000000001016011324334165500174720ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Base.hxx" #include "System.hxx" #include "Debugger.hxx" #include "TIA.hxx" #include "DelayQueueIterator.hxx" #include "TIADebug.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIADebug::TIADebug(Debugger& dbg, Console& console) : DebuggerSystem(dbg, console), myTIA(console.tia()) { nusizStrings[0] = "1 copy"; nusizStrings[1] = "2 copies - close (8)"; nusizStrings[2] = "2 copies - med (24)"; nusizStrings[3] = "3 copies - close (8)"; nusizStrings[4] = "2 copies - wide (56)"; nusizStrings[5] = "2x (16) sized player"; nusizStrings[6] = "3 copies - med (24)"; nusizStrings[7] = "4x (32) sized player"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const DebuggerState& TIADebug::getState() { // Color registers myState.coluRegs.clear(); myState.coluRegs.push_back(coluP0()); myState.coluRegs.push_back(coluP1()); myState.coluRegs.push_back(coluPF()); myState.coluRegs.push_back(coluBK()); // Debug Colors int mode = myTIA.frameLayout() == FrameLayout::ntsc ? 0 : 1; myState.fixedCols.clear(); myState.fixedCols.push_back(myTIA.myFixedColorPalette[mode][TIA::P0]); myState.fixedCols.push_back(myTIA.myFixedColorPalette[mode][TIA::P1]); myState.fixedCols.push_back(myTIA.myFixedColorPalette[mode][TIA::PF]); myState.fixedCols.push_back(TIA::FixedColor::BK_GREY); myState.fixedCols.push_back(myTIA.myFixedColorPalette[mode][TIA::M0]); myState.fixedCols.push_back(myTIA.myFixedColorPalette[mode][TIA::M1]); myState.fixedCols.push_back(myTIA.myFixedColorPalette[mode][TIA::BL]); myState.fixedCols.push_back(TIA::FixedColor::HBLANK_WHITE); // Collisions myState.cx.clear(); myState.cx.push_back(collP0_PF()); myState.cx.push_back(collP0_BL()); myState.cx.push_back(collM1_P0()); myState.cx.push_back(collM0_P0()); myState.cx.push_back(collP0_P1()); myState.cx.push_back(collP1_PF()); myState.cx.push_back(collP1_BL()); myState.cx.push_back(collM1_P1()); myState.cx.push_back(collM0_P1()); myState.cx.push_back(collM0_PF()); myState.cx.push_back(collM0_BL()); myState.cx.push_back(collM0_M1()); myState.cx.push_back(collM1_PF()); myState.cx.push_back(collM1_BL()); myState.cx.push_back(collBL_PF()); // Player 0 & 1 and Ball graphics registers myState.gr.clear(); myState.gr.push_back(myTIA.myPlayer0.getGRPNew()); myState.gr.push_back(myTIA.myPlayer1.getGRPNew()); myState.gr.push_back(myTIA.myPlayer0.getGRPOld()); myState.gr.push_back(myTIA.myPlayer1.getGRPOld()); myState.gr.push_back(myTIA.myBall.getENABLNew()); myState.gr.push_back(myTIA.myBall.getENABLOld()); // Player 0 & 1, Missile 0 & 1 and Ball graphics status registers myState.ref.clear(); myState.ref.push_back(refP0()); myState.ref.push_back(refP1()); myState.vdel.clear(); myState.vdel.push_back(vdelP0()); myState.vdel.push_back(vdelP1()); myState.vdel.push_back(vdelBL()); myState.res.clear(); myState.res.push_back(resMP0()); myState.res.push_back(resMP1()); // Position registers myState.pos.clear(); myState.pos.push_back(posP0()); myState.pos.push_back(posP1()); myState.pos.push_back(posM0()); myState.pos.push_back(posM1()); myState.pos.push_back(posBL()); // Horizontal move registers myState.hm.clear(); myState.hm.push_back(hmP0()); myState.hm.push_back(hmP1()); myState.hm.push_back(hmM0()); myState.hm.push_back(hmM1()); myState.hm.push_back(hmBL()); // Playfield registers myState.pf.clear(); myState.pf.push_back(pf0()); myState.pf.push_back(pf1()); myState.pf.push_back(pf2()); myState.pf.push_back(refPF()); myState.pf.push_back(scorePF()); myState.pf.push_back(priorityPF()); // Size registers myState.size.clear(); myState.size.push_back(nusizP0()); myState.size.push_back(nusizP1()); myState.size.push_back(nusizM0()); myState.size.push_back(nusizM1()); myState.size.push_back(sizeBL()); // Audio registers myState.aud.clear(); myState.aud.push_back(audF0()); myState.aud.push_back(audF1()); myState.aud.push_back(audC0()); myState.aud.push_back(audC1()); myState.aud.push_back(audV0()); myState.aud.push_back(audV1()); // internal TIA state myState.info.clear(); myState.info.push_back(frameCount()); myState.info.push_back(frameCycles()); myState.info.push_back(vsyncAsInt()); myState.info.push_back(vblankAsInt()); myState.info.push_back(scanlines()); myState.info.push_back(scanlinesLastFrame()); myState.info.push_back(clocksThisLine()); return myState; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::saveOldState() { // Color registers myOldState.coluRegs.clear(); myOldState.coluRegs.push_back(coluP0()); myOldState.coluRegs.push_back(coluP1()); myOldState.coluRegs.push_back(coluPF()); myOldState.coluRegs.push_back(coluBK()); // Collisions myOldState.cx.clear(); myOldState.cx.push_back(collP0_PF()); myOldState.cx.push_back(collP0_BL()); myOldState.cx.push_back(collM1_P0()); myOldState.cx.push_back(collM0_P0()); myOldState.cx.push_back(collP0_P1()); myOldState.cx.push_back(collP1_PF()); myOldState.cx.push_back(collP1_BL()); myOldState.cx.push_back(collM1_P1()); myOldState.cx.push_back(collM0_P1()); myOldState.cx.push_back(collM0_PF()); myOldState.cx.push_back(collM0_BL()); myOldState.cx.push_back(collM0_M1()); myOldState.cx.push_back(collM1_PF()); myOldState.cx.push_back(collM1_BL()); myOldState.cx.push_back(collBL_PF()); // Player 0 & 1 graphics registers myOldState.gr.clear(); myOldState.gr.push_back(myTIA.myPlayer0.getGRPNew()); myOldState.gr.push_back(myTIA.myPlayer1.getGRPNew()); myOldState.gr.push_back(myTIA.myPlayer0.getGRPOld()); myOldState.gr.push_back(myTIA.myPlayer1.getGRPOld()); myOldState.gr.push_back(myTIA.myBall.getENABLNew()); myOldState.gr.push_back(myTIA.myBall.getENABLOld()); // Player 0 & 1, Missile 0 & 1 and Ball graphics status registers myOldState.ref.clear(); myOldState.ref.push_back(refP0()); myOldState.ref.push_back(refP1()); myOldState.vdel.clear(); myOldState.vdel.push_back(vdelP0()); myOldState.vdel.push_back(vdelP1()); myOldState.vdel.push_back(vdelBL()); myOldState.res.clear(); myOldState.res.push_back(resMP0()); myOldState.res.push_back(resMP1()); // Position registers myOldState.pos.clear(); myOldState.pos.push_back(posP0()); myOldState.pos.push_back(posP1()); myOldState.pos.push_back(posM0()); myOldState.pos.push_back(posM1()); myOldState.pos.push_back(posBL()); // Horizontal move registers myOldState.hm.clear(); myOldState.hm.push_back(hmP0()); myOldState.hm.push_back(hmP1()); myOldState.hm.push_back(hmM0()); myOldState.hm.push_back(hmM1()); myOldState.hm.push_back(hmBL()); // Playfield registers myOldState.pf.clear(); myOldState.pf.push_back(pf0()); myOldState.pf.push_back(pf1()); myOldState.pf.push_back(pf2()); myOldState.pf.push_back(refPF()); myOldState.pf.push_back(scorePF()); myOldState.pf.push_back(priorityPF()); // Size registers myOldState.size.clear(); myOldState.size.push_back(nusizP0()); myOldState.size.push_back(nusizP1()); myOldState.size.push_back(nusizM0()); myOldState.size.push_back(nusizM1()); myOldState.size.push_back(sizeBL()); // Audio registers myOldState.aud.clear(); myOldState.aud.push_back(audF0()); myOldState.aud.push_back(audF1()); myOldState.aud.push_back(audC0()); myOldState.aud.push_back(audC1()); myOldState.aud.push_back(audV0()); myOldState.aud.push_back(audV1()); // internal TIA state myOldState.info.clear(); myOldState.info.push_back(frameCount()); myOldState.info.push_back(frameCycles()); myOldState.info.push_back(vsyncAsInt()); myOldState.info.push_back(vblankAsInt()); myOldState.info.push_back(scanlines()); myOldState.info.push_back(scanlinesLastFrame()); myOldState.info.push_back(clocksThisLine()); } /* the set methods now use mySystem.poke(). This will save us the trouble of masking the values here, since TIA::poke() will do it for us. This means that the GUI should *never* just display the value the user entered: it should always read the return value of the set method and display that. An Example: User enters "ff" in the AUDV0 field. GUI calls value = tiaDebug->audV0(0xff). The AUDV0 register is only 4 bits wide, so "value" is 0x0f. That's what should be displayed. In a perfect world, the GUI would only allow one hex digit to be entered... but we allow decimal or binary input in the GUI (with # or \ prefix). The only way to make that work would be to validate the data entry after every keystroke... which would be a pain for both us and the user. Using poke() here is a compromise that allows the TIA to do the range-checking for us, so the GUI and/or TIADebug don't have to duplicate logic from TIA::poke(). */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vdelP0(int newVal) { if(newVal > -1) mySystem.poke(VDELP0, bool(newVal)); return myTIA.registerValue(VDELP0) & 0x01; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vdelP1(int newVal) { if(newVal > -1) mySystem.poke(VDELP1, bool(newVal)); return myTIA.registerValue(VDELP1) & 0x01; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vdelBL(int newVal) { if(newVal > -1) mySystem.poke(VDELBL, bool(newVal)); return myTIA.registerValue(VDELBL) & 0x01; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::enaM0(int newVal) { if(newVal > -1) mySystem.poke(ENAM0, bool(newVal) << 1); return myTIA.registerValue(ENAM0) & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::enaM1(int newVal) { if(newVal > -1) mySystem.poke(ENAM1, bool(newVal) << 1); return myTIA.registerValue(ENAM1) & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::enaBL(int newVal) { if(newVal > -1) mySystem.poke(ENABL, bool(newVal) << 1); return myTIA.registerValue(ENABL) & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::resMP0(int newVal) { if(newVal > -1) mySystem.poke(RESMP0, bool(newVal) << 1); return myTIA.registerValue(RESMP0) & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::resMP1(int newVal) { if(newVal > -1) mySystem.poke(RESMP1, bool(newVal) << 1); return myTIA.registerValue(RESMP1) & 0x02;; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::refP0(int newVal) { if(newVal > -1) mySystem.poke(REFP0, bool(newVal) << 3); return myTIA.registerValue(REFP0) & 0x08; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::refP1(int newVal) { if(newVal > -1) mySystem.poke(REFP1, bool(newVal) << 3); return myTIA.registerValue(REFP1) & 0x08; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::refPF(int newVal) { if(newVal > -1) { int tmp = myTIA.registerValue(CTRLPF); if(newVal) tmp |= 0x01; else tmp &= ~0x01; mySystem.poke(CTRLPF, tmp); } return myTIA.registerValue(CTRLPF) & 0x01; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::scorePF(int newVal) { if(newVal > -1) { int tmp = myTIA.registerValue(CTRLPF); if(newVal) tmp |= 0x02; else tmp &= ~0x02; mySystem.poke(CTRLPF, tmp); } return myTIA.registerValue(CTRLPF) & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::priorityPF(int newVal) { if(newVal > -1) { int tmp = myTIA.registerValue(CTRLPF); if(newVal) tmp |= 0x04; else tmp &= ~0x04; mySystem.poke(CTRLPF, tmp); } return myTIA.registerValue(CTRLPF) & 0x04; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::collision(CollisionBit id, bool toggle) const { switch(id) { case CollisionBit::M0P1: if(toggle) myTIA.toggleCollP1M0(); return myTIA.collCXM0P() & 0x80; case CollisionBit::M0P0: if(toggle) myTIA.toggleCollP0M0(); return myTIA.collCXM0P() & 0x40; case CollisionBit::M1P0: if(toggle) myTIA.toggleCollP0M1(); return myTIA.collCXM1P() & 0x80; case CollisionBit::M1P1: if(toggle) myTIA.toggleCollP1M1(); return myTIA.collCXM1P() & 0x40; case CollisionBit::P0PF: if(toggle) myTIA.toggleCollP0PF(); return myTIA.collCXP0FB() & 0x80; case CollisionBit::P0BL: if(toggle) myTIA.toggleCollP0BL(); return myTIA.collCXP0FB() & 0x40; case CollisionBit::P1PF: if(toggle) myTIA.toggleCollP1PF(); return myTIA.collCXP1FB() & 0x80; case CollisionBit::P1BL: if(toggle) myTIA.toggleCollP1BL(); return myTIA.collCXP1FB() & 0x40; case CollisionBit::M0PF: if(toggle) myTIA.toggleCollM0PF(); return myTIA.collCXM0FB() & 0x80; case CollisionBit::M0BL: if(toggle) myTIA.toggleCollM0BL(); return myTIA.collCXM0FB() & 0x40; case CollisionBit::M1PF: if(toggle) myTIA.toggleCollM1PF(); return myTIA.collCXM1FB() & 0x80; case CollisionBit::M1BL: if(toggle) myTIA.toggleCollM1BL(); return myTIA.collCXM1FB() & 0x40; case CollisionBit::BLPF: if(toggle) myTIA.toggleCollBLPF(); return myTIA.collCXBLPF() & 0x80; case CollisionBit::P0P1: if(toggle) myTIA.toggleCollP0P1(); return myTIA.collCXPPMM() & 0x80; case CollisionBit::M0M1: if(toggle) myTIA.toggleCollM0M1(); return myTIA.collCXPPMM() & 0x40; } return false; // make compiler happy } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audC0(int newVal) { if(newVal > -1) mySystem.poke(AUDC0, newVal); return myTIA.registerValue(AUDC0) & 0x0f; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audC1(int newVal) { if(newVal > -1) mySystem.poke(AUDC1, newVal); return myTIA.registerValue(AUDC1) & 0x0f; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audV0(int newVal) { if(newVal > -1) mySystem.poke(AUDV0, newVal); return myTIA.registerValue(AUDV0) & 0x0f; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audV1(int newVal) { if(newVal > -1) mySystem.poke(AUDV1, newVal); return myTIA.registerValue(AUDV1) & 0x0f; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audF0(int newVal) { if(newVal > -1) mySystem.poke(AUDF0, newVal); return myTIA.registerValue(AUDF0) & 0x1f; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::audF1(int newVal) { if(newVal > -1) mySystem.poke(AUDF1, newVal); return myTIA.registerValue(AUDF1) & 0x1f; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::pf0(int newVal) { if(newVal > -1) mySystem.poke(PF0, newVal << 4); return myTIA.registerValue(PF0) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::pf1(int newVal) { if(newVal > -1) mySystem.poke(PF1, newVal); return myTIA.registerValue(PF1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::pf2(int newVal) { if(newVal > -1) mySystem.poke(PF2, newVal); return myTIA.registerValue(PF2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::coluP0(int newVal) { if(newVal > -1) mySystem.poke(COLUP0, newVal); return myTIA.registerValue(COLUP0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::coluP1(int newVal) { if(newVal > -1) mySystem.poke(COLUP1, newVal); return myTIA.registerValue(COLUP1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::coluPF(int newVal) { if(newVal > -1) mySystem.poke(COLUPF, newVal); return myTIA.registerValue(COLUPF); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::coluBK(int newVal) { if(newVal > -1) mySystem.poke(COLUBK, newVal); return myTIA.registerValue(COLUBK); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusiz0(int newVal) { if(newVal > -1) mySystem.poke(NUSIZ0, newVal); return myTIA.registerValue(NUSIZ0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusiz1(int newVal) { if(newVal > -1) mySystem.poke(NUSIZ1, newVal); return myTIA.registerValue(NUSIZ1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusizP0(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.registerValue(NUSIZ0) & ~0x07; tmp |= (newVal & 0x07); mySystem.poke(NUSIZ0, tmp); } return myTIA.registerValue(NUSIZ0) & 0x07; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusizP1(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.registerValue(NUSIZ1) & ~0x07; tmp |= newVal & 0x07; mySystem.poke(NUSIZ1, tmp); } return myTIA.registerValue(NUSIZ1) & 0x07; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusizM0(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.registerValue(NUSIZ0) & ~0x30; tmp |= (newVal & 0x04) << 4; mySystem.poke(NUSIZ0, tmp); } return (myTIA.registerValue(NUSIZ0) & 0x30) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::nusizM1(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.registerValue(NUSIZ1) & ~0x30; tmp |= (newVal & 0x04) << 4; mySystem.poke(NUSIZ1, tmp); } return (myTIA.registerValue(NUSIZ1) & 0x30) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::grP0(int newVal) { if(newVal > -1) mySystem.poke(GRP0, newVal); return myTIA.registerValue(GRP0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::grP1(int newVal) { if(newVal > -1) mySystem.poke(GRP1, newVal); return myTIA.registerValue(GRP1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posP0(int newVal) { if(newVal > -1) myTIA.myPlayer0.setPosition(newVal); return myTIA.myPlayer0.getPosition(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posP1(int newVal) { if(newVal > -1) myTIA.myPlayer1.setPosition(newVal); return myTIA.myPlayer1.getPosition(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posM0(int newVal) { if(newVal > -1) myTIA.myMissile0.setPosition(newVal); return myTIA.myMissile0.getPosition(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posM1(int newVal) { if(newVal > -1) myTIA.myMissile1.setPosition(newVal); return myTIA.myMissile1.getPosition(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::posBL(int newVal) { if(newVal > -1) myTIA.myBall.setPosition(newVal); return myTIA.myBall.getPosition(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::ctrlPF(int newVal) { if(newVal > -1) mySystem.poke(CTRLPF, newVal); return myTIA.registerValue(CTRLPF); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::sizeBL(int newVal) { if(newVal > -1) { uInt8 tmp = myTIA.registerValue(CTRLPF) & ~0x30; tmp |= (newVal & 0x04) << 4; mySystem.poke(CTRLPF, tmp); } return (myTIA.registerValue(CTRLPF) & 0x30) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmP0(int newVal) { if(newVal > -1) mySystem.poke(HMP0, newVal << 4); return myTIA.registerValue(HMP0) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmP1(int newVal) { if(newVal > -1) mySystem.poke(HMP1, newVal << 4); return myTIA.registerValue(HMP1) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmM0(int newVal) { if(newVal > -1) mySystem.poke(HMM0, newVal << 4); return myTIA.registerValue(HMM0) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmM1(int newVal) { if(newVal > -1) mySystem.poke(HMM1, newVal << 4); return myTIA.registerValue(HMM1) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIADebug::hmBL(int newVal) { if(newVal > -1) mySystem.poke(HMBL, newVal << 4); return myTIA.registerValue(HMBL) >> 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::setGRP0Old(uInt8 b) { myTIA.myPlayer0.setGRPOld(b); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::setGRP1Old(uInt8 b) { myTIA.myPlayer1.setGRPOld(b); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::setENABLOld(bool b) { myTIA.myBall.setENABLOld(b); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeWsync() { mySystem.poke(WSYNC, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeRsync() { mySystem.poke(RSYNC, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeResP0() { mySystem.poke(RESP0, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeResP1() { mySystem.poke(RESP1, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeResM0() { mySystem.poke(RESM0, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeResM1() { mySystem.poke(RESM1, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeResBL() { mySystem.poke(RESBL, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeHmove() { mySystem.poke(HMOVE, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeHmclr() { mySystem.poke(HMCLR, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIADebug::strobeCxclr() { mySystem.poke(CXCLR, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::frameCount() const { return myTIA.frameCount(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::frameCycles() const { return myTIA.frameCycles(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::cyclesLo() const { return int(myTIA.cycles()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::cyclesHi() const { return int(myTIA.cycles() >> 32); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::scanlines() const { return myTIA.scanlines(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::scanlinesLastFrame() const { return myTIA.scanlinesLastFrame(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::clocksThisLine() const { return myTIA.clocksThisLine(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TIADebug::cyclesThisLine() const { return myTIA.clocksThisLine()/3; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vsync() const { return myTIA.registerValue(VSYNC) & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIADebug::vblank() const { return myTIA.registerValue(VBLANK) & 0x02; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - shared_ptr TIADebug::delayQueueIterator() const { return myTIA.delayQueueIterator(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIADebug::colorSwatch(uInt8 c) const { string ret; ret += char((c >> 1) | 0x80); ret += "\177 "; ret += "\177\001 "; return ret; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // FIXME - how does this work; is this even needed ?? string TIADebug::audFreq(uInt8 div) { string ret; char buf[10]; double hz = 31400.0; if(div) hz /= div; std::snprintf(buf, 9, "%5.1f", hz); ret += buf; ret += "Hz"; return ret; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIADebug::booleanWithLabel(string label, bool value) { char buf[64]; string ret; if(value) { char *p = buf; const char *q = label.c_str(); while((*p++ = toupper(*q++))) ; ret += "+"; ret += buf; return ret; } else return "-" + label; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIADebug::debugColors() const { ostringstream buf; int mode = myTIA.frameLayout() == FrameLayout::ntsc ? 0 : 1; buf << " " << myTIA.myFixedColorNames[TIA::P0] << " " << colorSwatch(myTIA.myFixedColorPalette[mode][TIA::P0]) << " Player 0\n" << " " << myTIA.myFixedColorNames[TIA::M0] << " " << colorSwatch(myTIA.myFixedColorPalette[mode][TIA::M0]) << " Missile 0\n" << " " << myTIA.myFixedColorNames[TIA::P1] << " " << colorSwatch(myTIA.myFixedColorPalette[mode][TIA::P1]) << " Player 1\n" << " " << myTIA.myFixedColorNames[TIA::M1] << " " << colorSwatch(myTIA.myFixedColorPalette[mode][TIA::M1]) << " Missile 1\n" << " " << myTIA.myFixedColorNames[TIA::PF] << " " << colorSwatch(myTIA.myFixedColorPalette[mode][TIA::PF]) << " Playfield\n" << " " << myTIA.myFixedColorNames[TIA::BL] << " " << colorSwatch(myTIA.myFixedColorPalette[mode][TIA::BL]) << " Ball\n" << " Grey " << colorSwatch(TIA::FixedColor::BK_GREY) << " Background\n" << " White " << colorSwatch(TIA::FixedColor::HBLANK_WHITE) << " HMOVE\n"; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIADebug::palette() const { ostringstream buf; buf << " 0 2 4 6 8 A C E\n"; uInt8 c = 0; for(uInt16 row = 0; row < 16; ++row) { buf << " " << Common::Base::HEX1 << row << " "; for(uInt16 col = 0; col < 8; ++col, c += 2) buf << colorSwatch(c); buf << endl; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIADebug::toString() { ostringstream buf; buf << "00: "; for (uInt8 j = 0; j < 0x010; j++) { buf << Common::Base::HEX2 << int(mySystem.peek(j)) << " "; if(j == 0x07) buf << "- "; } buf << endl; // TODO: inverse video for changed regs. Core needs to track this. // TODO: strobes? WSYNC RSYNC RESP0/1 RESM0/1 RESBL HMOVE HMCLR CXCLR const TiaState& state = static_cast(getState()); // build up output, then return it. buf << "scanline " << std::dec << myTIA.scanlines() << " " << booleanWithLabel("vsync", vsync()) << " " << booleanWithLabel("vblank", vblank()) << endl << booleanWithLabel("inpt0", myTIA.peek(0x08) & 0x80) << " " << booleanWithLabel("inpt1", myTIA.peek(0x09) & 0x80) << " " << booleanWithLabel("inpt2", myTIA.peek(0x0a) & 0x80) << " " << booleanWithLabel("inpt3", myTIA.peek(0x0b) & 0x80) << " " << booleanWithLabel("inpt4", myTIA.peek(0x0c) & 0x80) << " " << booleanWithLabel("inpt5", myTIA.peek(0x0d) & 0x80) << " " << booleanWithLabel("dump_gnd_0123", myTIA.myPaddleReaders[0].vblankDumped()) << endl << "COLUxx: " << "P0=$" << Common::Base::HEX2 << state.coluRegs[0] << "/" << colorSwatch(state.coluRegs[0]) << " P1=$" << Common::Base::HEX2 << state.coluRegs[1] << "/" << colorSwatch(state.coluRegs[1]) << " PF=$" << Common::Base::HEX2 << state.coluRegs[2] << "/" << colorSwatch(state.coluRegs[2]) << " BK=$" << Common::Base::HEX2 << state.coluRegs[3] << "/" << colorSwatch(state.coluRegs[3]) << endl << "P0: GR=%" << Common::Base::toString(state.gr[P0], Common::Base::F_2_8) << " pos=#" << std::dec << state.pos[P0] << " HM=$" << Common::Base::HEX2 << state.hm[P0] << " " << nusizP0String() << " " << booleanWithLabel("refl", refP0()) << " " << booleanWithLabel("delay", vdelP0()) << endl << "P1: GR=%" << Common::Base::toString(state.gr[P1], Common::Base::F_2_8) << " pos=#" << std::dec << state.pos[P1] << " HM=$" << Common::Base::HEX2 << state.hm[P1] << " " << nusizP1String() << " " << booleanWithLabel("refl", refP1()) << " " << booleanWithLabel("delay", vdelP1()) << endl << "M0: " << (enaM0() ? " ENABLED" : "disabled") << " pos=#" << std::dec << state.pos[M0] << " HM=$" << Common::Base::HEX2 << state.hm[M0] << " size=" << std::dec << state.size[M0] << " " << booleanWithLabel("reset", resMP0()) << endl << "M1: " << (enaM1() ? " ENABLED" : "disabled") << " pos=#" << std::dec << state.pos[M1] << " HM=$" << Common::Base::HEX2 << state.hm[M1] << " size=" << std::dec << state.size[M1] << " " << booleanWithLabel("reset", resMP0()) << endl << "BL: " << (enaBL() ? " ENABLED" : "disabled") << " pos=#" << std::dec << state.pos[BL] << " HM=$" << Common::Base::HEX2 << state.hm[BL] << " size=" << std::dec << state.size[BL] << " " << booleanWithLabel("delay", vdelBL()) << endl << "PF0: %" << Common::Base::toString(state.pf[0], Common::Base::F_2_8) << "/$" << Common::Base::HEX2 << state.pf[0] << " PF1: %" << Common::Base::toString(state.pf[1], Common::Base::F_2_8) << "/$" << Common::Base::HEX2 << state.pf[1] << " PF2: %" << Common::Base::toString(state.pf[2], Common::Base::F_2_8) << "/$" << Common::Base::HEX2 << state.pf[2] << endl << " " << booleanWithLabel("reflect", refPF()) << " " << booleanWithLabel("score", scorePF()) << " " << booleanWithLabel("priority", priorityPF()) << endl << "Collisions: " << booleanWithLabel("m0_p1 ", collM0_P1()) << booleanWithLabel("m0_p0 ", collM0_P0()) << booleanWithLabel("m1_p0 ", collM1_P0()) << booleanWithLabel("m1_p1 ", collM1_P1()) << booleanWithLabel("p0_pf ", collP0_PF()) << booleanWithLabel("p0_bl ", collP0_BL()) << booleanWithLabel("p1_pf ", collP1_PF()) << endl << " " << booleanWithLabel("p1_bl ", collP1_BL()) << booleanWithLabel("m0_pf ", collM0_PF()) << booleanWithLabel("m0_bl ", collM0_BL()) << booleanWithLabel("m1_pf ", collM1_PF()) << booleanWithLabel("m1_bl ", collM1_BL()) << booleanWithLabel("bl_pf ", collBL_PF()) << booleanWithLabel("p0_p1 ", collP0_P1()) << endl << " " << booleanWithLabel("m0_m1 ", collM0_M1()) << endl << "AUDF0: $" << Common::Base::HEX2 << int(audF0()) << "/" << audFreq(audF0()) << " " << "AUDC0: $" << Common::Base::HEX2 << int(audC0()) << " " << "AUDV0: $" << Common::Base::HEX2 << int(audV0()) << endl << "AUDF1: $" << Common::Base::HEX2 << int(audF1()) << "/" << audFreq(audF1()) << " " << "AUDC1: $" << Common::Base::HEX2 << int(audC1()) << " " << "AUDV1: $" << Common::Base::HEX2 << int(audV1()) ; // note: last line should not contain \n, caller will add. return buf.str(); } stella-5.1.1/src/debugger/TIADebug.hxx000066400000000000000000000141471324334165500175070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_DEBUG_HXX #define TIA_DEBUG_HXX class Debugger; class TIA; class DelayQueueIterator; // Function type for TIADebug instance methods class TIADebug; using TiaMethod = int (TIADebug::*)() const; #include "DebuggerSystem.hxx" #include "bspf.hxx" // Indices for various IntArray in TiaState enum { P0, P1, M0, M1, BL }; class TiaState : public DebuggerState { public: IntArray coluRegs; IntArray fixedCols; BoolArray cx; IntArray gr; BoolArray ref; BoolArray vdel; BoolArray res; IntArray pos; IntArray hm; IntArray pf; IntArray size; IntArray aud; IntArray info; }; class TIADebug : public DebuggerSystem { public: TIADebug(Debugger& dbg, Console& console); TIA& tia() const { return myTIA; } const DebuggerState& getState() override; const DebuggerState& getOldState() override { return myOldState; } void saveOldState() override; string toString() override; string debugColors() const; string palette() const; // TIA byte (or part of a byte) registers uInt8 nusiz0(int newVal = -1); uInt8 nusiz1(int newVal = -1); uInt8 nusizP0(int newVal = -1); uInt8 nusizP1(int newVal = -1); uInt8 nusizM0(int newVal = -1); uInt8 nusizM1(int newVal = -1); const string& nusizP0String() { return nusizStrings[nusizP0()]; } const string& nusizP1String() { return nusizStrings[nusizP1()]; } uInt8 coluP0(int newVal = -1); uInt8 coluP1(int newVal = -1); uInt8 coluPF(int newVal = -1); uInt8 coluBK(int newVal = -1); uInt8 sizeBL(int newVal = -1); uInt8 ctrlPF(int newVal = -1); uInt8 pf0(int newVal = -1); uInt8 pf1(int newVal = -1); uInt8 pf2(int newVal = -1); uInt8 grP0(int newVal = -1); uInt8 grP1(int newVal = -1); uInt8 posP0(int newVal = -1); uInt8 posP1(int newVal = -1); uInt8 posM0(int newVal = -1); uInt8 posM1(int newVal = -1); uInt8 posBL(int newVal = -1); uInt8 hmP0(int newVal = -1); uInt8 hmP1(int newVal = -1); uInt8 hmM0(int newVal = -1); uInt8 hmM1(int newVal = -1); uInt8 hmBL(int newVal = -1); uInt8 audC0(int newVal = -1); uInt8 audC1(int newVal = -1); uInt8 audF0(int newVal = -1); uInt8 audF1(int newVal = -1); uInt8 audV0(int newVal = -1); uInt8 audV1(int newVal = -1); void setGRP0Old(uInt8 b); void setGRP1Old(uInt8 b); void setENABLOld(bool b); // TIA bool registers bool refP0(int newVal = -1); bool refP1(int newVal = -1); bool enaM0(int newVal = -1); bool enaM1(int newVal = -1); bool enaBL(int newVal = -1); bool vdelP0(int newVal = -1); bool vdelP1(int newVal = -1); bool vdelBL(int newVal = -1); bool resMP0(int newVal = -1); bool resMP1(int newVal = -1); bool refPF(int newVal = -1); bool scorePF(int newVal = -1); bool priorityPF(int newVal = -1); /** Get specific bits in the collision register (used by collXX_XX) */ bool collision(CollisionBit id, bool toggle = false) const; // Collision registers bool collM0_P1() const { return collision(CollisionBit::M0P1); } bool collM0_P0() const { return collision(CollisionBit::M0P0); } bool collM1_P0() const { return collision(CollisionBit::M1P0); } bool collM1_P1() const { return collision(CollisionBit::M1P1); } bool collP0_PF() const { return collision(CollisionBit::P0PF); } bool collP0_BL() const { return collision(CollisionBit::P0BL); } bool collP1_PF() const { return collision(CollisionBit::P1PF); } bool collP1_BL() const { return collision(CollisionBit::P1BL); } bool collM0_PF() const { return collision(CollisionBit::M0PF); } bool collM0_BL() const { return collision(CollisionBit::M0BL); } bool collM1_PF() const { return collision(CollisionBit::M1PF); } bool collM1_BL() const { return collision(CollisionBit::M1BL); } bool collBL_PF() const { return collision(CollisionBit::BLPF); } bool collP0_P1() const { return collision(CollisionBit::P0P1); } bool collM0_M1() const { return collision(CollisionBit::M0M1); } // TIA strobe registers void strobeWsync(); void strobeRsync(); void strobeResP0(); void strobeResP1(); void strobeResM0(); void strobeResM1(); void strobeResBL(); void strobeHmove(); void strobeHmclr(); void strobeCxclr(); // Read-only internal TIA state int scanlines() const; int scanlinesLastFrame() const; int frameCount() const; int frameCycles() const; int cyclesLo() const; int cyclesHi() const; int clocksThisLine() const; int cyclesThisLine() const; bool vsync() const; bool vblank() const; int vsyncAsInt() const { return int(vsync()); } // so we can use _vsync pseudo-register int vblankAsInt() const { return int(vblank()); } // so we can use _vblank pseudo-register shared_ptr delayQueueIterator() const; private: /** Display a color patch for color at given index in the palette */ string colorSwatch(uInt8 c) const; string audFreq(uInt8 div); string booleanWithLabel(string label, bool value); private: TiaState myState; TiaState myOldState; TIA& myTIA; string nusizStrings[8]; private: // Following constructors and assignment operators not supported TIADebug() = delete; TIADebug(const TIADebug&) = delete; TIADebug(TIADebug&&) = delete; TIADebug& operator=(const TIADebug&) = delete; TIADebug& operator=(TIADebug&&) = delete; }; #endif stella-5.1.1/src/debugger/TrapArray.hxx000066400000000000000000000035141324334165500200240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TRAP_ARRAY_HXX #define TRAP_ARRAY_HXX #include "bspf.hxx" class TrapArray { public: TrapArray() : myInitialized(false) {} bool isSet(const uInt16 address) const { return myCount[address]; } bool isClear(const uInt16 address) const { return myCount[address] == 0; } void add(const uInt16 address) { myCount[address]++; } void remove(const uInt16 address) { myCount[address]--; } //void toggle(uInt16 address) { myCount[address] ? remove(address) : add(address); } // TODO condition void initialize() { if(!myInitialized) memset(myCount, 0, sizeof(myCount)); myInitialized = true; } void clearAll() { myInitialized = false; memset(myCount, 0, sizeof(myCount)); } bool isInitialized() const { return myInitialized; } private: // The actual counts uInt8 myCount[0x10000]; // Indicates whether we should treat this array as initialized bool myInitialized; private: // Following constructors and assignment operators not supported TrapArray(const TrapArray&) = delete; TrapArray(TrapArray&&) = delete; TrapArray& operator=(const TrapArray&) = delete; TrapArray& operator=(TrapArray&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/000077500000000000000000000000001324334165500161475ustar00rootroot00000000000000stella-5.1.1/src/debugger/gui/AmigaMouseWidget.cxx000066400000000000000000000021201324334165500220610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "AmigaMouseWidget.hxx" AmigaMouseWidget::AmigaMouseWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : PointingDeviceWidget(boss, font, x, y, controller) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 AmigaMouseWidget::getGrayCodeTable(const int index, const int direction) { return myGrayCodeTable[index]; } stella-5.1.1/src/debugger/gui/AmigaMouseWidget.hxx000066400000000000000000000030051324334165500220710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef AMIGAMOUSE_WIDGET_HXX #define AMIGAMOUSE_WIDGET_HXX class Controller; #include "PointingDeviceWidget.hxx" class AmigaMouseWidget : public PointingDeviceWidget { public: AmigaMouseWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~AmigaMouseWidget() = default; private: uInt8 myGrayCodeTable[4] = { 0b00, 0b10, 0b11, 0b01 }; uInt8 getGrayCodeTable(const int index, const int direction) override; // Following constructors and assignment operators not supported AmigaMouseWidget() = delete; AmigaMouseWidget(const AmigaMouseWidget&) = delete; AmigaMouseWidget(AmigaMouseWidget&&) = delete; AmigaMouseWidget& operator=(const AmigaMouseWidget&) = delete; AmigaMouseWidget& operator=(AmigaMouseWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/AtariMouseWidget.cxx000066400000000000000000000021201324334165500221030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "AtariMouseWidget.hxx" AtariMouseWidget::AtariMouseWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : PointingDeviceWidget(boss, font, x, y, controller) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 AtariMouseWidget::getGrayCodeTable(const int index, const int direction) { return myGrayCodeTable[index]; } stella-5.1.1/src/debugger/gui/AtariMouseWidget.hxx000066400000000000000000000030051324334165500221130ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ATARIMOUSE_WIDGET_HXX #define ATARIMOUSE_WIDGET_HXX class Controller; #include "PointingDeviceWidget.hxx" class AtariMouseWidget : public PointingDeviceWidget { public: AtariMouseWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~AtariMouseWidget() = default; private: uInt8 myGrayCodeTable[4] = { 0b00, 0b01, 0b11, 0b10 }; uInt8 getGrayCodeTable(const int index, const int direction) override; // Following constructors and assignment operators not supported AtariMouseWidget() = delete; AtariMouseWidget(const AtariMouseWidget&) = delete; AtariMouseWidget(AtariMouseWidget&&) = delete; AtariMouseWidget& operator=(const AtariMouseWidget&) = delete; AtariMouseWidget& operator=(AtariMouseWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/AtariVoxWidget.cxx000066400000000000000000000026731324334165500216040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "AtariVox.hxx" #include "AtariVoxWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AtariVoxWidget::AtariVoxWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : FlashWidget(boss, font, x, y, controller) { init(boss, font, x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariVoxWidget::eraseCurrent() { AtariVox& avox = static_cast(myController); avox.eraseCurrent(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool AtariVoxWidget::isPageUsed(uInt32 page) { AtariVox& avox = static_cast(myController); return avox.isPageUsed(page); } stella-5.1.1/src/debugger/gui/AtariVoxWidget.hxx000066400000000000000000000026321324334165500216040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ATARIVOX_WIDGET_HXX #define ATARIVOX_WIDGET_HXX class Controller; #include "FlashWidget.hxx" class AtariVoxWidget : public FlashWidget { public: AtariVoxWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~AtariVoxWidget() = default; private: void eraseCurrent() override; bool isPageUsed(uInt32 page) override; // Following constructors and assignment operators not supported AtariVoxWidget() = delete; AtariVoxWidget(const AtariVoxWidget&) = delete; AtariVoxWidget(AtariVoxWidget&&) = delete; AtariVoxWidget& operator=(const AtariVoxWidget&) = delete; AtariVoxWidget& operator=(AtariVoxWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/AudioWidget.cxx000066400000000000000000000154461324334165500211120ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "DataGridWidget.hxx" #include "GuiObject.hxx" #include "Font.hxx" #include "OSystem.hxx" #include "Debugger.hxx" #include "TIADebug.hxx" #include "Widget.hxx" #include "Base.hxx" using Common::Base; #include "AudioWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AudioWidget::AudioWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) : Widget(boss, lfont, x, y, w, h), CommandSender(boss) { const int fontWidth = lfont.getMaxCharWidth(), fontHeight = lfont.getFontHeight(), lineHeight = lfont.getLineHeight(); int xpos = 10, ypos = 25, lwidth = lfont.getStringWidth("AUDW "); // AudF registers new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight, "AUDF", TextAlign::Left); xpos += lwidth; myAudF = new DataGridWidget(boss, nfont, xpos, ypos, 2, 1, 2, 5, Common::Base::F_16); myAudF->setTarget(this); myAudF->setID(kAUDFID); addFocusWidget(myAudF); for(int col = 0; col < 2; ++col) { new StaticTextWidget(boss, lfont, xpos + col * myAudF->colWidth() + int(myAudF->colWidth() / 2.75), ypos - lineHeight, fontWidth, fontHeight, Common::Base::toString(col, Common::Base::F_16_1), TextAlign::Left); } // AudC registers xpos = 10; ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight, "AUDC", TextAlign::Left); xpos += lwidth; myAudC = new DataGridWidget(boss, nfont, xpos + int(myAudF->colWidth() / 2.75), ypos, 2, 1, 1, 4, Common::Base::F_16_1); myAudC->setTarget(this); myAudC->setID(kAUDCID); addFocusWidget(myAudC); // AudV registers xpos = 10; ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight, "AUDV", TextAlign::Left); xpos += lwidth; myAudV = new DataGridWidget(boss, nfont, xpos + int(myAudF->colWidth() / 2.75), ypos, 2, 1, 1, 4, Common::Base::F_16_1); myAudV->setTarget(this); myAudV->setID(kAUDVID); addFocusWidget(myAudV); myAudEffV = new StaticTextWidget(boss, lfont, myAudV->getRight() + fontWidth, myAudV->getTop() + 2, "100% (eff. volume)"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioWidget::loadConfig() { IntArray alist; IntArray vlist; BoolArray blist, changed, grNew, grOld; Debugger& dbg = instance().debugger(); TIADebug& tia = dbg.tiaDebug(); const TiaState& state = static_cast(tia.getState()); const TiaState& oldstate = static_cast(tia.getOldState()); // AUDF0/1 alist.clear(); vlist.clear(); changed.clear(); for(uInt32 i = 0; i < 2; i++) { alist.push_back(i); vlist.push_back(state.aud[i]); changed.push_back(state.aud[i] != oldstate.aud[i]); } myAudF->setList(alist, vlist, changed); // AUDC0/1 alist.clear(); vlist.clear(); changed.clear(); for(uInt32 i = 2; i < 4; i++) { alist.push_back(i-2); vlist.push_back(state.aud[i]); changed.push_back(state.aud[i] != oldstate.aud[i]); } myAudC->setList(alist, vlist, changed); // AUDV0/1 alist.clear(); vlist.clear(); changed.clear(); for(uInt32 i = 4; i < 6; i++) { alist.push_back(i-4); vlist.push_back(state.aud[i]); changed.push_back(state.aud[i] != oldstate.aud[i]); } myAudV->setList(alist, vlist, changed); handleVolume(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioWidget::handleVolume() { stringstream s; s << getEffectiveVolume() << "% (eff. volume)"; myAudEffV->setLabel(s.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case DataGridWidget::kItemDataChangedCmd: switch(id) { case kAUDFID: changeFrequencyRegs(); break; case kAUDCID: changeControlRegs(); break; case kAUDVID: changeVolumeRegs(); break; default: cerr << "AudioWidget DG changed\n"; break; } break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioWidget::changeFrequencyRegs() { int addr = myAudF->getSelectedAddr(); int value = myAudF->getSelectedValue(); switch(addr) { case kAud0Addr: instance().debugger().tiaDebug().audF0(value); break; case kAud1Addr: instance().debugger().tiaDebug().audF1(value); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioWidget::changeControlRegs() { int addr = myAudC->getSelectedAddr(); int value = myAudC->getSelectedValue(); switch(addr) { case kAud0Addr: instance().debugger().tiaDebug().audC0(value); break; case kAud1Addr: instance().debugger().tiaDebug().audC1(value); break; } handleVolume(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioWidget::changeVolumeRegs() { int addr = myAudV->getSelectedAddr(); int value = myAudV->getSelectedValue(); switch(addr) { case kAud0Addr: instance().debugger().tiaDebug().audV0(value); break; case kAud1Addr: instance().debugger().tiaDebug().audV1(value); break; } handleVolume(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 AudioWidget::getEffectiveVolume() { const int EFF_VOL[] = { 0, 6, 13, 18, 24, 29, 33, 38, 42, 46, 50, 54, 57, 60, 64, 67, 70, 72, 75, 78, 80, 82, 85, 87, 89, 91, 93, 95, 97, 98,100}; return EFF_VOL[(instance().debugger().tiaDebug().audC0() ? instance().debugger().tiaDebug().audV0() : 0) + (instance().debugger().tiaDebug().audC1() ? instance().debugger().tiaDebug().audV1() : 0)]; } stella-5.1.1/src/debugger/gui/AudioWidget.hxx000066400000000000000000000037611324334165500211140ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef AUDIO_WIDGET_HXX #define AUDIO_WIDGET_HXX class GuiObject; class DataGridWidget; #include "Widget.hxx" #include "Command.hxx" class AudioWidget : public Widget, public CommandSender { public: AudioWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h); virtual ~AudioWidget() = default; private: // ID's for the various widgets // We need ID's, since there are more than one of several types of widgets enum { kAUDFID, kAUDCID, kAUDVID }; DataGridWidget* myAudF; DataGridWidget* myAudC; DataGridWidget* myAudV; StaticTextWidget* myAudEffV; // Audio channels enum { kAud0Addr, kAud1Addr }; private: void changeFrequencyRegs(); void changeControlRegs(); void changeVolumeRegs(); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void loadConfig() override; void handleVolume(); uInt32 getEffectiveVolume(); // Following constructors and assignment operators not supported AudioWidget() = delete; AudioWidget(const AudioWidget&) = delete; AudioWidget(AudioWidget&&) = delete; AudioWidget& operator=(const AudioWidget&) = delete; AudioWidget& operator=(AudioWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/BoosterWidget.cxx000066400000000000000000000116071324334165500214610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "BoosterWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BoosterWidget::BoosterWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { const string& label = isLeftPort() ? "Left (Booster)" : "Right (Booster)"; const int fontHeight = font.getFontHeight(); int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Booster)"); StaticTextWidget* t; t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth, fontHeight, label, TextAlign::Left); xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 10; myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJUp]->setID(kJUp); myPins[kJUp]->setTarget(this); ypos += myPins[kJUp]->getHeight() * 2 + 10; myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJDown]->setID(kJDown); myPins[kJDown]->setTarget(this); xpos -= myPins[kJUp]->getWidth() + 5; ypos -= myPins[kJUp]->getHeight() + 5; myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJLeft]->setID(kJLeft); myPins[kJLeft]->setTarget(this); xpos += (myPins[kJUp]->getWidth() + 5) * 2; myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJRight]->setID(kJRight); myPins[kJRight]->setTarget(this); xpos -= (myPins[kJUp]->getWidth() + 5) * 2; ypos = 20 + (myPins[kJUp]->getHeight() + 10) * 3; myPins[kJFire] = new CheckboxWidget(boss, font, xpos, ypos, "Fire", CheckboxWidget::kCheckActionCmd); myPins[kJFire]->setID(kJFire); myPins[kJFire]->setTarget(this); ypos += myPins[kJFire]->getHeight() + 5; myPins[kJBooster] = new CheckboxWidget(boss, font, xpos, ypos, "Booster", CheckboxWidget::kCheckActionCmd); myPins[kJBooster]->setID(kJBooster); myPins[kJBooster]->setTarget(this); ypos += myPins[kJBooster]->getHeight() + 5; myPins[kJTrigger] = new CheckboxWidget(boss, font, xpos, ypos, "Trigger", CheckboxWidget::kCheckActionCmd); myPins[kJTrigger]->setID(kJTrigger); myPins[kJTrigger]->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BoosterWidget::loadConfig() { myPins[kJUp]->setState(!myController.read(ourPinNo[kJUp])); myPins[kJDown]->setState(!myController.read(ourPinNo[kJDown])); myPins[kJLeft]->setState(!myController.read(ourPinNo[kJLeft])); myPins[kJRight]->setState(!myController.read(ourPinNo[kJRight])); myPins[kJFire]->setState(!myController.read(ourPinNo[kJFire])); myPins[kJBooster]->setState( myController.read(Controller::Five) == Controller::minimumResistance); myPins[kJTrigger]->setState( myController.read(Controller::Nine) == Controller::minimumResistance); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BoosterWidget::handleCommand( CommandSender* sender, int cmd, int data, int id) { if(cmd == CheckboxWidget::kCheckActionCmd) { switch(id) { case kJUp: case kJDown: case kJLeft: case kJRight: case kJFire: myController.set(ourPinNo[id], !myPins[id]->getState()); break; case kJBooster: myController.set(Controller::Five, myPins[id]->getState() ? Controller::minimumResistance : Controller::maximumResistance); break; case kJTrigger: myController.set(Controller::Nine, myPins[id]->getState() ? Controller::minimumResistance : Controller::maximumResistance); break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller::DigitalPin BoosterWidget::ourPinNo[5] = { Controller::One, Controller::Two, Controller::Three, Controller::Four, Controller::Six }; stella-5.1.1/src/debugger/gui/BoosterWidget.hxx000066400000000000000000000031511324334165500214610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef BOOSTER_WIDGET_HXX #define BOOSTER_WIDGET_HXX #include "Control.hxx" #include "ControllerWidget.hxx" class BoosterWidget : public ControllerWidget { public: BoosterWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~BoosterWidget() = default; private: enum { kJUp = 0, kJDown, kJLeft, kJRight, kJFire, kJBooster, kJTrigger }; CheckboxWidget* myPins[7]; static Controller::DigitalPin ourPinNo[5]; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Following constructors and assignment operators not supported BoosterWidget() = delete; BoosterWidget(const BoosterWidget&) = delete; BoosterWidget(BoosterWidget&&) = delete; BoosterWidget& operator=(const BoosterWidget&) = delete; BoosterWidget& operator=(BoosterWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/Cart0840Widget.cxx000066400000000000000000000063711324334165500212530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Cart0840.hxx" #include "PopUpWidget.hxx" #include "Cart0840Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge0840Widget::Cartridge0840Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge0840& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 2 * 4096; ostringstream info; info << "0840 ECONObanking, two 4K banks\n" << "Startup bank = " << cart.myStartBank << "\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < 2; ++i, offset += 0x1000, spot += 0x40) { uInt16 start = uInt16((cart.myImage[offset+1] << 8) | cart.myImage[offset]); start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Fred X. Quimby", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($800)"); VarList::push_back(items, "1 ($840)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($800) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge0840Widget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge0840Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge0840Widget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$800", "$840" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/Cart0840Widget.hxx000066400000000000000000000034041324334165500212520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE0840_WIDGET_HXX #define CARTRIDGE0840_WIDGET_HXX class Cartridge0840; class PopUpWidget; #include "CartDebugWidget.hxx" class Cartridge0840Widget : public CartDebugWidget { public: Cartridge0840Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge0840& cart); virtual ~Cartridge0840Widget() = default; private: Cartridge0840& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported Cartridge0840Widget() = delete; Cartridge0840Widget(const Cartridge0840Widget&) = delete; Cartridge0840Widget(Cartridge0840Widget&&) = delete; Cartridge0840Widget& operator=(const Cartridge0840Widget&) = delete; Cartridge0840Widget& operator=(Cartridge0840Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/Cart2KWidget.cxx000066400000000000000000000026641324334165500211350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Cart2K.hxx" #include "Cart2KWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge2KWidget::Cartridge2KWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge2K& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h) { // Eventually, we should query this from the debugger/disassembler uInt16 size = cart.mySize; uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % size; ostringstream info; info << "Standard 2K cartridge, non-bankswitched\n" << "Accessible @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + size - 1); addBaseInformation(size, "Atari", info.str()); } stella-5.1.1/src/debugger/gui/Cart2KWidget.hxx000066400000000000000000000031751324334165500211400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE2K_WIDGET_HXX #define CARTRIDGE2K_WIDGET_HXX class Cartridge2K; #include "CartDebugWidget.hxx" class Cartridge2KWidget : public CartDebugWidget { public: Cartridge2KWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge2K& cart); virtual ~Cartridge2KWidget() = default; private: // No implementation for non-bankswitched ROMs void loadConfig() override { } void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } // Following constructors and assignment operators not supported Cartridge2KWidget() = delete; Cartridge2KWidget(const Cartridge2KWidget&) = delete; Cartridge2KWidget(Cartridge2KWidget&&) = delete; Cartridge2KWidget& operator=(const Cartridge2KWidget&) = delete; Cartridge2KWidget& operator=(Cartridge2KWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/Cart3EPlusWidget.cxx000066400000000000000000000242341324334165500217710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Cart3EPlus.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "Cart3EPlusWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3EPlusWidget::Cartridge3EPlusWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3EPlus& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = cart.mySize; ostringstream info; info << "3EPlus cartridge - (64K ROM + RAM)\n" << " 4-64K ROM (1K banks), 32K RAM (512b banks)\n" << "Each 1K ROM selected by writing to $3F\n" "Each 512b RAM selected by writing to $3E\n" " Lower 512B of bank x (R)\n" " Upper 512B of bank x (+$200) (W)\n" << "Startup bank = 0/-1/-1/0 (ROM)\n"; // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % 0x1000; info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; int xpos = 10, ypos = addBaseInformation(size, "T. Jentzsch", info.str()) + myLineHeight; VariantList bankno; for(uInt32 i = 0; i < myCart.ROM_BANK_COUNT; ++i) VarList::push_back(bankno, i, i); VariantList banktype; VarList::push_back(banktype, "ROM", "ROM"); VarList::push_back(banktype, "RAM", "RAM"); for(uInt32 i = 0; i < 4; ++i) { int xpos_s, ypos_s = ypos; ostringstream label; label << "Set segment " << i << " as "; new StaticTextWidget(boss, _font, xpos, ypos, _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); ypos += myLineHeight + 8; xpos += 20; myBankNumber[i] = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("Slot "), myLineHeight, bankno, "Slot ", 6*_font.getMaxCharWidth()); addFocusWidget(myBankNumber[i]); xpos += myBankNumber[i]->getWidth(); myBankType[i] = new PopUpWidget(boss, _font, xpos, ypos-2, 5*_font.getMaxCharWidth(), myLineHeight, banktype, " of ", _font.getStringWidth(" of ")); addFocusWidget(myBankType[i]); xpos += myBankType[i]->getWidth() + 10; myBankCommit[i] = new ButtonWidget(boss, _font, xpos, ypos-4, _font.getStringWidth(" Commit "), myButtonHeight, "Commit", bankEnum[i]); myBankCommit[i]->setTarget(this); addFocusWidget(myBankCommit[i]); xpos_s = xpos + myBankCommit[i]->getWidth() + 20; StaticTextWidget* t; int addr1 = start + (i*0x400), addr2 = addr1 + 0x1FF; label.str(""); label << Common::Base::HEX4 << addr1 << "-" << Common::Base::HEX4 << addr2; t = new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); int xoffset = xpos_s+t->getWidth() + 10; myBankState[2*i] = new EditTextWidget(boss, _font, xoffset, ypos_s, w - xoffset - 10, myLineHeight, ""); myBankState[2*i]->setEditable(false, true); ypos_s += myLineHeight + 4; label.str(""); label << Common::Base::HEX4 << (addr2 + 1) << "-" << Common::Base::HEX4 << (addr2 + 1 + 0x1FF); new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); myBankState[2*i+1] = new EditTextWidget(boss, _font, xoffset, ypos_s, w - xoffset - 10, myLineHeight, ""); myBankState[2*i+1]->setEditable(false, true); xpos = 10; ypos+= 2 * myLineHeight; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlusWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) myOldState.internalram.push_back(myCart.myRAM[i]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlusWidget::loadConfig() { updateUIState(); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlusWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { uInt16 segment = 0; switch(cmd) { case kBank0Changed: segment = 0; break; case kBank1Changed: segment = 1; break; case kBank2Changed: segment = 2; break; case kBank3Changed: segment = 3; break; } // Ignore bank if either number or type hasn't been selected if(myBankNumber[segment]->getSelected() < 0 || myBankType[segment]->getSelected() < 0) return; uInt8 bank = (segment << myCart.BANK_BITS) | (myBankNumber[segment]->getSelected() & myCart.BIT_BANK_MASK); myCart.unlockBank(); if(myBankType[segment]->getSelectedTag() == "ROM") myCart.bankROM(bank); else myCart.bankRAM(bank); myCart.lockBank(); invalidate(); updateUIState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge3EPlusWidget::bankState() { ostringstream& buf = buffer(); // In this scheme, consecutive 512b segments are either both ROM or both RAM; // we only need to look at the lower segment to determine what the 1K bank is for(int i = 0; i < 4; ++i) { uInt16 bank = myCart.bankInUse[i*2]; if(bank == myCart.BANK_UNDEFINED) // never accessed { buf << " U!"; } else { int bankno = bank & myCart.BIT_BANK_MASK; if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? buf << " RAM " << bankno; else buf << " ROM " << bankno; } if(i < 3) buf << " /"; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlusWidget::updateUIState() { // Set description for each 512b bank state (@ each index) // Set contents for actual banks number and type (@ each even index) for(int i = 0; i < 8; ++i) { uInt16 bank = myCart.bankInUse[i]; if(bank == myCart.BANK_UNDEFINED) // never accessed { myBankState[i]->setText("Undefined"); if(i % 2 == 0) { myBankNumber[i/2]->clearSelection(); myBankType[i/2]->clearSelection(); } } else { ostringstream buf; int bankno = bank & myCart.BIT_BANK_MASK; if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? { if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port { buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 << (bankno << myCart.RAM_BANK_TO_POWER) << " (W)"; myBankState[i]->setText(buf.str()); } else { buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 << (bankno << myCart.RAM_BANK_TO_POWER) << " (R)"; myBankState[i]->setText(buf.str()); } if(i % 2 == 0) { myBankNumber[i/2]->setSelected(bankno); myBankType[i/2]->setSelected("RAM"); } } else { if(bank & myCart.BITMASK_LOWERUPPER) // upper is high 512b { buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 << ((bankno << myCart.RAM_BANK_TO_POWER) + myCart.RAM_BANK_SIZE); myBankState[i]->setText(buf.str()); } else { buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 << (bankno << myCart.RAM_BANK_TO_POWER); myBankState[i]->setText(buf.str()); } if(i % 2 == 0) { myBankNumber[i/2]->setSelected(bankno); myBankType[i/2]->setSelected("ROM"); } } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Cartridge3EPlusWidget::internalRamSize() { return 32*1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Cartridge3EPlusWidget::internalRamRPort(int start) { return 0x0000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge3EPlusWidget::internalRamDescription() { ostringstream desc; desc << "Accessible 512b at a time via:\n" << " $F000/$F400/$F800/etc used for Read Access\n" << " $F200/$F600/$FA00/etc used for Write Access (+$200)"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& Cartridge3EPlusWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& Cartridge3EPlusWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlusWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge3EPlusWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Cartridge3EPlusWidget::BankID Cartridge3EPlusWidget::bankEnum[4] = { kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed }; stella-5.1.1/src/debugger/gui/Cart3EPlusWidget.hxx000066400000000000000000000053271324334165500220000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE3EPLUS_WIDGET_HXX #define CARTRIDGE3EPLUS_WIDGET_HXX class Cartridge3EPlus; class ButtonWidget; class EditTextWidget; class PopUpWidget; #include "CartDebugWidget.hxx" class Cartridge3EPlusWidget : public CartDebugWidget { public: Cartridge3EPlusWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3EPlus& cart); virtual ~Cartridge3EPlusWidget() = default; private: void updateUIState(); private: Cartridge3EPlus& myCart; PopUpWidget* myBankNumber[4]; PopUpWidget* myBankType[4]; ButtonWidget* myBankCommit[4]; EditTextWidget* myBankState[8]; struct CartState { ByteArray internalram; }; CartState myOldState; enum BankID { kBank0Changed = 'b0CH', kBank1Changed = 'b1CH', kBank2Changed = 'b2CH', kBank3Changed = 'b3CH' }; static const BankID bankEnum[4]; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported Cartridge3EPlusWidget() = delete; Cartridge3EPlusWidget(const Cartridge3EPlusWidget&) = delete; Cartridge3EPlusWidget(Cartridge3EPlusWidget&&) = delete; Cartridge3EPlusWidget& operator=(const Cartridge3EPlusWidget&) = delete; Cartridge3EPlusWidget& operator=(Cartridge3EPlusWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/Cart3EWidget.cxx000066400000000000000000000154761324334165500211350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Cart3E.hxx" #include "PopUpWidget.hxx" #include "Cart3EWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3EWidget::Cartridge3EWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3E& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart), myNumRomBanks(cart.mySize >> 11), myNumRamBanks(32) { uInt32 size = cart.mySize; ostringstream info; info << "3E cartridge - (3F + RAM)\n" << " 2-256 2K ROM (currently " << myNumRomBanks << "), 32 1K RAM\n" << "First 2K (ROM) selected by writing to $3F\n" "First 2K (RAM) selected by writing to $3E\n" " $F000 - $F3FF (R), $F400 - $F7FF (W)\n" "Last 2K always points to last 2K of ROM\n"; if(cart.myStartBank < myNumRomBanks) info << "Startup bank = " << cart.myStartBank << " (ROM)\n"; else info << "Startup bank = " << (cart.myStartBank-myNumRomBanks) << " (RAM)\n"; // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % 0x1000; info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; int xpos = 10, ypos = addBaseInformation(size, "TigerVision", info.str()) + myLineHeight; VariantList romitems; for(uInt32 i = 0; i < myNumRomBanks; ++i) VarList::push_back(romitems, i); VarList::push_back(romitems, "Inactive", ""); VariantList ramitems; for(uInt32 i = 0; i < myNumRamBanks; ++i) VarList::push_back(ramitems, i); VarList::push_back(ramitems, "Inactive", ""); ostringstream label; label << "Set bank ($" << Common::Base::HEX4 << start << " - $" << (start+0x7FF) << "): "; new StaticTextWidget(_boss, _font, xpos, ypos, _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); ypos += myLineHeight + 8; xpos += 40; myROMBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($3E) "), myLineHeight, romitems, "ROM ($3F) ", _font.getStringWidth("ROM ($3F) "), kROMBankChanged); myROMBank->setTarget(this); addFocusWidget(myROMBank); xpos += myROMBank->getWidth() + 20; myRAMBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($3E) "), myLineHeight, ramitems, "RAM ($3E) ", _font.getStringWidth("RAM ($3E) "), kRAMBankChanged); myRAMBank->setTarget(this); addFocusWidget(myRAMBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EWidget::loadConfig() { if(myCart.myCurrentBank < 256) { myROMBank->setSelectedIndex(myCart.myCurrentBank % myNumRomBanks, myOldState.bank != myCart.myCurrentBank); myRAMBank->setSelectedMax(myOldState.bank >= 256); } else { myROMBank->setSelectedMax(myOldState.bank < 256); myRAMBank->setSelectedIndex(myCart.myCurrentBank - 256, myOldState.bank != myCart.myCurrentBank); } CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { int bank = -1; if(cmd == kROMBankChanged) { if(myROMBank->getSelected() < int(myNumRomBanks)) { bank = myROMBank->getSelected(); myRAMBank->setSelectedMax(); } else { bank = 256; // default to first RAM bank myRAMBank->setSelectedIndex(0); } } else if(cmd == kRAMBankChanged) { if(myRAMBank->getSelected() < int(myNumRamBanks)) { myROMBank->setSelectedMax(); bank = myRAMBank->getSelected() + 256; } else { bank = 0; // default to first ROM bank myROMBank->setSelectedIndex(0); } } myCart.unlockBank(); myCart.bank(bank); myCart.lockBank(); invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge3EWidget::bankState() { ostringstream& buf = buffer(); uInt16& bank = myCart.myCurrentBank; if(bank < 256) buf << "ROM bank " << std::dec << bank % myNumRomBanks << ", RAM inactive"; else buf << "ROM inactive, RAM bank " << bank % myNumRomBanks; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Cartridge3EWidget::internalRamSize() { return 32*1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Cartridge3EWidget::internalRamRPort(int start) { return 0x0000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge3EWidget::internalRamDescription() { ostringstream desc; desc << "Accessible 1K at a time via:\n" << " $F000 - $F3FF used for Read Access\n" << " $F400 - $F7FF used for Write Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& Cartridge3EWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& Cartridge3EWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge3EWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } stella-5.1.1/src/debugger/gui/Cart3EWidget.hxx000066400000000000000000000047041324334165500211320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE3E_WIDGET_HXX #define CARTRIDGE3E_WIDGET_HXX class Cartridge3E; class PopUpWidget; #include "CartDebugWidget.hxx" class Cartridge3EWidget : public CartDebugWidget { public: Cartridge3EWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3E& cart); virtual ~Cartridge3EWidget() = default; private: Cartridge3E& myCart; const uInt32 myNumRomBanks; const uInt32 myNumRamBanks; PopUpWidget *myROMBank, *myRAMBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kROMBankChanged = 'rmCH', kRAMBankChanged = 'raCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported Cartridge3EWidget() = delete; Cartridge3EWidget(const Cartridge3EWidget&) = delete; Cartridge3EWidget(Cartridge3EWidget&&) = delete; Cartridge3EWidget& operator=(const Cartridge3EWidget&) = delete; Cartridge3EWidget& operator=(Cartridge3EWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/Cart3FWidget.cxx000066400000000000000000000063651324334165500211330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Cart3F.hxx" #include "PopUpWidget.hxx" #include "Cart3FWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3FWidget::Cartridge3FWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3F& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = cart.mySize; ostringstream info; info << "Tigervision 3F cartridge, 2-256 2K banks\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n" << "First 2K bank selected by writing to $3F\n" << "Last 2K always points to last 2K of ROM\n"; // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % 0x1000; info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; int xpos = 10, ypos = addBaseInformation(size, "TigerVision", info.str()) + myLineHeight; VariantList items; for(uInt16 i = 0; i < cart.bankCount(); ++i) VarList::push_back(items, Variant(i).toString() + " ($3F)"); ostringstream label; label << "Set bank ($" << Common::Base::HEX4 << start << " - $" << (start+0x7FF) << ") "; myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($3F) "), myLineHeight, items, label.str(), _font.getStringWidth(label.str()), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3FWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3FWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge3FWidget::bankState() { ostringstream& buf = buffer(); buf << "Bank = " << std::dec << myCart.myCurrentBank << ", hotspot = $3F"; return buf.str(); } stella-5.1.1/src/debugger/gui/Cart3FWidget.hxx000066400000000000000000000033341324334165500211310ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE3F_WIDGET_HXX #define CARTRIDGE3F_WIDGET_HXX class Cartridge3F; class PopUpWidget; #include "CartDebugWidget.hxx" class Cartridge3FWidget : public CartDebugWidget { public: Cartridge3FWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge3F& cart); virtual ~Cartridge3FWidget() = default; private: Cartridge3F& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported Cartridge3FWidget() = delete; Cartridge3FWidget(const Cartridge3FWidget&) = delete; Cartridge3FWidget(Cartridge3FWidget&&) = delete; Cartridge3FWidget& operator=(const Cartridge3FWidget&) = delete; Cartridge3FWidget& operator=(Cartridge3FWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/Cart4A50Widget.cxx000066400000000000000000000206611324334165500212670ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Cart4A50.hxx" #include "PopUpWidget.hxx" #include "Cart4A50Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4A50Widget::Cartridge4A50Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4A50& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { string info = "4A50 cartridge - 128K ROM and 32K RAM, split in various bank configurations\n" "Multiple hotspots, see documentation for further details\n" "Lower bank region (2K) : $F000 - $F7FF\n" "Middle bank region (1.5K): $F800 - $FDFF\n" "High bank region (256B) : $FE00 - $FEFF\n" "Fixed (last 256B of ROM) : $FF00 - $FFFF\n"; int xpos = 10, ypos = addBaseInformation(cart.mySize, "John Payson / Supercat", info) + myLineHeight; VariantList items16, items32, items128, items256; for(uInt32 i = 0; i < 16; ++i) VarList::push_back(items16, i); VarList::push_back(items16, "Inactive", ""); for(uInt32 i = 0; i < 32; ++i) VarList::push_back(items32, i); VarList::push_back(items32, "Inactive", ""); for(uInt32 i = 0; i < 128; ++i) VarList::push_back(items128, i); VarList::push_back(items128, "Inactive", ""); for(uInt32 i = 0; i < 256; ++i) VarList::push_back(items256, i); VarList::push_back(items256, "Inactive", ""); string lowerlabel = "Set lower 2K region ($F000 - $F7FF): "; string middlelabel = "Set middle 1.5K region ($F800 - $FDFF): "; string highlabel = "Set high 256B region ($FE00 - $FEFF): "; const int lwidth = _font.getStringWidth(middlelabel), fwidth = _font.getStringWidth("Inactive"), flwidth = _font.getStringWidth("ROM "); // Lower bank/region configuration xpos = 10; new StaticTextWidget(_boss, _font, xpos, ypos, lwidth, myFontHeight, lowerlabel, TextAlign::Left); ypos += myLineHeight + 8; xpos += 40; myROMLower = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items32, "ROM ", flwidth, kROMLowerChanged); myROMLower->setTarget(this); addFocusWidget(myROMLower); xpos += myROMLower->getWidth() + 20; myRAMLower = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items16, "RAM ", flwidth, kRAMLowerChanged); myRAMLower->setTarget(this); addFocusWidget(myRAMLower); // Middle bank/region configuration xpos = 10; ypos += myLineHeight + 14; new StaticTextWidget(_boss, _font, xpos, ypos, lwidth, myFontHeight, middlelabel, TextAlign::Left); ypos += myLineHeight + 8; xpos += 40; myROMMiddle = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items32, "ROM ", flwidth, kROMMiddleChanged); myROMMiddle->setTarget(this); addFocusWidget(myROMMiddle); xpos += myROMMiddle->getWidth() + 20; myRAMMiddle = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items16, "RAM ", flwidth, kRAMMiddleChanged); myRAMMiddle->setTarget(this); addFocusWidget(myRAMMiddle); // High bank/region configuration xpos = 10; ypos += myLineHeight + 14; new StaticTextWidget(_boss, _font, xpos, ypos, lwidth, myFontHeight, highlabel, TextAlign::Left); ypos += myLineHeight + 8; xpos += 40; myROMHigh = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items256, "ROM ", flwidth, kROMHighChanged); myROMHigh->setTarget(this); addFocusWidget(myROMHigh); xpos += myROMHigh->getWidth() + 20; myRAMHigh = new PopUpWidget(boss, _font, xpos, ypos-2, fwidth, myLineHeight, items128, "RAM ", flwidth, kRAMHighChanged); myRAMHigh->setTarget(this); addFocusWidget(myRAMHigh); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50Widget::loadConfig() { // Lower bank if(myCart.myIsRomLow) // ROM active { myROMLower->setSelectedIndex((myCart.mySliceLow >> 11) & 0x1F); myRAMLower->setSelectedMax(); } else // RAM active { myROMLower->setSelectedMax(); myRAMLower->setSelectedIndex((myCart.mySliceLow >> 11) & 0x0F); } // Middle bank if(myCart.myIsRomMiddle) // ROM active { myROMMiddle->setSelectedIndex((myCart.mySliceMiddle >> 11) & 0x1F); myRAMMiddle->setSelectedMax(); } else // RAM active { myROMMiddle->setSelectedMax(); myRAMMiddle->setSelectedIndex((myCart.mySliceMiddle >> 11) & 0x0F); } // High bank if(myCart.myIsRomHigh) // ROM active { myROMHigh->setSelectedIndex((myCart.mySliceHigh >> 11) & 0xFF); myRAMHigh->setSelectedMax(); } else // RAM active { myROMHigh->setSelectedMax(); myRAMHigh->setSelectedIndex((myCart.mySliceHigh >> 11) & 0x7F); } CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { myCart.unlockBank(); switch(cmd) { case kROMLowerChanged: if(myROMLower->getSelected() < 32) { myCart.bankROMLower(myROMLower->getSelected()); myRAMLower->setSelectedMax(); } else { // default to first RAM bank myRAMLower->setSelectedIndex(0); myCart.bankRAMLower(0); } break; case kRAMLowerChanged: if(myRAMLower->getSelected() < 16) { myROMLower->setSelectedMax(); myCart.bankRAMLower(myRAMLower->getSelected()); } else { // default to first ROM bank myROMLower->setSelectedIndex(0); myCart.bankROMLower(0); } break; case kROMMiddleChanged: if(myROMMiddle->getSelected() < 32) { myCart.bankROMMiddle(myROMMiddle->getSelected()); myRAMMiddle->setSelectedMax(); } else { // default to first RAM bank myRAMMiddle->setSelectedIndex(0); myCart.bankRAMMiddle(0); } break; case kRAMMiddleChanged: if(myRAMMiddle->getSelected() < 16) { myROMMiddle->setSelectedMax(); myCart.bankRAMMiddle(myRAMMiddle->getSelected()); } else { // default to first ROM bank myROMMiddle->setSelectedIndex(0); myCart.bankROMMiddle(0); } break; case kROMHighChanged: if(myROMHigh->getSelected() < 256) { myCart.bankROMHigh(myROMHigh->getSelected()); myRAMHigh->setSelectedMax(); } else { // default to first RAM bank myRAMHigh->setSelectedIndex(0); myCart.bankRAMHigh(0); } break; case kRAMHighChanged: if(myRAMHigh->getSelected() < 128) { myROMHigh->setSelectedMax(); myCart.bankRAMHigh(myRAMHigh->getSelected()); } else { // default to first ROM bank myROMHigh->setSelectedIndex(0); myCart.bankROMHigh(0); } break; } myCart.lockBank(); invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge4A50Widget::bankState() { ostringstream& buf = buffer(); buf << "L/M/H = " << std::dec; if(myCart.myIsRomLow) buf << "ROM bank " << ((myCart.mySliceLow >> 11) & 0x1F) << " / "; else buf << "RAM bank " << ((myCart.mySliceLow >> 11) & 0x0F) << " / "; if(myCart.myIsRomMiddle) buf << "ROM bank " << ((myCart.mySliceMiddle >> 11) & 0x1F) << " / "; else buf << "RAM bank " << ((myCart.mySliceMiddle >> 11) & 0x0F) << " / "; if(myCart.myIsRomHigh) buf << "ROM bank " << ((myCart.mySliceHigh >> 11) & 0xFF); else buf << "RAM bank " << ((myCart.mySliceHigh >> 11) & 0x7F); return buf.str(); } stella-5.1.1/src/debugger/gui/Cart4A50Widget.hxx000066400000000000000000000040421324334165500212670ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE4A50_WIDGET_HXX #define CARTRIDGE4A50_WIDGET_HXX class Cartridge4A50; class PopUpWidget; #include "CartDebugWidget.hxx" class Cartridge4A50Widget : public CartDebugWidget { public: Cartridge4A50Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4A50& cart); virtual ~Cartridge4A50Widget() = default; private: Cartridge4A50& myCart; PopUpWidget *myROMLower, *myRAMLower; PopUpWidget *myROMMiddle, *myRAMMiddle; PopUpWidget *myROMHigh, *myRAMHigh; enum { kROMLowerChanged = 'rmLW', kRAMLowerChanged = 'raLW', kROMMiddleChanged = 'rmMD', kRAMMiddleChanged = 'raMD', kROMHighChanged = 'rmHI', kRAMHighChanged = 'raHI' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported Cartridge4A50Widget() = delete; Cartridge4A50Widget(const Cartridge4A50Widget&) = delete; Cartridge4A50Widget(Cartridge4A50Widget&&) = delete; Cartridge4A50Widget& operator=(const Cartridge4A50Widget&) = delete; Cartridge4A50Widget& operator=(Cartridge4A50Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/Cart4KSCWidget.cxx000066400000000000000000000071231324334165500213600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "Cart4KSC.hxx" #include "Cart4KSCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4KSCWidget::Cartridge4KSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4KSC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[0xFFD] << 8) | cart.myImage[0xFFC]; start -= start % 0x1000; ostringstream info; info << "4KSC cartridge, non-bankswitched\n" << "128 bytes RAM @ $F000 - $F0FF\n" << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" << "Accessible @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF); addBaseInformation(4096, "homebrew intermediate format", info.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4KSCWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Cartridge4KSCWidget::internalRamSize() { return 128; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Cartridge4KSCWidget::internalRamRPort(int start) { return 0xF080 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge4KSCWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F07F used for Write Access\n" << "$F080 - $F0FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& Cartridge4KSCWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& Cartridge4KSCWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4KSCWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge4KSCWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Cartridge4KSCWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF080, false); } stella-5.1.1/src/debugger/gui/Cart4KSCWidget.hxx000066400000000000000000000045151324334165500213670ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE4KSC_WIDGET_HXX #define CARTRIDGE4KSC_WIDGET_HXX class Cartridge4KSC; #include "CartDebugWidget.hxx" class Cartridge4KSCWidget : public CartDebugWidget { public: Cartridge4KSCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4KSC& cart); virtual ~Cartridge4KSCWidget() = default; private: Cartridge4KSC& myCart; struct CartState { ByteArray internalram; }; CartState myOldState; private: // No implementation for non-bankswitched ROMs void loadConfig() override { } void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } void saveOldState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported Cartridge4KSCWidget() = delete; Cartridge4KSCWidget(const Cartridge4KSCWidget&) = delete; Cartridge4KSCWidget(Cartridge4KSCWidget&&) = delete; Cartridge4KSCWidget& operator=(const Cartridge4KSCWidget&) = delete; Cartridge4KSCWidget& operator=(Cartridge4KSCWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/Cart4KWidget.cxx000066400000000000000000000026331324334165500211330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Cart4K.hxx" #include "Cart4KWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4KWidget::Cartridge4KWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4K& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h) { // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[0xFFD] << 8) | cart.myImage[0xFFC]; start -= start % 0x1000; ostringstream info; info << "Standard 4K cartridge, non-bankswitched\n" << "Accessible @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF); addBaseInformation(4096, "Atari", info.str()); } stella-5.1.1/src/debugger/gui/Cart4KWidget.hxx000066400000000000000000000031751324334165500211420ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE4K_WIDGET_HXX #define CARTRIDGE4K_WIDGET_HXX class Cartridge4K; #include "CartDebugWidget.hxx" class Cartridge4KWidget : public CartDebugWidget { public: Cartridge4KWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, Cartridge4K& cart); virtual ~Cartridge4KWidget() = default; private: // No implementation for non-bankswitched ROMs void loadConfig() override { } void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } // Following constructors and assignment operators not supported Cartridge4KWidget() = delete; Cartridge4KWidget(const Cartridge4KWidget&) = delete; Cartridge4KWidget(Cartridge4KWidget&&) = delete; Cartridge4KWidget& operator=(const Cartridge4KWidget&) = delete; Cartridge4KWidget& operator=(Cartridge4KWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartARWidget.cxx000066400000000000000000000073731324334165500211650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartAR.hxx" #include "PopUpWidget.hxx" #include "CartARWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeARWidget::CartridgeARWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeAR& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = myCart.mySize; string info = "Supercharger cartridge, four 2K slices (3 RAM, 1 ROM)\n" "\nTHIS SCHEME IS NOT FULLY IMPLEMENTED OR TESTED\n"; int xpos = 10, ypos = addBaseInformation(size, "Starpath", info) + myLineHeight; VariantList items; VarList::push_back(items, " 0"); VarList::push_back(items, " 1"); VarList::push_back(items, " 2"); VarList::push_back(items, " 3"); VarList::push_back(items, " 4"); VarList::push_back(items, " 5"); VarList::push_back(items, " 6"); VarList::push_back(items, " 7"); VarList::push_back(items, " 8"); VarList::push_back(items, " 9"); VarList::push_back(items, " 10"); VarList::push_back(items, " 11"); VarList::push_back(items, " 12"); VarList::push_back(items, " 13"); VarList::push_back(items, " 14"); VarList::push_back(items, " 15"); VarList::push_back(items, " 16"); VarList::push_back(items, " 17"); VarList::push_back(items, " 18"); VarList::push_back(items, " 19"); VarList::push_back(items, " 20"); VarList::push_back(items, " 21"); VarList::push_back(items, " 22"); VarList::push_back(items, " 23"); VarList::push_back(items, " 24"); VarList::push_back(items, " 25"); VarList::push_back(items, " 26"); VarList::push_back(items, " 27"); VarList::push_back(items, " 28"); VarList::push_back(items, " 29"); VarList::push_back(items, " 30"); VarList::push_back(items, " 31"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth(" XX "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeARWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeARWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeARWidget::bankState() { ostringstream& buf = buffer(); buf << "Bank = " << std::dec << myCart.myCurrentBank; return buf.str(); } stella-5.1.1/src/debugger/gui/CartARWidget.hxx000066400000000000000000000033341324334165500211630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEAR_WIDGET_HXX #define CARTRIDGEAR_WIDGET_HXX class CartridgeAR; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeARWidget : public CartDebugWidget { public: CartridgeARWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeAR& cart); virtual ~CartridgeARWidget() = default; private: CartridgeAR& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeARWidget() = delete; CartridgeARWidget(const CartridgeARWidget&) = delete; CartridgeARWidget(CartridgeARWidget&&) = delete; CartridgeARWidget& operator=(const CartridgeARWidget&) = delete; CartridgeARWidget& operator=(CartridgeARWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartBFSCWidget.cxx000066400000000000000000000205761324334165500214000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartBFSC.hxx" #include "PopUpWidget.hxx" #include "CartBFSCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBFSCWidget::CartridgeBFSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBFSC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 64 * 4096; ostringstream info; info << "256K BFSC + RAM, 64 4K banks\n" << "128 bytes RAM @ $F000 - $F0FF\n" << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" << "Startup bank = " << cart.myStartBank << "\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xF80; i < 64; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, " 0 ($FF80)"); VarList::push_back(items, " 1 ($FF81)"); VarList::push_back(items, " 2 ($FF82)"); VarList::push_back(items, " 3 ($FF83)"); VarList::push_back(items, " 4 ($FF84)"); VarList::push_back(items, " 5 ($FF85)"); VarList::push_back(items, " 6 ($FF86)"); VarList::push_back(items, " 7 ($FF87)"); VarList::push_back(items, " 8 ($FF88)"); VarList::push_back(items, " 9 ($FF89)"); VarList::push_back(items, "10 ($FF8A)"); VarList::push_back(items, "11 ($FF8B)"); VarList::push_back(items, "12 ($FF8C)"); VarList::push_back(items, "13 ($FF8D)"); VarList::push_back(items, "14 ($FF8E)"); VarList::push_back(items, "15 ($FF8F)"); VarList::push_back(items, "16 ($FF90)"); VarList::push_back(items, "17 ($FF91)"); VarList::push_back(items, "18 ($FF92)"); VarList::push_back(items, "19 ($FF93)"); VarList::push_back(items, "20 ($FF94)"); VarList::push_back(items, "21 ($FF95)"); VarList::push_back(items, "22 ($FF96)"); VarList::push_back(items, "23 ($FF97)"); VarList::push_back(items, "24 ($FF98)"); VarList::push_back(items, "25 ($FF99)"); VarList::push_back(items, "26 ($FF9A)"); VarList::push_back(items, "27 ($FF9B)"); VarList::push_back(items, "28 ($FF9C)"); VarList::push_back(items, "29 ($FF9D)"); VarList::push_back(items, "30 ($FF9E)"); VarList::push_back(items, "31 ($FF9F)"); VarList::push_back(items, "32 ($FFA0)"); VarList::push_back(items, "33 ($FFA1)"); VarList::push_back(items, "34 ($FFA2)"); VarList::push_back(items, "35 ($FFA3)"); VarList::push_back(items, "36 ($FFA4)"); VarList::push_back(items, "37 ($FFA5)"); VarList::push_back(items, "38 ($FFA6)"); VarList::push_back(items, "39 ($FFA7)"); VarList::push_back(items, "40 ($FFA8)"); VarList::push_back(items, "41 ($FFA9)"); VarList::push_back(items, "42 ($FFAA)"); VarList::push_back(items, "43 ($FFAB)"); VarList::push_back(items, "44 ($FFAC)"); VarList::push_back(items, "45 ($FFAD)"); VarList::push_back(items, "46 ($FFAE)"); VarList::push_back(items, "47 ($FFAF)"); VarList::push_back(items, "48 ($FFB0)"); VarList::push_back(items, "49 ($FFB1)"); VarList::push_back(items, "50 ($FFB2)"); VarList::push_back(items, "51 ($FFB3)"); VarList::push_back(items, "52 ($FFB4)"); VarList::push_back(items, "53 ($FFB5)"); VarList::push_back(items, "54 ($FFB6)"); VarList::push_back(items, "55 ($FFB7)"); VarList::push_back(items, "56 ($FFB8)"); VarList::push_back(items, "57 ($FFB9)"); VarList::push_back(items, "58 ($FFBA)"); VarList::push_back(items, "59 ($FFBB)"); VarList::push_back(items, "60 ($FFBC)"); VarList::push_back(items, "61 ($FFBD)"); VarList::push_back(items, "62 ($FFBE)"); VarList::push_back(items, "63 ($FFBF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("63 ($FFBF) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSCWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSCWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSCWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeBFSCWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FF80", "$FF81", "$FF82", "$FF83", "$FF84", "$FF85", "$FF86", "$FF87", "$FF88", "$FF89", "$FF8A", "$FF8B", "$FF8C", "$FF8D", "$FF8E", "$FF8F", "$FF90", "$FF91", "$FF92", "$FF93", "$FF94", "$FF95", "$FF96", "$FF97", "$FF98", "$FF99", "$FF9A", "$FF9B", "$FF9C", "$FF9D", "$FF9E", "$FF9F", "$FFA0", "$FFA1", "$FFA2", "$FFA3", "$FFA4", "$FFA5", "$FFA6", "$FFA7", "$FFA8", "$FFA9", "$FFAA", "$FFAB", "$FFAC", "$FFAD", "$FFAE", "$FFAF", "$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7", "$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBFSCWidget::internalRamSize() { return 128; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBFSCWidget::internalRamRPort(int start) { return 0xF080 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeBFSCWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F07F used for Write Access\n" << "$F080 - $F0FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeBFSCWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeBFSCWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSCWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBFSCWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeBFSCWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF080, false); } stella-5.1.1/src/debugger/gui/CartBFSCWidget.hxx000066400000000000000000000046401324334165500213770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEBFSC_WIDGET_HXX #define CARTRIDGEBFSC_WIDGET_HXX class CartridgeBFSC; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeBFSCWidget : public CartDebugWidget { public: CartridgeBFSCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBFSC& cart); virtual ~CartridgeBFSCWidget() = default; private: CartridgeBFSC& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeBFSCWidget() = delete; CartridgeBFSCWidget(const CartridgeBFSCWidget&) = delete; CartridgeBFSCWidget(CartridgeBFSCWidget&&) = delete; CartridgeBFSCWidget& operator=(const CartridgeBFSCWidget&) = delete; CartridgeBFSCWidget& operator=(CartridgeBFSCWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartBFWidget.cxx000066400000000000000000000146231324334165500211460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartBF.hxx" #include "PopUpWidget.hxx" #include "CartBFWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBFWidget::CartridgeBFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBF& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 64 * 4096; ostringstream info; info << "BF cartridge, 64 4K banks\n" << "Startup bank = " << cart.myStartBank << "\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xF80; i < 64; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, " 0 ($FF80)"); VarList::push_back(items, " 1 ($FF81)"); VarList::push_back(items, " 2 ($FF82)"); VarList::push_back(items, " 3 ($FF83)"); VarList::push_back(items, " 4 ($FF84)"); VarList::push_back(items, " 5 ($FF85)"); VarList::push_back(items, " 6 ($FF86)"); VarList::push_back(items, " 7 ($FF87)"); VarList::push_back(items, " 8 ($FF88)"); VarList::push_back(items, " 9 ($FF89)"); VarList::push_back(items, "10 ($FF8A)"); VarList::push_back(items, "11 ($FF8B)"); VarList::push_back(items, "12 ($FF8C)"); VarList::push_back(items, "13 ($FF8D)"); VarList::push_back(items, "14 ($FF8E)"); VarList::push_back(items, "15 ($FF8F)"); VarList::push_back(items, "16 ($FF90)"); VarList::push_back(items, "17 ($FF91)"); VarList::push_back(items, "18 ($FF92)"); VarList::push_back(items, "19 ($FF93)"); VarList::push_back(items, "20 ($FF94)"); VarList::push_back(items, "21 ($FF95)"); VarList::push_back(items, "22 ($FF96)"); VarList::push_back(items, "23 ($FF97)"); VarList::push_back(items, "24 ($FF98)"); VarList::push_back(items, "25 ($FF99)"); VarList::push_back(items, "26 ($FF9A)"); VarList::push_back(items, "27 ($FF9B)"); VarList::push_back(items, "28 ($FF9C)"); VarList::push_back(items, "29 ($FF9D)"); VarList::push_back(items, "30 ($FF9E)"); VarList::push_back(items, "31 ($FF9F)"); VarList::push_back(items, "32 ($FFA0)"); VarList::push_back(items, "33 ($FFA1)"); VarList::push_back(items, "34 ($FFA2)"); VarList::push_back(items, "35 ($FFA3)"); VarList::push_back(items, "36 ($FFA4)"); VarList::push_back(items, "37 ($FFA5)"); VarList::push_back(items, "38 ($FFA6)"); VarList::push_back(items, "39 ($FFA7)"); VarList::push_back(items, "40 ($FFA8)"); VarList::push_back(items, "41 ($FFA9)"); VarList::push_back(items, "42 ($FFAA)"); VarList::push_back(items, "43 ($FFAB)"); VarList::push_back(items, "44 ($FFAC)"); VarList::push_back(items, "45 ($FFAD)"); VarList::push_back(items, "46 ($FFAE)"); VarList::push_back(items, "47 ($FFAF)"); VarList::push_back(items, "48 ($FFB0)"); VarList::push_back(items, "49 ($FFB1)"); VarList::push_back(items, "50 ($FFB2)"); VarList::push_back(items, "51 ($FFB3)"); VarList::push_back(items, "52 ($FFB4)"); VarList::push_back(items, "53 ($FFB5)"); VarList::push_back(items, "54 ($FFB6)"); VarList::push_back(items, "55 ($FFB7)"); VarList::push_back(items, "56 ($FFB8)"); VarList::push_back(items, "57 ($FFB9)"); VarList::push_back(items, "58 ($FFBA)"); VarList::push_back(items, "59 ($FFBB)"); VarList::push_back(items, "60 ($FFBC)"); VarList::push_back(items, "61 ($FFBD)"); VarList::push_back(items, "62 ($FFBE)"); VarList::push_back(items, "63 ($FFBF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("64 ($FFBF) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeBFWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FF80", "$FF81", "$FF82", "$FF83", "$FF84", "$FF85", "$FF86", "$FF87", "$FF88", "$FF89", "$FF8A", "$FF8B", "$FF8C", "$FF8D", "$FF8E", "$FF8F", "$FF90", "$FF91", "$FF92", "$FF93", "$FF94", "$FF95", "$FF96", "$FF97", "$FF98", "$FF99", "$FF9A", "$FF9B", "$FF9C", "$FF9D", "$FF9E", "$FF9F", "$FFA0", "$FFA1", "$FFA2", "$FFA3", "$FFA4", "$FFA5", "$FFA6", "$FFA7", "$FFA8", "$FFA9", "$FFAA", "$FFAB", "$FFAC", "$FFAD", "$FFAE", "$FFAF", "$FFB0", "$FFB1", "$FFB2", "$FFB3", "$FFB4", "$FFB5", "$FFB6", "$FFB7", "$FFB8", "$FFB9", "$FFBA", "$FFBB", "$FFBC", "$FFBD", "$FFBE", "$FFBF" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartBFWidget.hxx000066400000000000000000000033341324334165500211500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEBF_WIDGET_HXX #define CARTRIDGEBF_WIDGET_HXX class CartridgeBF; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeBFWidget : public CartDebugWidget { public: CartridgeBFWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBF& cart); virtual ~CartridgeBFWidget() = default; private: CartridgeBF& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeBFWidget() = delete; CartridgeBFWidget(const CartridgeBFWidget&) = delete; CartridgeBFWidget(CartridgeBFWidget&&) = delete; CartridgeBFWidget& operator=(const CartridgeBFWidget&) = delete; CartridgeBFWidget& operator=(CartridgeBFWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartBUSWidget.cxx000066400000000000000000000376171324334165500213200ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartBUS.hxx" #include "DataGridWidget.hxx" #include "PopUpWidget.hxx" #include "CartBUSWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBUSWidget::CartridgeBUSWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBUS& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 8 * 4096; ostringstream info; info << "BUS Stuffing cartridge (EXPERIMENTAL)\n" << "32K ROM, seven 4K banks are accessible to 2600\n" << "8K BUS RAM\n" << "BUS registers accessible @ $FFEE - $FFF3\n" << "Banks accessible at hotspots $FFFF to $FFFB\n" << "Startup bank = " << cart.myStartBank << "\n"; #if 0 // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < 7; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << HEX4 << (start + 0x80) << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } #endif int xpos = 10, ypos = addBaseInformation(size, "AtariAge", info.str(), 4) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF5)"); VarList::push_back(items, "1 ($FFF6)"); VarList::push_back(items, "2 ($FFF7)"); VarList::push_back(items, "3 ($FFF8)"); VarList::push_back(items, "4 ($FFF9)"); VarList::push_back(items, "5 ($FFFA)"); VarList::push_back(items, "6 ($FFFB)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); int lwidth = _font.getStringWidth("Datastream Increments "); // get width of the widest label // Datastream Pointers #define DS_X 30 xpos = DS_X; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Datastream Pointers", TextAlign::Left); xpos += lwidth; myDatastreamPointers = new DataGridWidget(boss, _nfont, DS_X, ypos+myLineHeight-2, 4, 4, 6, 32, Common::Base::F_16_3_2); myDatastreamPointers->setTarget(this); myDatastreamPointers->setEditable(false); myDatastreamPointers2 = new DataGridWidget(boss, _nfont, DS_X + myDatastreamPointers->getWidth() * 3 / 4, ypos+myLineHeight-2 + 4*myLineHeight, 1, 2, 6, 32, Common::Base::F_16_3_2); myDatastreamPointers2->setTarget(this); myDatastreamPointers2->setEditable(false); uInt32 row; for(row = 0; row < 4; ++row) { myDatastreamLabels[row] = new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight-2 + row*myLineHeight + 2, myFontWidth*2, myFontHeight, "", TextAlign::Left); myDatastreamLabels[row]->setLabel(Common::Base::toString(row * 4, Common::Base::F_16_2)); } lwidth = _font.getStringWidth("Write Data (stream 16)"); myDatastreamLabels[4] = new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight-2 + 4*myLineHeight + 2, lwidth, myFontHeight, "Write Data (stream 16)", TextAlign::Left); myDatastreamLabels[5] = new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight-2 + 5*myLineHeight + 2, lwidth, myFontHeight, "Jump Data (stream 17)", TextAlign::Left); // Datastream Increments xpos = DS_X + myDatastreamPointers->getWidth() + 20; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Datastream Increments", TextAlign::Left); myDatastreamIncrements = new DataGridWidget(boss, _nfont, xpos, ypos+myLineHeight-2, 4, 4, 5, 32, Common::Base::F_16_2_2); myDatastreamIncrements->setTarget(this); myDatastreamIncrements->setEditable(false); myDatastreamIncrements2 = new DataGridWidget(boss, _nfont, xpos, ypos+myLineHeight-2 + 4*myLineHeight, 1, 2, 5, 32, Common::Base::F_16_2_2); myDatastreamIncrements2->setTarget(this); myDatastreamIncrements2->setEditable(false); // Datastream Maps xpos = 0; ypos += myLineHeight*7 + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Address Maps", TextAlign::Left); myAddressMaps = new DataGridWidget(boss, _nfont, 0, ypos+myLineHeight-2, 8, 5, 8, 32, Common::Base::F_16_8); myAddressMaps->setTarget(this); myAddressMaps->setEditable(false); // Music counters xpos = 10; ypos += myLineHeight*6 + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Counters", TextAlign::Left); xpos += lwidth; myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8); myMusicCounters->setTarget(this); myMusicCounters->setEditable(false); // Music frequencies xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Frequencies", TextAlign::Left); xpos += lwidth; myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8); myMusicFrequencies->setTarget(this); myMusicFrequencies->setEditable(false); // Music waveforms xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Waveforms", TextAlign::Left); xpos += lwidth; myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2); myMusicWaveforms->setTarget(this); myMusicWaveforms->setEditable(false); int xpossp = xpos + myMusicWaveforms->getWidth() + 20; int lwidth2 = _font.getStringWidth("Sample Pointer "); new StaticTextWidget(boss, _font, xpossp, ypos, lwidth2, myFontHeight, "Sample Pointer ", TextAlign::Left); mySamplePointer = new DataGridWidget(boss, _nfont, xpossp + lwidth2, ypos-2, 1, 1, 8, 32, Common::Base::F_16_8); mySamplePointer->setTarget(this); mySamplePointer->setEditable(false); // Music waveform sizes xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Waveform Sizes", TextAlign::Left); xpos += lwidth; myMusicWaveformSizes = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2); myMusicWaveformSizes->setTarget(this); myMusicWaveformSizes->setEditable(false); // BUS stuff and Digital Audio flags xpos = 10; ypos += myLineHeight + 4; myBusOverdrive = new CheckboxWidget(boss, _font, xpos, ypos, "BUS Overdrive enabled"); myBusOverdrive->setTarget(this); myBusOverdrive->setEditable(false); myDigitalSample = new CheckboxWidget(boss, _font, xpossp, ypos, "Digital Sample mode"); myDigitalSample->setTarget(this); myDigitalSample->setEditable(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUSWidget::saveOldState() { myOldState.tops.clear(); myOldState.bottoms.clear(); myOldState.datastreampointers.clear(); myOldState.datastreamincrements.clear(); myOldState.addressmaps.clear(); myOldState.mcounters.clear(); myOldState.mfreqs.clear(); myOldState.mwaves.clear(); myOldState.mwavesizes.clear(); myOldState.internalram.clear(); myOldState.samplepointer.clear(); for(uInt32 i = 0; i < 18; i++) { // Pointers are stored as: // PPPFF--- // // Increments are stored as // ----IIFF // // P = Pointer // I = Increment // F = Fractional myOldState.datastreampointers.push_back(myCart.getDatastreamPointer(i)>>12); if (i < 16) myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i)); else myOldState.datastreamincrements.push_back(0x100); } for(uInt32 i = 0; i < 37; i++) // only 37 map values { myOldState.addressmaps.push_back(myCart.getAddressMap(i)); } for(uInt32 i = 37; i < 40; i++) // but need 40 for the grid { myOldState.addressmaps.push_back(0); } for(uInt32 i = 0; i < 3; ++i) { myOldState.mcounters.push_back(myCart.myMusicCounters[i]); } for(uInt32 i = 0; i < 3; ++i) { myOldState.mfreqs.push_back(myCart.myMusicFrequencies[i]); myOldState.mwaves.push_back(myCart.getWaveform(i) >> 5); myOldState.mwavesizes.push_back(myCart.getWaveformSize((i))); } for(uInt32 i = 0; i < internalRamSize(); ++i) myOldState.internalram.push_back(myCart.myBUSRAM[i]); myOldState.samplepointer.push_back(myCart.getSample()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUSWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank()); // Get registers, using change tracking IntArray alist; IntArray vlist; BoolArray changed; alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 16; ++i) { // Pointers are stored as: // PPPFF--- // // Increments are stored as // ----IIFF // // P = Pointer // I = Increment // F = Fractional Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12; alist.push_back(0); vlist.push_back(pointervalue); changed.push_back(pointervalue != myOldState.datastreampointers[i]); } myDatastreamPointers->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 16; i < 18; ++i) { Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12; alist.push_back(0); vlist.push_back(pointervalue); changed.push_back(pointervalue != myOldState.datastreampointers[i]); } myDatastreamPointers2->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 16; ++i) { Int32 incrementvalue = myCart.getDatastreamIncrement(i); alist.push_back(0); vlist.push_back(incrementvalue); changed.push_back(incrementvalue != myOldState.datastreamincrements[i]); } myDatastreamIncrements->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 16; i < 18; ++i) { Int32 incrementvalue = 0x100; alist.push_back(0); vlist.push_back(incrementvalue); changed.push_back(incrementvalue != myOldState.datastreamincrements[i]); } myDatastreamIncrements2->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 37; ++i) // only 37 map values { Int32 mapvalue = myCart.getAddressMap(i); alist.push_back(0); vlist.push_back(mapvalue); changed.push_back(mapvalue != myOldState.addressmaps[i]); } for(int i = 37; i < 40; ++i) // but need 40 for the grid { Int32 mapvalue = 0; alist.push_back(0); vlist.push_back(mapvalue); changed.push_back(mapvalue != myOldState.addressmaps[i]); } myAddressMaps->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.myMusicCounters[i]); changed.push_back(myCart.myMusicCounters[i] != uInt32(myOldState.mcounters[i])); } myMusicCounters->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[i]); changed.push_back(myCart.myMusicFrequencies[i] != uInt32(myOldState.mfreqs[i])); } myMusicFrequencies->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.getWaveform(i) >> 5); changed.push_back((myCart.getWaveform(i) >> 5) != uInt32(myOldState.mwaves[i])); } myMusicWaveforms->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.getWaveformSize(i)); changed.push_back((myCart.getWaveformSize(i)) != uInt32(myOldState.mwavesizes[i])); } myMusicWaveformSizes->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); alist.push_back(0); vlist.push_back(myCart.getSample()); changed.push_back((myCart.getSample()) != uInt32(myOldState.samplepointer[0])); mySamplePointer->setList(alist, vlist, changed); myBusOverdrive->setState((myCart.myMode & 0x0f) == 0); myDigitalSample->setState((myCart.myMode & 0xf0) == 0); if ((myCart.myMode & 0xf0) == 0) { myMusicWaveforms->setCrossed(true); myMusicWaveformSizes->setCrossed(true); mySamplePointer->setCrossed(false); } else { myMusicWaveforms->setCrossed(false); myMusicWaveformSizes->setCrossed(false); mySamplePointer->setCrossed(true); } CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUSWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeBUSWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUSWidget::internalRamSize() { return 8*1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUSWidget::internalRamRPort(int start) { return 0x0000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeBUSWidget::internalRamDescription() { ostringstream desc; desc << "$0000 - $07FF - BUS driver\n" << " not accessible to 6507\n" << "$0800 - $17FF - 4K Data Stream storage\n" << " indirectly accessible to 6507\n" << " via BUS's Data Stream registers\n" << "$1800 - $1FFF - 2K C variable storage and stack\n" << " not accessible to 6507"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeBUSWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeBUSWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myBUSRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUSWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myBUSRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBUSWidget::internalRamGetValue(int addr) { return myCart.myBUSRAM[addr]; } stella-5.1.1/src/debugger/gui/CartBUSWidget.hxx000066400000000000000000000062511324334165500213130ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEBUS_WIDGET_HXX #define CARTRIDGEBUS_WIDGET_HXX class CartridgeBUS; class PopUpWidget; class CheckboxWidget; class DataGridWidget; #include "CartDebugWidget.hxx" class CartridgeBUSWidget : public CartDebugWidget { public: CartridgeBUSWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeBUS& cart); virtual ~CartridgeBUSWidget() = default; private: struct CartState { ByteArray tops; ByteArray bottoms; IntArray datastreampointers; IntArray datastreamincrements; IntArray addressmaps; IntArray mcounters; IntArray mfreqs; IntArray mwaves; IntArray mwavesizes; IntArray samplepointer; uInt32 random; ByteArray internalram; }; CartridgeBUS& myCart; PopUpWidget* myBank; DataGridWidget* myDatastreamPointers; DataGridWidget* myDatastreamIncrements; DataGridWidget* myDatastreamPointers2; DataGridWidget* myDatastreamIncrements2; DataGridWidget* myAddressMaps; DataGridWidget* myMusicCounters; DataGridWidget* myMusicFrequencies; DataGridWidget* myMusicWaveforms; DataGridWidget* myMusicWaveformSizes; DataGridWidget* mySamplePointer; StaticTextWidget* myDatastreamLabels[6]; CheckboxWidget* myBusOverdrive; CheckboxWidget* myDigitalSample; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeBUSWidget() = delete; CartridgeBUSWidget(const CartridgeBUSWidget&) = delete; CartridgeBUSWidget(CartridgeBUSWidget&&) = delete; CartridgeBUSWidget& operator=(const CartridgeBUSWidget&) = delete; CartridgeBUSWidget& operator=(CartridgeBUSWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartCDFWidget.cxx000066400000000000000000000352641324334165500212570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartCDF.hxx" #include "DataGridWidget.hxx" #include "PopUpWidget.hxx" #include "CartCDFWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCDFWidget::CartridgeCDFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCDF& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 8 * 4096; ostringstream info; info << "CDF cartridge (version " << cart.myVersion << ")\n" << "32K ROM, seven 4K banks are accessible to 2600\n" << "8K CDF RAM\n" << "CDF registers accessible @ $FFF0 - $FFF3\n" << "Banks accessible at hotspots $FFF5 to $FFFB\n" << "Startup bank = " << cart.myStartBank << "\n"; #if 0 // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < 7; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << HEX4 << (start + 0x80) << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } #endif int xpos = 10, ypos = addBaseInformation(size, "AtariAge", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF5)"); VarList::push_back(items, "1 ($FFF6)"); VarList::push_back(items, "2 ($FFF7)"); VarList::push_back(items, "3 ($FFF8)"); VarList::push_back(items, "4 ($FFF9)"); VarList::push_back(items, "5 ($FFFA)"); VarList::push_back(items, "6 ($FFFB)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); int lwidth = _font.getStringWidth("Datastream Increments"); // get width of the widest label // Datastream Pointers #define DS_X 30 xpos = DS_X; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Datastream Pointers", TextAlign::Left); xpos += lwidth; myDatastreamPointers = new DataGridWidget(boss, _nfont, DS_X, ypos+myLineHeight-2, 4, 8, 6, 32, Common::Base::F_16_3_2); myDatastreamPointers->setTarget(this); myDatastreamPointers->setEditable(false); myDatastreamPointers2 = new DataGridWidget(boss, _nfont, DS_X + myDatastreamPointers->getWidth() * 3 / 4, ypos+myLineHeight-2 + 8*myLineHeight, 1, 2, 6, 32, Common::Base::F_16_3_2); myDatastreamPointers2->setTarget(this); myDatastreamPointers2->setEditable(false); uInt32 row; for(row = 0; row < 8; ++row) { myDatastreamLabels[row] = new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight-2 + row*myLineHeight + 2, myFontWidth*2, myFontHeight, "", TextAlign::Left); myDatastreamLabels[row]->setLabel(Common::Base::toString(row * 4, Common::Base::F_16_2)); } lwidth = _font.getStringWidth("Write Data (stream 20)"); myDatastreamLabels[8] = new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight-2 + 8*myLineHeight + 2, lwidth, myFontHeight, "Write Data (stream 20)", TextAlign::Left); myDatastreamLabels[9] = new StaticTextWidget(_boss, _font, DS_X - _font.getStringWidth("xx "), ypos+myLineHeight-2 + 9*myLineHeight + 2, lwidth, myFontHeight, "Jump Data (stream 21)", TextAlign::Left); // Datastream Increments xpos = DS_X + myDatastreamPointers->getWidth() + 20; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Datastream Increments", TextAlign::Left); myDatastreamIncrements = new DataGridWidget(boss, _nfont, xpos, ypos+myLineHeight-2, 4, 8, 5, 32, Common::Base::F_16_2_2); myDatastreamIncrements->setTarget(this); myDatastreamIncrements->setEditable(false); myDatastreamIncrements2 = new DataGridWidget(boss, _nfont, xpos, ypos+myLineHeight-2 + 8*myLineHeight, 1, 2, 5, 32, Common::Base::F_16_2_2); myDatastreamIncrements2->setTarget(this); myDatastreamIncrements2->setEditable(false); // Music counters xpos = 10; ypos += myLineHeight*12 + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Counters", TextAlign::Left); xpos += lwidth; myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8); myMusicCounters->setTarget(this); myMusicCounters->setEditable(false); // Music frequencies xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Frequencies", TextAlign::Left); xpos += lwidth; myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8); myMusicFrequencies->setTarget(this); myMusicFrequencies->setEditable(false); // Music waveforms xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Waveforms", TextAlign::Left); xpos += lwidth; myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2); myMusicWaveforms->setTarget(this); myMusicWaveforms->setEditable(false); int xpossp = xpos + myMusicWaveforms->getWidth() + 20; int lwidth2 = _font.getStringWidth("Sample Pointer "); new StaticTextWidget(boss, _font, xpossp, ypos, lwidth2, myFontHeight, "Sample Pointer ", TextAlign::Left); mySamplePointer = new DataGridWidget(boss, _nfont, xpossp + lwidth2, ypos-2, 1, 1, 8, 32, Common::Base::F_16_8); mySamplePointer->setTarget(this); mySamplePointer->setEditable(false); // Music waveform sizes xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Waveform Sizes", TextAlign::Left); xpos += lwidth; myMusicWaveformSizes = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_2); myMusicWaveformSizes->setTarget(this); myMusicWaveformSizes->setEditable(false); // Fast Fetch and Digital Audio flags xpos = 10; ypos += myLineHeight + 4; myFastFetch = new CheckboxWidget(boss, _font, xpos, ypos, "Fast Fetcher enabled"); myFastFetch->setTarget(this); myFastFetch->setEditable(false); myDigitalSample = new CheckboxWidget(boss, _font, xpossp, ypos, "Digital Sample mode"); myDigitalSample->setTarget(this); myDigitalSample->setEditable(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDFWidget::saveOldState() { myOldState.tops.clear(); myOldState.bottoms.clear(); myOldState.datastreampointers.clear(); myOldState.datastreamincrements.clear(); myOldState.addressmaps.clear(); myOldState.mcounters.clear(); myOldState.mfreqs.clear(); myOldState.mwaves.clear(); myOldState.mwavesizes.clear(); myOldState.internalram.clear(); myOldState.samplepointer.clear(); for(uInt32 i = 0; i < 34; i++) { // Pointers are stored as: // PPPFF--- // // Increments are stored as // ----IIFF // // P = Pointer // I = Increment // F = Fractional myOldState.datastreampointers.push_back(myCart.getDatastreamPointer(i)>>12); myOldState.datastreamincrements.push_back(myCart.getDatastreamIncrement(i)); } for(uInt32 i = 0; i < 3; ++i) { myOldState.mcounters.push_back(myCart.myMusicCounters[i]); } for(uInt32 i = 0; i < 3; ++i) { myOldState.mfreqs.push_back(myCart.myMusicFrequencies[i]); myOldState.mwaves.push_back(myCart.getWaveform(i) >> 5); myOldState.mwavesizes.push_back(myCart.getWaveformSize((i))); } for(uInt32 i = 0; i < internalRamSize(); ++i) myOldState.internalram.push_back(myCart.myCDFRAM[i]); myOldState.samplepointer.push_back(myCart.getSample()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDFWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank()); // Get registers, using change tracking IntArray alist; IntArray vlist; BoolArray changed; alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 32; ++i) { // Pointers are stored as: // PPPFF--- // // Increments are stored as // ----IIFF // // P = Pointer // I = Increment // F = Fractional Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12; alist.push_back(0); vlist.push_back(pointervalue); changed.push_back(pointervalue != myOldState.datastreampointers[i]); } myDatastreamPointers->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 32; i < 34; ++i) { Int32 pointervalue = myCart.getDatastreamPointer(i) >> 12; alist.push_back(0); vlist.push_back(pointervalue); changed.push_back(pointervalue != myOldState.datastreampointers[i]); } myDatastreamPointers2->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 32; ++i) { Int32 incrementvalue = myCart.getDatastreamIncrement(i); alist.push_back(0); vlist.push_back(incrementvalue); changed.push_back(incrementvalue != myOldState.datastreamincrements[i]); } myDatastreamIncrements->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 32; i < 34; ++i) { Int32 incrementvalue = myCart.getDatastreamIncrement(i); alist.push_back(0); vlist.push_back(incrementvalue); changed.push_back(incrementvalue != myOldState.datastreamincrements[i]); } myDatastreamIncrements2->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.myMusicCounters[i]); changed.push_back(myCart.myMusicCounters[i] != uInt32(myOldState.mcounters[i])); } myMusicCounters->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[i]); changed.push_back(myCart.myMusicFrequencies[i] != uInt32(myOldState.mfreqs[i])); } myMusicFrequencies->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.getWaveform(i) >> 5); changed.push_back((myCart.getWaveform(i) >> 5) != uInt32(myOldState.mwaves[i])); } myMusicWaveforms->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.getWaveformSize(i)); changed.push_back((myCart.getWaveformSize(i)) != uInt32(myOldState.mwavesizes[i])); } myMusicWaveformSizes->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); alist.push_back(0); vlist.push_back(myCart.getSample()); changed.push_back((myCart.getSample()) != uInt32(myOldState.samplepointer[0])); mySamplePointer->setList(alist, vlist, changed); myFastFetch->setState((myCart.myMode & 0x0f) == 0); myDigitalSample->setState((myCart.myMode & 0xf0) == 0); if ((myCart.myMode & 0xf0) == 0) { myMusicWaveforms->setCrossed(true); myMusicWaveformSizes->setCrossed(true); mySamplePointer->setCrossed(false); } else { myMusicWaveforms->setCrossed(false); myMusicWaveformSizes->setCrossed(false); mySamplePointer->setCrossed(true); } CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDFWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCDFWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDFWidget::internalRamSize() { return 8*1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDFWidget::internalRamRPort(int start) { return 0x0000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCDFWidget::internalRamDescription() { ostringstream desc; desc << "$0000 - $07FF - CDF driver\n" << " not accessible to 6507\n" << "$0800 - $17FF - 4K Data Stream storage\n" << " indirectly accessible to 6507\n" << " via CDF's Data Stream registers\n" << "$1800 - $1FFF - 2K C variable storage and stack\n" << " not accessible to 6507"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCDFWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCDFWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myCDFRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDFWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myCDFRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCDFWidget::internalRamGetValue(int addr) { return myCart.myCDFRAM[addr]; } stella-5.1.1/src/debugger/gui/CartCDFWidget.hxx000066400000000000000000000062351324334165500212600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECDF_WIDGET_HXX #define CARTRIDGECDF_WIDGET_HXX class CartridgeCDF; class PopUpWidget; class CheckboxWidget; class DataGridWidget; class StaticTextWidget; #include "CartDebugWidget.hxx" class CartridgeCDFWidget : public CartDebugWidget { public: CartridgeCDFWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCDF& cart); virtual ~CartridgeCDFWidget() = default; private: struct CartState { ByteArray tops; ByteArray bottoms; IntArray datastreampointers; IntArray datastreamincrements; IntArray addressmaps; IntArray mcounters; IntArray mfreqs; IntArray mwaves; IntArray mwavesizes; IntArray samplepointer; uInt32 random; ByteArray internalram; }; CartridgeCDF& myCart; PopUpWidget* myBank; DataGridWidget* myDatastreamPointers; DataGridWidget* myDatastreamIncrements; DataGridWidget* myDatastreamPointers2; DataGridWidget* myDatastreamIncrements2; DataGridWidget* myMusicCounters; DataGridWidget* myMusicFrequencies; DataGridWidget* myMusicWaveforms; DataGridWidget* myMusicWaveformSizes; DataGridWidget* mySamplePointer; StaticTextWidget* myDatastreamLabels[10]; CheckboxWidget* myFastFetch; CheckboxWidget* myDigitalSample; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeCDFWidget() = delete; CartridgeCDFWidget(const CartridgeCDFWidget&) = delete; CartridgeCDFWidget(CartridgeCDFWidget&&) = delete; CartridgeCDFWidget& operator=(const CartridgeCDFWidget&) = delete; CartridgeCDFWidget& operator=(CartridgeCDFWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartCMWidget.cxx000066400000000000000000000226361324334165500211610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartCM.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "RiotDebug.hxx" #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "ToggleBitWidget.hxx" #include "CartCMWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCMWidget::CartridgeCMWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCM& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 4 * 4096; string info = "CM cartridge, four 4K banks + 2K RAM\n" "2K RAM accessible @ $1800 - $1FFF in read or write-only mode " "(no separate ports)\n" "All TIA controller registers (INPT0-INPT5) and RIOT SWCHA are " "used to control the cart functionality\n" "Startup bank = 3 (ROM), RAM disabled\n"; int xpos = 10, ypos = addBaseInformation(size, "CompuMate", info) + myLineHeight; VariantList items; VarList::push_back(items, " 0 "); VarList::push_back(items, " 1 "); VarList::push_back(items, " 2 "); VarList::push_back(items, " 3 "); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth(" 0 "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); // Raw SWCHA value (this will be broken down further in other UI elements) int lwidth = _font.getStringWidth("Current column "); ypos += myLineHeight + 8; new StaticTextWidget(boss, _font, xpos, ypos+2, lwidth, myFontHeight, "Current SWCHA ", TextAlign::Left); xpos += lwidth; mySWCHA = new ToggleBitWidget(boss, _nfont, xpos, ypos, 8, 1); mySWCHA->setTarget(this); mySWCHA->setEditable(false); // Current column number xpos = 10; ypos += myLineHeight + 5; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Current column ", TextAlign::Left); xpos += lwidth; myColumn = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 2, 8, Common::Base::F_16); myColumn->setTarget(this); myColumn->setEditable(false); // Relevant pins of SWCHA xpos = 30; // D6 (column part) ypos += myLineHeight + 8; myIncrease = new CheckboxWidget(boss, _font, xpos, ypos, "Increase Column"); myIncrease->setTarget(this); myIncrease->setEditable(false); int orig_ypos = ypos; // save for when we go to the next column // D5 (column part) ypos += myLineHeight + 4; myReset = new CheckboxWidget(boss, _font, xpos, ypos, "Reset Column"); myReset->setTarget(this); myReset->setEditable(false); // Row inputs ypos += myLineHeight + 4; myRow[0] = new CheckboxWidget(boss, _font, xpos, ypos, "Row 0"); myRow[0]->setTarget(this); myRow[0]->setEditable(false); ypos += myLineHeight + 4; myRow[1] = new CheckboxWidget(boss, _font, xpos, ypos, "Row 1"); myRow[1]->setTarget(this); myRow[1]->setEditable(false); ypos += myLineHeight + 4; myRow[2] = new CheckboxWidget(boss, _font, xpos, ypos, "Row 2"); myRow[2]->setTarget(this); myRow[2]->setEditable(false); ypos += myLineHeight + 4; myRow[3] = new CheckboxWidget(boss, _font, xpos, ypos, "Row 3"); myRow[3]->setTarget(this); myRow[3]->setEditable(false); // Func and Shift keys ypos += myLineHeight + 4; myFunc = new CheckboxWidget(boss, _font, xpos, ypos, "FUNC key pressed"); myFunc->setTarget(this); myFunc->setEditable(false); ypos += myLineHeight + 4; myShift = new CheckboxWidget(boss, _font, xpos, ypos, "Shift key pressed"); myShift->setTarget(this); myShift->setEditable(false); // Move to next column xpos += myShift->getWidth() + 20; ypos = orig_ypos; // D7 myAudIn = new CheckboxWidget(boss, _font, xpos, ypos, "Audio Input"); myAudIn->setTarget(this); myAudIn->setEditable(false); // D6 (audio part) ypos += myLineHeight + 4; myAudOut = new CheckboxWidget(boss, _font, xpos, ypos, "Audio Output"); myAudOut->setTarget(this); myAudOut->setEditable(false); // Ram state (combination of several bits in SWCHA) ypos += myLineHeight + 8; lwidth = _font.getStringWidth("Ram State "); new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Ram State ", TextAlign::Left); myRAM = new EditTextWidget(boss, _nfont, xpos+lwidth, ypos-2, _nfont.getStringWidth(" Write-only "), myLineHeight, ""); myRAM->setEditable(false, true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCMWidget::saveOldState() { myOldState.swcha = myCart.mySWCHA; myOldState.column = myCart.column(); myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) myOldState.internalram.push_back(myCart.myRAM[i]); myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCMWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); RiotDebug& riot = Debugger::debugger().riotDebug(); const RiotState& state = static_cast(riot.getState()); uInt8 swcha = myCart.mySWCHA; // SWCHA BoolArray oldbits, newbits, changed; Debugger::set_bits(myOldState.swcha, oldbits); Debugger::set_bits(swcha, newbits); for(uInt32 i = 0; i < oldbits.size(); ++i) changed.push_back(oldbits[i] != newbits[i]); mySWCHA->setState(newbits, changed); // Column myColumn->setList(0, myCart.column(), myCart.column() != myOldState.column); // Various bits from SWCHA and INPTx myIncrease->setState(swcha & 0x40); myReset->setState(swcha & 0x20); myRow[0]->setState(!(state.INPT4 & 0x80)); myRow[1]->setState(!(swcha & 0x04)); myRow[2]->setState(!(state.INPT5 & 0x80)); myRow[3]->setState(!(swcha & 0x08)); myFunc->setState(state.INPT0 & 0x80); myShift->setState(state.INPT3 & 0x80); // Audio in and out (used for communicating with the external cassette) myAudIn->setState(swcha & 0x80); myAudOut->setState(swcha & 0x40); // RAM state (several bits from SWCHA) const string& ram = swcha & 0x10 ? " Inactive" : swcha & 0x20 ? " Read-only" : " Write-only"; myRAM->setText(ram, (swcha & 0x30) != (myOldState.swcha & 0x30)); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCMWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.mySWCHA &= 0xFC; myCart.mySWCHA |= myBank->getSelected(); myCart.bank(myCart.mySWCHA & 0x03); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCMWidget::bankState() { ostringstream& buf = buffer(); buf << "Bank = " << std::dec << myCart.getBank() << ", RAM is" << (myCart.mySWCHA & 0x10 ? " Inactive" : myCart.mySWCHA & 0x20 ? " Read-only" : " Write-only"); return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCMWidget::internalRamSize() { return 2048; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCMWidget::internalRamRPort(int start) { return 0xF800 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCMWidget::internalRamDescription() { ostringstream desc; desc << "$F800 - $FFFF used for Exclusive Read\n" << " or Exclusive Write Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCMWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCMWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCMWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCMWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCMWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF800, false); } stella-5.1.1/src/debugger/gui/CartCMWidget.hxx000066400000000000000000000053251324334165500211620ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECM_WIDGET_HXX #define CARTRIDGECM_WIDGET_HXX class CartridgeCM; class CheckboxWidget; class DataGridWidget; class EditTextWidget; class PopUpWidget; class ToggleBitWidget; #include "CartDebugWidget.hxx" class CartridgeCMWidget : public CartDebugWidget { public: CartridgeCMWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCM& cart); virtual ~CartridgeCMWidget() = default; private: struct CartState { uInt8 swcha; uInt8 column; ByteArray internalram; uInt16 bank; }; CartridgeCM& myCart; PopUpWidget* myBank; ToggleBitWidget* mySWCHA; DataGridWidget* myColumn; CheckboxWidget *myAudIn, *myAudOut, *myIncrease, *myReset; CheckboxWidget* myRow[4]; CheckboxWidget *myFunc, *myShift; EditTextWidget* myRAM; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeCMWidget() = delete; CartridgeCMWidget(const CartridgeCMWidget&) = delete; CartridgeCMWidget(CartridgeCMWidget&&) = delete; CartridgeCMWidget& operator=(const CartridgeCMWidget&) = delete; CartridgeCMWidget& operator=(CartridgeCMWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartCTYWidget.cxx000066400000000000000000000120371324334165500213130ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartCTY.hxx" #include "PopUpWidget.hxx" #include "CartCTYWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCTYWidget::CartridgeCTYWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCTY& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 8 * 4096; string info = "Chetiry cartridge, eight 4K banks (bank 0 is ARM code and is ignored)\n" "64 bytes RAM @ $F000 - $F080\n" " $F040 - $F07F (R), $F000 - $F03F (W)\n" "\nTHIS SCHEME IS NOT FULLY IMPLEMENTED OR TESTED\n"; int xpos = 10, ypos = addBaseInformation(size, "Chris D. Walton", info) + myLineHeight; VariantList items; VarList::push_back(items, "1 ($FFF5)"); VarList::push_back(items, "2 ($FFF6)"); VarList::push_back(items, "3 ($FFF7)"); VarList::push_back(items, "4 ($FFF8)"); VarList::push_back(items, "5 ($FFF9)"); VarList::push_back(items, "6 ($FFFA)"); VarList::push_back(items, "7 ($FFFB)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTYWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTYWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank()-1, myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTYWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()+1); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCTYWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" }; uInt16 bank = myCart.getBank(); buf << "Bank = " << std::dec << bank << ", hotspot = " << spot[bank]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCTYWidget::internalRamSize() { return 64; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCTYWidget::internalRamRPort(int start) { return 0xF040 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCTYWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F03F used for Write Access\n" << "$F040 - $F07F used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCTYWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCTYWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTYWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCTYWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCTYWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF040, false); } stella-5.1.1/src/debugger/gui/CartCTYWidget.hxx000066400000000000000000000046141324334165500213220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECTY_WIDGET_HXX #define CARTRIDGECTY_WIDGET_HXX class CartridgeCTY; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeCTYWidget : public CartDebugWidget { public: CartridgeCTYWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCTY& cart); virtual ~CartridgeCTYWidget() = default; private: CartridgeCTY& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeCTYWidget() = delete; CartridgeCTYWidget(const CartridgeCTYWidget&) = delete; CartridgeCTYWidget(CartridgeCTYWidget&&) = delete; CartridgeCTYWidget& operator=(const CartridgeCTYWidget&) = delete; CartridgeCTYWidget& operator=(CartridgeCTYWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartCVPlusWidget.cxx000066400000000000000000000117001324334165500220240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartCVPlus.hxx" #include "PopUpWidget.hxx" #include "CartCVPlusWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCVPlusWidget::CartridgeCVPlusWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCVPlus& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = cart.mySize; ostringstream info; info << "LS_Dracon CV+ cartridge, 1K RAM, 2-256 2K ROM\n" << "1024 bytes RAM @ $F000 - $F7FF\n" << " $F000 - $F3FF (R), $F400 - $F7FF (W)\n" << "2048 bytes ROM @ $F800 - $FFFF, by writing to $3D\n" << "Startup bank = " << cart.myStartBank << "\n"; int xpos = 10, ypos = addBaseInformation(size, "LS_Dracon / Stephen Anthony", info.str()) + myLineHeight; VariantList items; for(uInt16 i = 0; i < cart.bankCount(); ++i) VarList::push_back(items, Variant(i).toString() + " ($3D)"); ostringstream label; label << "Set bank ($F800 - $FFFF) "; myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("xxx ($3D) "), myLineHeight, items, label.str(), _font.getStringWidth(label.str()), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCVPlusWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCVPlusWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCVPlusWidget::bankState() { ostringstream& buf = buffer(); buf << "Bank = " << std::dec << myCart.myCurrentBank << ", hotspot = $3D"; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCVPlusWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) myOldState.internalram.push_back(myCart.myRAM[i]); myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCVPlusWidget::internalRamSize() { return 1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCVPlusWidget::internalRamRPort(int start) { return 0xF000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCVPlusWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F3FF used for Read Access\n" << "$F400 - $F7FF used for Write Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCVPlusWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCVPlusWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCVPlusWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCVPlusWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCVPlusWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF000, false); } stella-5.1.1/src/debugger/gui/CartCVPlusWidget.hxx000066400000000000000000000047101324334165500220340ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECVPlus_WIDGET_HXX #define CARTRIDGECVPlus_WIDGET_HXX class CartridgeCVPlus; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeCVPlusWidget : public CartDebugWidget { public: CartridgeCVPlusWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCVPlus& cart); virtual ~CartridgeCVPlusWidget() = default; private: CartridgeCVPlus& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; void saveOldState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeCVPlusWidget() = delete; CartridgeCVPlusWidget(const CartridgeCVPlusWidget&) = delete; CartridgeCVPlusWidget(CartridgeCVPlusWidget&&) = delete; CartridgeCVPlusWidget& operator=(const CartridgeCVPlusWidget&) = delete; CartridgeCVPlusWidget& operator=(CartridgeCVPlusWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartCVWidget.cxx000066400000000000000000000071051324334165500211640ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartCV.hxx" #include "CartCVWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCVWidget::CartridgeCVWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCV& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { // Eventually, we should query this from the debugger/disassembler uInt16 size = 2048; uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % size; ostringstream info; info << "CV 2K ROM + 1K RAM , non-bankswitched\n" << "1024 bytes RAM @ $F000 - $F7FF\n" << " $F000 - $F3FF (R), $F400 - $F7FF (W)\n" << "ROM accessible @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + size - 1); addBaseInformation(cart.mySize, "CommaVid", info.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCVWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) myOldState.internalram.push_back(myCart.myRAM[i]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCVWidget::internalRamSize() { return 1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCVWidget::internalRamRPort(int start) { return 0xF000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCVWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F3FF used for Read Access\n" << "$F400 - $F7FF used for Write Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCVWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeCVWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCVWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCVWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeCVWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF000, false); } stella-5.1.1/src/debugger/gui/CartCVWidget.hxx000066400000000000000000000044531324334165500211740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECV_WIDGET_HXX #define CARTRIDGECV_WIDGET_HXX class CartridgeCV; #include "CartDebugWidget.hxx" class CartridgeCVWidget : public CartDebugWidget { public: CartridgeCVWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeCV& cart); virtual ~CartridgeCVWidget() = default; private: CartridgeCV& myCart; struct CartState { ByteArray internalram; }; CartState myOldState; private: // No implementation for non-bankswitched ROMs void loadConfig() override { } void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } void saveOldState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeCVWidget() = delete; CartridgeCVWidget(const CartridgeCVWidget&) = delete; CartridgeCVWidget(CartridgeCVWidget&&) = delete; CartridgeCVWidget& operator=(const CartridgeCVWidget&) = delete; CartridgeCVWidget& operator=(CartridgeCVWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartDASHWidget.cxx000066400000000000000000000256551324334165500214050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartDASH.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "CartDASHWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDASHWidget::CartridgeDASHWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDASH& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = cart.mySize; ostringstream info; info << "DASH cartridge - (64K ROM + RAM)\n" << " 4-64K ROM (1K banks), 32K RAM (512b banks)\n" << "Each 1K ROM selected by writing to $3F\n" "Each 512b RAM selected by writing to $3E\n" " First 512B of bank x (R)\n" " First 512B of bank x+4 (+$800) (W)\n" << "Startup bank = 0/-1/-1/0 (ROM)\n"; // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % 0x1000; info << "Bank RORG" << " = $" << Common::Base::HEX4 << start << "\n"; int xpos = 10, ypos = addBaseInformation(size, "A. Davie & T. Jentzsch", info.str()) + myLineHeight; VariantList bankno; for(uInt32 i = 0; i < myCart.ROM_BANK_COUNT; ++i) VarList::push_back(bankno, i, i); VariantList banktype; VarList::push_back(banktype, "ROM", "ROM"); VarList::push_back(banktype, "RAM", "RAM"); for(uInt32 i = 0; i < 4; ++i) { int xpos_s, ypos_s = ypos; ostringstream label; label << "Set segment " << i << " as: "; new StaticTextWidget(boss, _font, xpos, ypos, _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); ypos += myLineHeight + 8; xpos += 20; myBankNumber[i] = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("Slot "), myLineHeight, bankno, "Slot ", 6*_font.getMaxCharWidth()); addFocusWidget(myBankNumber[i]); xpos += myBankNumber[i]->getWidth(); myBankType[i] = new PopUpWidget(boss, _font, xpos, ypos-2, 5*_font.getMaxCharWidth(), myLineHeight, banktype, " of ", _font.getStringWidth(" of ")); addFocusWidget(myBankType[i]); xpos += myBankType[i]->getWidth() + 10; myBankCommit[i] = new ButtonWidget(boss, _font, xpos, ypos-4, _font.getStringWidth(" Commit "), myButtonHeight, "Commit", bankEnum[i]); myBankCommit[i]->setTarget(this); addFocusWidget(myBankCommit[i]); xpos_s = xpos + myBankCommit[i]->getWidth() + 20; StaticTextWidget* t; int addr1 = start + (i*0x400), addr2 = addr1 + 0x1FF; label.str(""); label << Common::Base::HEX4 << addr1 << "-" << Common::Base::HEX4 << addr2; t = new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); int xoffset = xpos_s+t->getWidth() + 10; myBankState[2*i] = new EditTextWidget(boss, _font, xoffset, ypos_s, w - xoffset - 10, myLineHeight, ""); myBankState[2*i]->setEditable(false, true); ypos_s += myLineHeight + 4; label.str(""); label << Common::Base::HEX4 << (addr2 + 1) << "-" << Common::Base::HEX4 << (addr2 + 1 + 0x1FF); new StaticTextWidget(boss, _font, xpos_s, ypos_s+2, _font.getStringWidth(label.str()), myFontHeight, label.str(), TextAlign::Left); myBankState[2*i+1] = new EditTextWidget(boss, _font, xoffset, ypos_s, w - xoffset - 10, myLineHeight, ""); myBankState[2*i+1]->setEditable(false, true); xpos = 10; ypos+= 2 * myLineHeight; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASHWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) myOldState.internalram.push_back(myCart.myRAM[i]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASHWidget::loadConfig() { updateUIState(); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASHWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { uInt16 segment = 0; switch(cmd) { case kBank0Changed: segment = 0; break; case kBank1Changed: segment = 1; break; case kBank2Changed: segment = 2; break; case kBank3Changed: segment = 3; break; } // Ignore bank if either number or type hasn't been selected if(myBankNumber[segment]->getSelected() < 0 || myBankType[segment]->getSelected() < 0) return; uInt8 bank = (segment << myCart.BANK_BITS) | (myBankNumber[segment]->getSelected() & myCart.BIT_BANK_MASK); myCart.unlockBank(); if(myBankType[segment]->getSelectedTag() == "ROM") myCart.bankROM(bank); else myCart.bankRAM(bank); myCart.lockBank(); invalidate(); updateUIState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDASHWidget::bankState() { ostringstream& buf = buffer(); int lastROMBank = -1; bool lastSlotRAM = false; for(int i = 0; i < 8; ++i) { uInt16 bank = myCart.bankInUse[i]; if(bank == myCart.BANK_UNDEFINED) // never accessed { buf << " U!"; } else { int bankno = bank & myCart.BIT_BANK_MASK; if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? { // RAM will always need a '+' placed somewhere, since it always // consists of 512B segments bool inFirstSlot = (i % 2 == 0); if(!(inFirstSlot || lastSlotRAM)) { lastSlotRAM = false; buf << " +"; } if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port buf << " RAM " << bankno << "W"; else buf << " RAM " << bankno << "R"; if(inFirstSlot) { buf << " +"; lastSlotRAM = true; } } else { // ROM can be contiguous, since 2 512B segments can form a single // 1K bank; in this case we only show the info once bool highBankSame = (i % 2 == 1) && (bankno == lastROMBank); if(!highBankSame) { buf << " ROM " << bankno; lastROMBank = bankno; } else lastROMBank = -1; lastSlotRAM = false; } } if((i+1) % 2 == 0 && i < 7) buf << " /"; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASHWidget::updateUIState() { // Set contents for actual banks number and type for(int i = 0; i < 4; ++i) { uInt16 segment = myCart.segmentInUse[i]; if(segment == myCart.BANK_UNDEFINED) { myBankNumber[i]->clearSelection(); myBankType[i]->clearSelection(); } else { int bankno = segment & myCart.BIT_BANK_MASK; const string& banktype = segment & myCart.BITMASK_ROMRAM ? "RAM" : "ROM"; myBankNumber[i]->setSelected(bankno); myBankType[i]->setSelected(banktype); } } // Set description for each 512b bank state for(int i = 0; i < 8; ++i) { uInt16 bank = myCart.bankInUse[i]; if(bank == myCart.BANK_UNDEFINED) // never accessed { myBankState[i]->setText("Undefined"); } else { ostringstream buf; int bankno = bank & myCart.BIT_BANK_MASK; if(bank & myCart.BITMASK_ROMRAM) // was RAM mapped here? { if(bank & myCart.BITMASK_LOWERUPPER) // upper is write port { buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 << (bankno << myCart.RAM_BANK_TO_POWER) << " (W)"; myBankState[i]->setText(buf.str()); } else { buf << "RAM " << bankno << " @ $" << Common::Base::HEX4 << (bankno << myCart.RAM_BANK_TO_POWER) << " (R)"; myBankState[i]->setText(buf.str()); } } else { if(bank & myCart.BITMASK_LOWERUPPER) // upper is high 512b { buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 << ((bankno << myCart.RAM_BANK_TO_POWER) + myCart.RAM_BANK_SIZE); myBankState[i]->setText(buf.str()); } else { buf << "ROM " << bankno << " @ $" << Common::Base::HEX4 << (bankno << myCart.RAM_BANK_TO_POWER); myBankState[i]->setText(buf.str()); } } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeDASHWidget::internalRamSize() { return 32*1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeDASHWidget::internalRamRPort(int start) { return 0x0000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDASHWidget::internalRamDescription() { ostringstream desc; desc << "Accessible 512b at a time via:\n" << " $F000/$F200/$F400/etc used for Read Access\n" << " $F800/$FA00/$FC00/etc used for Write Access (+$800)"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeDASHWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeDASHWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASHWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDASHWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const CartridgeDASHWidget::BankID CartridgeDASHWidget::bankEnum[4] = { kBank0Changed, kBank1Changed, kBank2Changed, kBank3Changed }; stella-5.1.1/src/debugger/gui/CartDASHWidget.hxx000066400000000000000000000052571324334165500214060ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEDASH_WIDGET_HXX #define CARTRIDGEDASH_WIDGET_HXX class CartridgeDASH; class ButtonWidget; class EditTextWidget; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeDASHWidget : public CartDebugWidget { public: CartridgeDASHWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDASH& cart); virtual ~CartridgeDASHWidget() = default; private: void updateUIState(); private: CartridgeDASH& myCart; PopUpWidget* myBankNumber[4]; PopUpWidget* myBankType[4]; ButtonWidget* myBankCommit[4]; EditTextWidget* myBankState[8]; struct CartState { ByteArray internalram; }; CartState myOldState; enum BankID { kBank0Changed = 'b0CH', kBank1Changed = 'b1CH', kBank2Changed = 'b2CH', kBank3Changed = 'b3CH' }; static const BankID bankEnum[4]; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeDASHWidget() = delete; CartridgeDASHWidget(const CartridgeDASHWidget&) = delete; CartridgeDASHWidget(CartridgeDASHWidget&&) = delete; CartridgeDASHWidget& operator=(const CartridgeDASHWidget&) = delete; CartridgeDASHWidget& operator=(CartridgeDASHWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartDFSCWidget.cxx000066400000000000000000000153571324334165500214030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartDFSC.hxx" #include "PopUpWidget.hxx" #include "CartDFSCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDFSCWidget::CartridgeDFSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDFSC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 32 * 4096; ostringstream info; info << "128K DFSC + RAM, 32 4K banks\n" << "128 bytes RAM @ $F000 - $F0FF\n" << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" << "Startup bank = " << cart.myStartBank << "\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFC0; i < 32; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, " 0 ($FFC0)"); VarList::push_back(items, " 1 ($FFC1)"); VarList::push_back(items, " 2 ($FFC2)"); VarList::push_back(items, " 3 ($FFC3)"); VarList::push_back(items, " 4 ($FFC4)"); VarList::push_back(items, " 5 ($FFC5)"); VarList::push_back(items, " 6 ($FFC6)"); VarList::push_back(items, " 7 ($FFC7)"); VarList::push_back(items, " 8 ($FFC8)"); VarList::push_back(items, " 9 ($FFC9)"); VarList::push_back(items, "10 ($FFCA)"); VarList::push_back(items, "11 ($FFCB)"); VarList::push_back(items, "12 ($FFCC)"); VarList::push_back(items, "13 ($FFCD)"); VarList::push_back(items, "14 ($FFCE)"); VarList::push_back(items, "15 ($FFCF)"); VarList::push_back(items, "16 ($FFD0)"); VarList::push_back(items, "17 ($FFD1)"); VarList::push_back(items, "18 ($FFD2)"); VarList::push_back(items, "19 ($FFD3)"); VarList::push_back(items, "20 ($FFD4)"); VarList::push_back(items, "21 ($FFD5)"); VarList::push_back(items, "22 ($FFD6)"); VarList::push_back(items, "23 ($FFD7)"); VarList::push_back(items, "24 ($FFD8)"); VarList::push_back(items, "25 ($FFD9)"); VarList::push_back(items, "26 ($FFDA)"); VarList::push_back(items, "27 ($FFDB)"); VarList::push_back(items, "28 ($FFDC)"); VarList::push_back(items, "29 ($FFDD)"); VarList::push_back(items, "30 ($FFDE)"); VarList::push_back(items, "31 ($FFDF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("31 ($FFE0) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSCWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSCWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSCWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDFSCWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFC0", "$FFC1", "$FFC2", "$FFC3", "$FFC4", "$FFC5", "$FFC6", "$FFC7", "$FFC8", "$FFC9", "$FFCA", "$FFCB", "$FFCC", "$FFCD", "$FFCE", "$FFCF", "$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFE7", "$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeDFSCWidget::internalRamSize() { return 128; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeDFSCWidget::internalRamRPort(int start) { return 0xF080 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDFSCWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F07F used for Write Access\n" << "$F080 - $F0FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeDFSCWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeDFSCWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSCWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDFSCWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDFSCWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF080, false); } stella-5.1.1/src/debugger/gui/CartDFSCWidget.hxx000066400000000000000000000046401324334165500214010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEDFSC_WIDGET_HXX #define CARTRIDGEDFSC_WIDGET_HXX class CartridgeDFSC; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeDFSCWidget : public CartDebugWidget { public: CartridgeDFSCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDFSC& cart); virtual ~CartridgeDFSCWidget() = default; private: CartridgeDFSC& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeDFSCWidget() = delete; CartridgeDFSCWidget(const CartridgeDFSCWidget&) = delete; CartridgeDFSCWidget(CartridgeDFSCWidget&&) = delete; CartridgeDFSCWidget& operator=(const CartridgeDFSCWidget&) = delete; CartridgeDFSCWidget& operator=(CartridgeDFSCWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartDFWidget.cxx000066400000000000000000000114051324334165500211430ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartDF.hxx" #include "PopUpWidget.hxx" #include "CartDFWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDFWidget::CartridgeDFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDF& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 32 * 4096; ostringstream info; info << "EF 2 cartridge, 32 4K banks\n" << "Startup bank = " << cart.myStartBank << "\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFD0; i < 32; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CPUWIZ", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, " 0 ($FFC0)"); VarList::push_back(items, " 1 ($FFC1)"); VarList::push_back(items, " 2 ($FFC2)"); VarList::push_back(items, " 3 ($FFC3)"); VarList::push_back(items, " 4 ($FFC4)"); VarList::push_back(items, " 5 ($FFC5)"); VarList::push_back(items, " 6 ($FFC6)"); VarList::push_back(items, " 7 ($FFC7)"); VarList::push_back(items, " 8 ($FFC8)"); VarList::push_back(items, " 9 ($FFC9)"); VarList::push_back(items, "10 ($FFCA)"); VarList::push_back(items, "11 ($FFCB)"); VarList::push_back(items, "12 ($FFCC)"); VarList::push_back(items, "13 ($FFCD)"); VarList::push_back(items, "14 ($FFCE)"); VarList::push_back(items, "15 ($FFCF)"); VarList::push_back(items, "16 ($FFD0)"); VarList::push_back(items, "17 ($FFD1)"); VarList::push_back(items, "18 ($FFD2)"); VarList::push_back(items, "19 ($FFD3)"); VarList::push_back(items, "20 ($FFD4)"); VarList::push_back(items, "21 ($FFD5)"); VarList::push_back(items, "22 ($FFD6)"); VarList::push_back(items, "23 ($FFD7)"); VarList::push_back(items, "24 ($FFD8)"); VarList::push_back(items, "25 ($FFD9)"); VarList::push_back(items, "26 ($FFDA)"); VarList::push_back(items, "27 ($FFDB)"); VarList::push_back(items, "28 ($FFDC)"); VarList::push_back(items, "29 ($FFDD)"); VarList::push_back(items, "30 ($FFDE)"); VarList::push_back(items, "31 ($FFDF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("31 ($FFDF) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDFWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFC0", "$FFC1", "$FFC2", "$FFC3", "$FFC4", "$FFC5", "$FFC6", "$FFC7", "$FFC8", "$FFC9", "$FFCA", "$FFCB", "$FFCC", "$FFCD", "$FFCE", "$FFCF", "$FFD0", "$FFD1", "$FFD2", "$FFD3", "$FFD4", "$FFD5", "$FFD6", "$FFD7", "$FFD8", "$FFD9", "$FFDA", "$FFDB", "$FFDC", "$FFDD", "$FFDE", "$FFDF" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartDFWidget.hxx000066400000000000000000000033341324334165500211520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEDF_WIDGET_HXX #define CARTRIDGEDF_WIDGET_HXX class CartridgeDF; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeDFWidget : public CartDebugWidget { public: CartridgeDFWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDF& cart); virtual ~CartridgeDFWidget() = default; private: CartridgeDF& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeDFWidget() = delete; CartridgeDFWidget(const CartridgeDFWidget&) = delete; CartridgeDFWidget(CartridgeDFWidget&&) = delete; CartridgeDFWidget& operator=(const CartridgeDFWidget&) = delete; CartridgeDFWidget& operator=(CartridgeDFWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartDPCPlusWidget.cxx000066400000000000000000000326631324334165500221350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartDPCPlus.hxx" #include "DataGridWidget.hxx" #include "PopUpWidget.hxx" #include "CartDPCPlusWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPCPlusWidget::CartridgeDPCPlusWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDPCPlus& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = cart.mySize; ostringstream info; info << "Extended DPC cartridge, six 4K banks, 4K display bank, 1K frequency table, " << "8K DPC RAM\n" << "DPC registers accessible @ $F000 - $F07F\n" << " $F000 - $F03F (R), $F040 - $F07F (W)\n" << "Banks accessible at hotspots $FFF6 to $FFFB\n" << "Startup bank = " << cart.myStartBank << "\n"; #if 0 // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF6; i < 6; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << HEX4 << (start + 0x80) << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << (spot+i) << ")\n"; } #endif int xpos = 10, ypos = addBaseInformation(size, "Activision (Pitfall II)", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF6)"); VarList::push_back(items, "1 ($FFF7)"); VarList::push_back(items, "2 ($FFF8)"); VarList::push_back(items, "3 ($FFF9)"); VarList::push_back(items, "4 ($FFFA)"); VarList::push_back(items, "5 ($FFFB)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); // Top registers int lwidth = _font.getStringWidth("Counter Registers "); xpos = 10; ypos += myLineHeight + 8; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Top Registers ", TextAlign::Left); xpos += lwidth; myTops = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16); myTops->setTarget(this); myTops->setEditable(false); // Bottom registers xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Bottom Registers ", TextAlign::Left); xpos += lwidth; myBottoms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16); myBottoms->setTarget(this); myBottoms->setEditable(false); // Counter registers xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Counter Registers ", TextAlign::Left); xpos += lwidth; myCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 4, 16, Common::Base::F_16_4); myCounters->setTarget(this); myCounters->setEditable(false); // Fractional counter registers xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Frac Counters ", TextAlign::Left); xpos += lwidth; myFracCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 4, 2, 8, 32, Common::Base::F_16_8); myFracCounters->setTarget(this); myFracCounters->setEditable(false); // Fractional increment registers xpos = 10; ypos += myFracCounters->getHeight() + 8; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Frac Increments ", TextAlign::Left); xpos += lwidth; myFracIncrements = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16); myFracIncrements->setTarget(this); myFracIncrements->setEditable(false); // Special function parameters xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Function Params ", TextAlign::Left); xpos += lwidth; myParameter = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16); myParameter->setTarget(this); myParameter->setEditable(false); // Music counters xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Counters ", TextAlign::Left); xpos += lwidth; myMusicCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8); myMusicCounters->setTarget(this); myMusicCounters->setEditable(false); // Music frequencies xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Frequencies ", TextAlign::Left); xpos += lwidth; myMusicFrequencies = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 8, 32, Common::Base::F_16_8); myMusicFrequencies->setTarget(this); myMusicFrequencies->setEditable(false); // Music waveforms xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music Waveforms ", TextAlign::Left); xpos += lwidth; myMusicWaveforms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 4, 16, Common::Base::F_16_4); myMusicWaveforms->setTarget(this); myMusicWaveforms->setEditable(false); // Current random number lwidth = _font.getStringWidth("Current random number "); xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Current random number ", TextAlign::Left); xpos += lwidth; myRandom = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 8, 32, Common::Base::F_16_8); myRandom->setTarget(this); myRandom->setEditable(false); // Fast fetch and immediate mode LDA flags xpos += myRandom->getWidth() + 30; myFastFetch = new CheckboxWidget(boss, _font, xpos, ypos, "Fast Fetcher enabled"); myFastFetch->setTarget(this); myFastFetch->setEditable(false); ypos += myLineHeight + 4; myIMLDA = new CheckboxWidget(boss, _font, xpos, ypos, "Immediate mode LDA"); myIMLDA->setTarget(this); myIMLDA->setEditable(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlusWidget::saveOldState() { myOldState.tops.clear(); myOldState.bottoms.clear(); myOldState.counters.clear(); myOldState.fraccounters.clear(); myOldState.fracinc.clear(); myOldState.param.clear(); myOldState.mcounters.clear(); myOldState.mfreqs.clear(); myOldState.mwaves.clear(); myOldState.internalram.clear(); for(uInt32 i = 0; i < 8; ++i) { myOldState.tops.push_back(myCart.myTops[i]); myOldState.bottoms.push_back(myCart.myBottoms[i]); myOldState.counters.push_back(myCart.myCounters[i]); myOldState.fraccounters.push_back(myCart.myFractionalCounters[i]); myOldState.fracinc.push_back(myCart.myFractionalIncrements[i]); myOldState.param.push_back(myCart.myParameter[i]); } for(uInt32 i = 0; i < 3; ++i) { myOldState.mcounters.push_back(myCart.myMusicCounters[i]); myOldState.mfreqs.push_back(myCart.myMusicFrequencies[i]); myOldState.mwaves.push_back(myCart.myMusicWaveforms[i]); } myOldState.random = myCart.myRandomNumber; for(uInt32 i = 0; i < internalRamSize(); ++i) myOldState.internalram.push_back(myCart.myDisplayImage[i]); myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlusWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); // Get registers, using change tracking IntArray alist; IntArray vlist; BoolArray changed; alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myTops[i]); changed.push_back(myCart.myTops[i] != myOldState.tops[i]); } myTops->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myBottoms[i]); changed.push_back(myCart.myBottoms[i] != myOldState.bottoms[i]); } myBottoms->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myCounters[i]); changed.push_back(myCart.myCounters[i] != myOldState.counters[i]); } myCounters->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myFractionalCounters[i]); changed.push_back(myCart.myFractionalCounters[i] != uInt32(myOldState.fraccounters[i])); } myFracCounters->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myFractionalIncrements[i]); changed.push_back(myCart.myFractionalIncrements[i] != myOldState.fracinc[i]); } myFracIncrements->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myParameter[i]); changed.push_back(myCart.myParameter[i] != myOldState.param[i]); } myParameter->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.myMusicCounters[i]); changed.push_back(myCart.myMusicCounters[i] != uInt32(myOldState.mcounters[i])); } myMusicCounters->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.myMusicFrequencies[i]); changed.push_back(myCart.myMusicFrequencies[i] != uInt32(myOldState.mfreqs[i])); } myMusicFrequencies->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.myMusicWaveforms[i]); changed.push_back(myCart.myMusicWaveforms[i] != myOldState.mwaves[i]); } myMusicWaveforms->setList(alist, vlist, changed); myRandom->setList(0, myCart.myRandomNumber, myCart.myRandomNumber != myOldState.random); myFastFetch->setState(myCart.myFastFetch); myIMLDA->setState(myCart.myLDAimmediate); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlusWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDPCPlusWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeDPCPlusWidget::internalRamSize() { return 5*1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeDPCPlusWidget::internalRamRPort(int start) { return 0x0000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDPCPlusWidget::internalRamDescription() { ostringstream desc; desc << "$0000 - $0FFF - 4K display data\n" << " indirectly accessible to 6507\n" << " via DPC+'s Data Fetcher registers\n" << "$1000 - $13FF - 1K frequency table,\n" << " C variables and C stack\n" << " not accessible to 6507"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeDPCPlusWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeDPCPlusWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myDisplayImage[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlusWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myDisplayImage[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDPCPlusWidget::internalRamGetValue(int addr) { return myCart.myDisplayImage[addr]; } stella-5.1.1/src/debugger/gui/CartDPCPlusWidget.hxx000066400000000000000000000061421324334165500221330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEDPCPLUS_WIDGET_HXX #define CARTRIDGEDPCPLUS_WIDGET_HXX class CartridgeDPCPlus; class PopUpWidget; class CheckboxWidget; class DataGridWidget; #include "CartDebugWidget.hxx" class CartridgeDPCPlusWidget : public CartDebugWidget { public: CartridgeDPCPlusWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDPCPlus& cart); virtual ~CartridgeDPCPlusWidget() = default; private: struct CartState { ByteArray tops; ByteArray bottoms; IntArray counters; IntArray fraccounters; ByteArray fracinc; ByteArray param; IntArray mcounters; IntArray mfreqs; IntArray mwaves; uInt32 random; ByteArray internalram; uInt16 bank; }; CartridgeDPCPlus& myCart; PopUpWidget* myBank; DataGridWidget* myTops; DataGridWidget* myBottoms; DataGridWidget* myCounters; DataGridWidget* myFracCounters; DataGridWidget* myFracIncrements; DataGridWidget* myParameter; DataGridWidget* myMusicCounters; DataGridWidget* myMusicFrequencies; DataGridWidget* myMusicWaveforms; CheckboxWidget* myFastFetch; CheckboxWidget* myIMLDA; DataGridWidget* myRandom; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeDPCPlusWidget() = delete; CartridgeDPCPlusWidget(const CartridgeDPCPlusWidget&) = delete; CartridgeDPCPlusWidget(CartridgeDPCPlusWidget&&) = delete; CartridgeDPCPlusWidget& operator=(const CartridgeDPCPlusWidget&) = delete; CartridgeDPCPlusWidget& operator=(CartridgeDPCPlusWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartDPCWidget.cxx000066400000000000000000000227631324334165500212710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartDPC.hxx" #include "DataGridWidget.hxx" #include "PopUpWidget.hxx" #include "CartDPCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPCWidget::CartridgeDPCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDPC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = cart.mySize; ostringstream info; info << "DPC cartridge, two 4K banks + 2K display bank\n" << "DPC registers accessible @ $F000 - $F07F\n" << " $F000 - $F03F (R), $F040 - $F07F (W)\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 2; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x80) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Activision (Pitfall II)", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF8)"); VarList::push_back(items, "1 ($FFF9)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); ypos += myLineHeight + 8; // Data fetchers int lwidth = _font.getStringWidth("Data Fetchers "); new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Data Fetchers ", TextAlign::Left); // Top registers lwidth = _font.getStringWidth("Counter Registers "); xpos = 18; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Top Registers ", TextAlign::Left); xpos += lwidth; myTops = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16); myTops->setTarget(this); myTops->setEditable(false); // Bottom registers xpos = 18; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Bottom Registers ", TextAlign::Left); xpos += lwidth; myBottoms = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16); myBottoms->setTarget(this); myBottoms->setEditable(false); // Counter registers xpos = 18; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Counter Registers ", TextAlign::Left); xpos += lwidth; myCounters = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 4, 16, Common::Base::F_16_4); myCounters->setTarget(this); myCounters->setEditable(false); // Flag registers xpos = 18; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Flag Registers ", TextAlign::Left); xpos += lwidth; myFlags = new DataGridWidget(boss, _nfont, xpos, ypos-2, 8, 1, 2, 8, Common::Base::F_16); myFlags->setTarget(this); myFlags->setEditable(false); // Music mode xpos = 10; ypos += myLineHeight + 12; lwidth = _font.getStringWidth("Music mode (DF5/DF6/DF7) "); new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Music mode (DF5/DF6/DF7) ", TextAlign::Left); xpos += lwidth; myMusicMode = new DataGridWidget(boss, _nfont, xpos, ypos-2, 3, 1, 2, 8, Common::Base::F_16); myMusicMode->setTarget(this); myMusicMode->setEditable(false); // Current random number xpos = 10; ypos += myLineHeight + 4; new StaticTextWidget(boss, _font, xpos, ypos, lwidth, myFontHeight, "Current random number ", TextAlign::Left); xpos += lwidth; myRandom = new DataGridWidget(boss, _nfont, xpos, ypos-2, 1, 1, 2, 8, Common::Base::F_16); myRandom->setTarget(this); myRandom->setEditable(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCWidget::saveOldState() { myOldState.tops.clear(); myOldState.bottoms.clear(); myOldState.counters.clear(); myOldState.flags.clear(); myOldState.music.clear(); for(uInt32 i = 0; i < 8; ++i) { myOldState.tops.push_back(myCart.myTops[i]); myOldState.bottoms.push_back(myCart.myBottoms[i]); myOldState.counters.push_back(myCart.myCounters[i]); myOldState.flags.push_back(myCart.myFlags[i]); } for(uInt32 i = 0; i < 3; ++i) myOldState.music.push_back(myCart.myMusicMode[i]); myOldState.random = myCart.myRandomNumber; for(uInt32 i = 0; i < internalRamSize(); ++i) myOldState.internalram.push_back(myCart.myDisplayImage[i]); myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); // Get registers, using change tracking IntArray alist; IntArray vlist; BoolArray changed; alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myTops[i]); changed.push_back(myCart.myTops[i] != myOldState.tops[i]); } myTops->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myBottoms[i]); changed.push_back(myCart.myBottoms[i] != myOldState.bottoms[i]); } myBottoms->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myCounters[i]); changed.push_back(myCart.myCounters[i] != myOldState.counters[i]); } myCounters->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 8; ++i) { alist.push_back(0); vlist.push_back(myCart.myFlags[i]); changed.push_back(myCart.myFlags[i] != myOldState.flags[i]); } myFlags->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); for(int i = 0; i < 3; ++i) { alist.push_back(0); vlist.push_back(myCart.myMusicMode[i]); changed.push_back(myCart.myMusicMode[i] != myOldState.music[i]); } myMusicMode->setList(alist, vlist, changed); myRandom->setList(0, myCart.myRandomNumber, myCart.myRandomNumber != myOldState.random); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDPCWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF8", "$FFF9" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeDPCWidget::internalRamSize() { return 2*1024; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeDPCWidget::internalRamRPort(int start) { return 0x0000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeDPCWidget::internalRamDescription() { ostringstream desc; desc << "$0000 - $07FF - 2K display data\n" << " indirectly accessible to 6507\n" << " via DPC+'s Data Fetcher\n" << " registers\n"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeDPCWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeDPCWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myDisplayImage[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myDisplayImage[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDPCWidget::internalRamGetValue(int addr) { return myCart.myDisplayImage[addr]; } stella-5.1.1/src/debugger/gui/CartDPCWidget.hxx000066400000000000000000000052661324334165500212750ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEDPC_WIDGET_HXX #define CARTRIDGEDPC_WIDGET_HXX class CartridgeDPC; class PopUpWidget; class DataGridWidget; #include "CartDebugWidget.hxx" class CartridgeDPCWidget : public CartDebugWidget { public: CartridgeDPCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeDPC& cart); virtual ~CartridgeDPCWidget() = default; private: struct CartState { ByteArray tops; ByteArray bottoms; IntArray counters; ByteArray flags; BoolArray music; uInt8 random; ByteArray internalram; uInt16 bank; }; CartridgeDPC& myCart; PopUpWidget* myBank; DataGridWidget* myTops; DataGridWidget* myBottoms; DataGridWidget* myCounters; DataGridWidget* myFlags; DataGridWidget* myMusicMode; DataGridWidget* myRandom; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeDPCWidget() = delete; CartridgeDPCWidget(const CartridgeDPCWidget&) = delete; CartridgeDPCWidget(CartridgeDPCWidget&&) = delete; CartridgeDPCWidget& operator=(const CartridgeDPCWidget&) = delete; CartridgeDPCWidget& operator=(CartridgeDPCWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartDebugWidget.cxx000066400000000000000000000064321324334165500217040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Font.hxx" #include "RomWidget.hxx" #include "EditTextWidget.hxx" #include "StringListWidget.hxx" #include "ScrollBarWidget.hxx" #include "StringParser.hxx" #include "CartDebugWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartDebugWidget::CartDebugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) : Widget(boss, lfont, x, y, w, h), CommandSender(boss), _nfont(nfont), myFontWidth(lfont.getMaxCharWidth()), myFontHeight(lfont.getFontHeight()), myLineHeight(lfont.getLineHeight()), myButtonHeight(myLineHeight + 4), myDesc(nullptr) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int CartDebugWidget::addBaseInformation(int bytes, const string& manufacturer, const string& desc, const uInt16 maxlines) { const int lwidth = _font.getStringWidth("Manufacturer "), fwidth = _w - lwidth - 20; EditTextWidget* w = nullptr; ostringstream buf; int x = 10, y = 10; // Add ROM size, manufacturer and bankswitch info new StaticTextWidget(_boss, _font, x, y, lwidth, myFontHeight, "ROM Size ", TextAlign::Left); buf << bytes << " bytes"; if(bytes >= 1024) buf << " / " << (bytes/1024) << "KB"; w = new EditTextWidget(_boss, _nfont, x+lwidth, y, fwidth, myLineHeight, buf.str()); w->setEditable(false); y += myLineHeight + 4; new StaticTextWidget(_boss, _font, x, y, lwidth, myFontHeight, "Manufacturer ", TextAlign::Left); w = new EditTextWidget(_boss, _nfont, x+lwidth, y, fwidth, myLineHeight, manufacturer); w->setEditable(false); y += myLineHeight + 4; StringParser bs(desc, (fwidth - kScrollBarWidth) / myFontWidth - 4); const StringList& sl = bs.stringList(); uInt32 lines = uInt32(sl.size()); if(lines < 3) lines = 3; if(lines > maxlines) lines = maxlines; new StaticTextWidget(_boss, _font, x, y, lwidth, myFontHeight, "Description ", TextAlign::Left); myDesc = new StringListWidget(_boss, _nfont, x+lwidth, y, fwidth, lines * myLineHeight, false); myDesc->setEditable(false); myDesc->setList(sl); addFocusWidget(myDesc); y += myDesc->getHeight() + 4; return y; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebugWidget::invalidate() { sendCommand(RomWidget::kInvalidateListing, -1, -1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartDebugWidget::loadConfig() { myDesc->setSelected(0); } stella-5.1.1/src/debugger/gui/CartDebugWidget.hxx000066400000000000000000000067601324334165500217150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CART_DEBUG_WIDGET_HXX #define CART_DEBUG_WIDGET_HXX class GuiObject; class ButtonWidget; class StringListWidget; namespace GUI { class Font; } #include "Base.hxx" // not needed here, but all child classes need it #include "Command.hxx" #include "Widget.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" class CartDebugWidget : public Widget, public CommandSender { public: CartDebugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h); virtual ~CartDebugWidget() = default; public: int addBaseInformation(int bytes, const string& manufacturer, const string& desc, const uInt16 maxlines = 10); // Inform the ROM Widget that the underlying cart has somehow changed void invalidate(); // Some carts need to save old state in the debugger, so that we can // implement change tracking; most carts probably won't do anything here virtual void saveOldState() { } virtual void loadConfig() override; virtual void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } // Query internal state of the cart (usually just bankswitching info) virtual string bankState() { return "0 (non-bankswitched)"; } // To make the Cartridge RAM show up in the debugger, implement // the following 8 functions for cartridges with internal RAM virtual uInt32 internalRamSize() { return 0; } virtual uInt32 internalRamRPort(int start) { return 0; } virtual string internalRamDescription() { return EmptyString; } virtual const ByteArray& internalRamOld(int start, int count) { return myRamOld; } virtual const ByteArray& internalRamCurrent(int start, int count) { return myRamCurrent; } virtual void internalRamSetValue(int addr, uInt8 value) { } virtual uInt8 internalRamGetValue(int addr) { return 0; } virtual string internalRamLabel(int addr) { return "Not available/applicable"; } protected: // Arrays used to hold current and previous internal RAM values ByteArray myRamOld, myRamCurrent; // Font used for 'normal' text; _font is for 'label' text const GUI::Font& _nfont; // These will be needed by most of the child classes; // we may as well make them protected variables int myFontWidth, myFontHeight, myLineHeight, myButtonHeight; ostringstream& buffer() { myBuffer.str(""); return myBuffer; } private: StringListWidget* myDesc; ostringstream myBuffer; private: // Following constructors and assignment operators not supported CartDebugWidget() = delete; CartDebugWidget(const CartDebugWidget&) = delete; CartDebugWidget(CartDebugWidget&&) = delete; CartDebugWidget& operator=(const CartDebugWidget&) = delete; CartDebugWidget& operator=(CartDebugWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartE0Widget.cxx000066400000000000000000000111231324334165500211130ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartE0.hxx" #include "PopUpWidget.hxx" #include "CartE0Widget.hxx" static const char* const seg0[] = { "0 ($FFE0)", "1 ($FFE1)", "2 ($FFE2)", "3 ($FFE3)", "4 ($FFE4)", "5 ($FFE5)", "6 ($FFE6)", "7 ($FFE7)" }; static const char* const seg1[] = { "0 ($FFE8)", "1 ($FFE9)", "2 ($FFEA)", "3 ($FFEB)", "4 ($FFEC)", "5 ($FFED)", "6 ($FFEE)", "7 ($FFEF)" }; static const char* const seg2[] = { "0 ($FFF0)", "1 ($FFF1)", "2 ($FFF2)", "3 ($FFF3)", "4 ($FFF4)", "5 ($FFF5)", "6 ($FFF6)", "7 ($FFF7)" }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE0Widget::CartridgeE0Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeE0& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 8 * 1024; string info = "E0 cartridge, eight 1K slices\n" "Segment 0 accessible @ $F000 - $F3FF\n" " Hotspots $FE0 to $FE7\n" "Segment 1 accessible @ $F400 - $F7FF\n" " Hotspots $FE8 to $FEF\n" "Segment 2 accessible @ $F800 - $FBFF\n" " Hotspots $FF0 to $FF7\n" "Segment 3 accessible @ $FC00 - $FFFF\n" " Always points to last 1K of ROM\n" "Startup slices = 4 / 5 / 6 or undetermined\n"; #if 0 // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % 0x1000; info << "Bank RORG" << " = $" << HEX4 << start << "\n"; #endif int xpos = 10, ypos = addBaseInformation(size, "Parker Brothers", info) + myLineHeight; VariantList items0, items1, items2; for(int i = 0; i < 8; ++i) { VarList::push_back(items0, seg0[i]); VarList::push_back(items1, seg1[i]); VarList::push_back(items2, seg2[i]); } const int lwidth = _font.getStringWidth("Set slice for segment X "); mySlice0 = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("7 ($FFF7)"), myLineHeight, items0, "Set slice for segment 0 ", lwidth, kSlice0Changed); mySlice0->setTarget(this); addFocusWidget(mySlice0); ypos += mySlice0->getHeight() + 4; mySlice1 = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("7 ($FFF7)"), myLineHeight, items1, "Set slice for segment 1 ", lwidth, kSlice1Changed); mySlice1->setTarget(this); addFocusWidget(mySlice1); ypos += mySlice1->getHeight() + 4; mySlice2 = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("7 ($FFF7)"), myLineHeight, items2, "Set slice for segment 2 ", lwidth, kSlice2Changed); mySlice2->setTarget(this); addFocusWidget(mySlice2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0Widget::loadConfig() { mySlice0->setSelectedIndex(myCart.myCurrentSlice[0]); mySlice1->setSelectedIndex(myCart.myCurrentSlice[1]); mySlice2->setSelectedIndex(myCart.myCurrentSlice[2]); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { myCart.unlockBank(); switch(cmd) { case kSlice0Changed: myCart.segmentZero(mySlice0->getSelected()); break; case kSlice1Changed: myCart.segmentOne(mySlice1->getSelected()); break; case kSlice2Changed: myCart.segmentTwo(mySlice2->getSelected()); break; } myCart.lockBank(); invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeE0Widget::bankState() { ostringstream& buf = buffer(); buf << "Slices: " << std::dec << seg0[myCart.myCurrentSlice[0]] << " / " << seg1[myCart.myCurrentSlice[1]] << " / " << seg2[myCart.myCurrentSlice[2]]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartE0Widget.hxx000066400000000000000000000034761324334165500211340ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEE0_WIDGET_HXX #define CARTRIDGEE0_WIDGET_HXX class CartridgeE0; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeE0Widget : public CartDebugWidget { public: CartridgeE0Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeE0& cart); virtual ~CartridgeE0Widget() = default; private: CartridgeE0& myCart; PopUpWidget *mySlice0, *mySlice1, *mySlice2; enum { kSlice0Changed = 's0CH', kSlice1Changed = 's1CH', kSlice2Changed = 's2CH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeE0Widget() = delete; CartridgeE0Widget(const CartridgeE0Widget&) = delete; CartridgeE0Widget(CartridgeE0Widget&&) = delete; CartridgeE0Widget& operator=(const CartridgeE0Widget&) = delete; CartridgeE0Widget& operator=(CartridgeE0Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartE78KWidget.cxx000066400000000000000000000050301324334165500213250ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartMNetwork.hxx" #include "PopUpWidget.hxx" #include "CartE78KWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE78KWidget::CartridgeE78KWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMNetwork& cart) : CartridgeMNetworkWidget(boss, lfont, nfont, x, y, w, h, cart) { ostringstream info; info << "E78K cartridge, 4 2K slices ROM + 2 1K RAM\n" << "Lower 2K accessible @ $F000 - $F7FF\n" << " Slice 0 - 2 of ROM (hotspots $FE4 to $FE6)\n" << " Slice 7 (1K) of RAM (hotspot $FE7)\n" << " $F400 - $F7FF (R), $F000 - $F3FF (W)\n" << "256B RAM accessible @ $F800 - $F9FF\n" << " Hotspots $FE8 - $FEB (256B of RAM slice 1)\n" << " $F900 - $F9FF (R), $F800 - $F8FF (W)\n" << "Upper 1.5K ROM accessible @ $FA00 - $FFFF\n" << " Always points to last 1.5K of ROM\n" << "Startup slices = 0 / 0 or undetermined\n"; #if 0 // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[size - 3] << 8) | cart.myImage[size - 4]; start -= start % 0x1000; info << "Bank RORG" << " = $" << HEX4 << start << "\n"; #endif initialize(boss, cart, info); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* CartridgeE78KWidget::getSpotLower(int idx) { static const char* const spot_lower[] = { "0 - ROM ($FFE4)", "1 - ROM ($FFE5)", "2 - ROM ($FFE6)", "3 - RAM ($FFE7)" }; return spot_lower[idx]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* CartridgeE78KWidget::getSpotUpper(int idx) { static const char* const spot_upper[] = { "0 - RAM ($FFE8)", "1 - RAM ($FFE9)", "2 - RAM ($FFEA)", "3 - RAM ($FFEB)" }; return spot_upper[idx]; } stella-5.1.1/src/debugger/gui/CartE78KWidget.hxx000066400000000000000000000031131324334165500213320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEE78K_WIDGET_HXX #define CARTRIDGEE78K_WIDGET_HXX #include "CartMNetworkWidget.hxx" class CartridgeE78KWidget : public CartridgeMNetworkWidget { public: CartridgeE78KWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMNetwork& cart); virtual ~CartridgeE78KWidget() = default; protected: const char* getSpotLower(int idx); const char* getSpotUpper(int idx); private: // Following constructors and assignment operators not supported CartridgeE78KWidget() = delete; CartridgeE78KWidget(const CartridgeE78KWidget&) = delete; CartridgeE78KWidget(CartridgeE78KWidget&&) = delete; CartridgeE78KWidget& operator=(const CartridgeE78KWidget&) = delete; CartridgeE78KWidget& operator=(CartridgeE78KWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartE7Widget.cxx000066400000000000000000000050751324334165500211330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartMNetwork.hxx" #include "CartE7Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE7Widget::CartridgeE7Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMNetwork& cart) : CartridgeMNetworkWidget(boss, lfont, nfont, x, y, w, h, cart) { ostringstream info; info << "E7 cartridge, 8 2K slices ROM + 2 1K RAM\n" << "Lower 2K accessible @ $F000 - $F7FF\n" << " Slice 0 - 6 of ROM (hotspots $FE0 to $FE6)\n" << " Slice 7 (1K) of RAM (hotspot $FE7)\n" << " $F400 - $F7FF (R), $F000 - $F3FF (W)\n" << "256B RAM accessible @ $F800 - $F9FF\n" << " Hotspots $FE8 - $FEB (256B of RAM slice 1)\n" << " $F900 - $F9FF (R), $F800 - $F8FF (W)\n" << "Upper 1.5K ROM accessible @ $FA00 - $FFFF\n" << " Always points to last 1.5K of ROM\n" << "Startup slices = 0 / 0 or undetermined\n"; #if 0 // Eventually, we should query this from the debugger/disassembler uInt16 start = (cart.myImage[size-3] << 8) | cart.myImage[size-4]; start -= start % 0x1000; info << "Bank RORG" << " = $" << HEX4 << start << "\n"; #endif initialize(boss, cart, info); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* CartridgeE7Widget::getSpotLower(int idx) { static const char* const spot_lower[] = { "0 - ROM ($FFE0)", "1 - ROM ($FFE1)", "2 - ROM ($FFE2)", "3 - ROM ($FFE3)", "4 - ROM ($FFE4)", "5 - ROM ($FFE5)", "6 - ROM ($FFE6)", "7 - RAM ($FFE7)" }; return spot_lower[idx]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* CartridgeE7Widget::getSpotUpper(int idx) { static const char* const spot_upper[] = { "0 - RAM ($FFE8)", "1 - RAM ($FFE9)", "2 - RAM ($FFEA)", "3 - RAM ($FFEB)" }; return spot_upper[idx]; } stella-5.1.1/src/debugger/gui/CartE7Widget.hxx000066400000000000000000000030511324334165500211300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEE7_WIDGET_HXX #define CARTRIDGEE7_WIDGET_HXX #include "CartMNetworkWidget.hxx" class CartridgeE7Widget : public CartridgeMNetworkWidget { public: CartridgeE7Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMNetwork& cart); virtual ~CartridgeE7Widget() = default; protected: const char* getSpotLower(int idx); const char* getSpotUpper(int idx); private: // Following constructors and assignment operators not supported CartridgeE7Widget() = delete; CartridgeE7Widget(const CartridgeE7Widget&) = delete; CartridgeE7Widget(CartridgeE7Widget&&) = delete; CartridgeE7Widget& operator=(const CartridgeE7Widget&) = delete; CartridgeE7Widget& operator=(CartridgeE7Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartEFSCWidget.cxx000066400000000000000000000137461324334165500214040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartEFSC.hxx" #include "PopUpWidget.hxx" #include "CartEFSCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEFSCWidget::CartridgeEFSCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEFSC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 16 * 4096; ostringstream info; info << "64K H. Runner EFSC + RAM, 16 4K banks\n" << "128 bytes RAM @ $F000 - $F0FF\n" << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" << "Startup bank = " << cart.myStartBank << "\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFE0; i < 16; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Paul Slocum / Homestar Runner", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, " 0 ($FFE0)"); VarList::push_back(items, " 1 ($FFE1)"); VarList::push_back(items, " 2 ($FFE2)"); VarList::push_back(items, " 3 ($FFE3)"); VarList::push_back(items, " 4 ($FFE4)"); VarList::push_back(items, " 5 ($FFE5)"); VarList::push_back(items, " 6 ($FFE6)"); VarList::push_back(items, " 7 ($FFE7)"); VarList::push_back(items, " 8 ($FFE8)"); VarList::push_back(items, " 9 ($FFE9)"); VarList::push_back(items, "10 ($FFEA)"); VarList::push_back(items, "11 ($FFEB)"); VarList::push_back(items, "12 ($FFEC)"); VarList::push_back(items, "13 ($FFED)"); VarList::push_back(items, "14 ($FFEE)"); VarList::push_back(items, "15 ($FFEF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("15 ($FFE0) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSCWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSCWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSCWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeEFSCWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7", "$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeEFSCWidget::internalRamSize() { return 128; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeEFSCWidget::internalRamRPort(int start) { return 0xF080 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeEFSCWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F07F used for Write Access\n" << "$F080 - $F0FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeEFSCWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeEFSCWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSCWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeEFSCWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeEFSCWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF080, false); } stella-5.1.1/src/debugger/gui/CartEFSCWidget.hxx000066400000000000000000000046401324334165500214020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEEFSC_WIDGET_HXX #define CARTRIDGEEFSC_WIDGET_HXX class CartridgeEFSC; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeEFSCWidget : public CartDebugWidget { public: CartridgeEFSCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEFSC& cart); virtual ~CartridgeEFSCWidget() = default; private: CartridgeEFSC& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeEFSCWidget() = delete; CartridgeEFSCWidget(const CartridgeEFSCWidget&) = delete; CartridgeEFSCWidget(CartridgeEFSCWidget&&) = delete; CartridgeEFSCWidget& operator=(const CartridgeEFSCWidget&) = delete; CartridgeEFSCWidget& operator=(CartridgeEFSCWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartEFWidget.cxx000066400000000000000000000077771324334165500211650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartEF.hxx" #include "PopUpWidget.hxx" #include "CartEFWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEFWidget::CartridgeEFWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEF& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 16 * 4096; ostringstream info; info << "64K H. Runner EF cartridge, 16 4K banks\n" << "Startup bank = " << cart.myStartBank << "\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFE0; i < 16; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Paul Slocum / Homestar Runner", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, " 0 ($FFE0)"); VarList::push_back(items, " 1 ($FFE1)"); VarList::push_back(items, " 2 ($FFE2)"); VarList::push_back(items, " 3 ($FFE3)"); VarList::push_back(items, " 4 ($FFE4)"); VarList::push_back(items, " 5 ($FFE5)"); VarList::push_back(items, " 6 ($FFE6)"); VarList::push_back(items, " 7 ($FFE7)"); VarList::push_back(items, " 8 ($FFE8)"); VarList::push_back(items, " 9 ($FFE9)"); VarList::push_back(items, "10 ($FFEA)"); VarList::push_back(items, "11 ($FFEB)"); VarList::push_back(items, "12 ($FFEC)"); VarList::push_back(items, "13 ($FFED)"); VarList::push_back(items, "14 ($FFEE)"); VarList::push_back(items, "15 ($FFEF)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("15 ($FFE0) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeEFWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFE0", "$FFE1", "$FFE2", "$FFE3", "$FFE4", "$FFE5", "$FFE6", "$FFE7", "$FFE8", "$FFE9", "$FFEA", "$FFEB", "$FFEC", "$FFED", "$FFEE", "$FFEF" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartEFWidget.hxx000066400000000000000000000033341324334165500211530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEEF_WIDGET_HXX #define CARTRIDGEEF_WIDGET_HXX class CartridgeEF; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeEFWidget : public CartDebugWidget { public: CartridgeEFWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeEF& cart); virtual ~CartridgeEFWidget() = default; private: CartridgeEF& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeEFWidget() = delete; CartridgeEFWidget(const CartridgeEFWidget&) = delete; CartridgeEFWidget(CartridgeEFWidget&&) = delete; CartridgeEFWidget& operator=(const CartridgeEFWidget&) = delete; CartridgeEFWidget& operator=(CartridgeEFWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartF0Widget.cxx000066400000000000000000000072621324334165500211250ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartF0.hxx" #include "PopUpWidget.hxx" #include "CartF0Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF0Widget::CartridgeF0Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF0& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 16 * 4096; ostringstream info; info << "64K Megaboy F0 cartridge, 16 4K banks\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n" << "Bankswitch triggered by accessing $1FF0\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC; i < 16; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << "\n"; } int xpos = 10, ypos = addBaseInformation(size, "Dynacom Megaboy", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, " 0"); VarList::push_back(items, " 1"); VarList::push_back(items, " 2"); VarList::push_back(items, " 3"); VarList::push_back(items, " 4"); VarList::push_back(items, " 5"); VarList::push_back(items, " 6"); VarList::push_back(items, " 7"); VarList::push_back(items, " 8"); VarList::push_back(items, " 9"); VarList::push_back(items, " 10"); VarList::push_back(items, " 11"); VarList::push_back(items, " 12"); VarList::push_back(items, " 13"); VarList::push_back(items, " 14"); VarList::push_back(items, " 15"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth(" 15 "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF0Widget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF0Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF0Widget::bankState() { ostringstream& buf = buffer(); buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = $FFF0"; return buf.str(); } stella-5.1.1/src/debugger/gui/CartF0Widget.hxx000066400000000000000000000033341324334165500211260ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF0_WIDGET_HXX #define CARTRIDGEF0_WIDGET_HXX class CartridgeF0; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeF0Widget : public CartDebugWidget { public: CartridgeF0Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF0& cart); virtual ~CartridgeF0Widget() = default; private: CartridgeF0& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeF0Widget() = delete; CartridgeF0Widget(const CartridgeF0Widget&) = delete; CartridgeF0Widget(CartridgeF0Widget&&) = delete; CartridgeF0Widget& operator=(const CartridgeF0Widget&) = delete; CartridgeF0Widget& operator=(CartridgeF0Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartF4SCWidget.cxx000066400000000000000000000130101324334165500213430ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartF4SC.hxx" #include "PopUpWidget.hxx" #include "CartF4SCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4SCWidget::CartridgeF4SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF4SC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 8 * 4096; ostringstream info; info << "Standard F4SC cartridge, eight 4K banks\n" << "128 bytes RAM @ $F000 - $F0FF\n" << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF4; i < 8; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str(), 15) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF4)"); VarList::push_back(items, "1 ($FFF5)"); VarList::push_back(items, "2 ($FFF6)"); VarList::push_back(items, "3 ($FFF7)"); VarList::push_back(items, "4 ($FFF8)"); VarList::push_back(items, "5 ($FFF9)"); VarList::push_back(items, "6 ($FFFA)"); VarList::push_back(items, "7 ($FFFB)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4SCWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4SCWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4SCWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF4SCWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeF4SCWidget::internalRamSize() { return 128; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeF4SCWidget::internalRamRPort(int start) { return 0xF080 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF4SCWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F07F used for Write Access\n" << "$F080 - $F0FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeF4SCWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeF4SCWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4SCWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF4SCWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF4SCWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF080, false); } stella-5.1.1/src/debugger/gui/CartF4SCWidget.hxx000066400000000000000000000046411324334165500213620ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF4SC_WIDGET_HXX #define CARTRIDGEF4SC_WIDGET_HXX class CartridgeF4SC; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeF4SCWidget : public CartDebugWidget { public: CartridgeF4SCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF4SC& cart); virtual ~CartridgeF4SCWidget() = default; private: CartridgeF4SC& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeF4SCWidget() = delete; CartridgeF4SCWidget(const CartridgeF4SCWidget&) = delete; CartridgeF4SCWidget(CartridgeF4SCWidget&&) = delete; CartridgeF4SCWidget& operator=(const CartridgeF4SCWidget&) = delete; CartridgeF4SCWidget& operator=(CartridgeF4SCWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartF4Widget.cxx000066400000000000000000000070361324334165500211300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartF4.hxx" #include "PopUpWidget.hxx" #include "CartF4Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4Widget::CartridgeF4Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF4& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 8 * 4096; ostringstream info; info << "Standard F4 cartridge, eight 4K banks\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF4; i < 8; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str(), 15) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF4)"); VarList::push_back(items, "1 ($FFF5)"); VarList::push_back(items, "2 ($FFF6)"); VarList::push_back(items, "3 ($FFF7)"); VarList::push_back(items, "4 ($FFF8)"); VarList::push_back(items, "5 ($FFF9)"); VarList::push_back(items, "6 ($FFFA)"); VarList::push_back(items, "7 ($FFFB)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4Widget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF4Widget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF4", "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartF4Widget.hxx000066400000000000000000000033341324334165500211320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF4_WIDGET_HXX #define CARTRIDGEF4_WIDGET_HXX class CartridgeF4; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeF4Widget : public CartDebugWidget { public: CartridgeF4Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF4& cart); virtual ~CartridgeF4Widget() = default; private: CartridgeF4& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeF4Widget() = delete; CartridgeF4Widget(const CartridgeF4Widget&) = delete; CartridgeF4Widget(CartridgeF4Widget&&) = delete; CartridgeF4Widget& operator=(const CartridgeF4Widget&) = delete; CartridgeF4Widget& operator=(CartridgeF4Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartF6SCWidget.cxx000066400000000000000000000124621324334165500213570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartF6SC.hxx" #include "PopUpWidget.hxx" #include "CartF6SCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6SCWidget::CartridgeF6SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF6SC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 4 * 4096; ostringstream info; info << "Standard F6SC cartridge, four 4K banks\n" << "128 bytes RAM @ $F000 - $F0FF\n" << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF6; i < 4; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF6)"); VarList::push_back(items, "1 ($FFF7)"); VarList::push_back(items, "2 ($FFF8)"); VarList::push_back(items, "3 ($FFF9)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6SCWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6SCWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6SCWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF6SCWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF6", "$FFF7", "$FFF8", "$FFF9" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeF6SCWidget::internalRamSize() { return 128; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeF6SCWidget::internalRamRPort(int start) { return 0xF080 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF6SCWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F07F used for Write Access\n" << "$F080 - $F0FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeF6SCWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeF6SCWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6SCWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF6SCWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF6SCWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF080, false); } stella-5.1.1/src/debugger/gui/CartF6SCWidget.hxx000066400000000000000000000046371324334165500213710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF6SC_WIDGET_HXX #define CARTRIDGEF6SC_WIDGET_HXX class CartridgeF6SC; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeF6SCWidget : public CartDebugWidget { public: CartridgeF6SCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF6SC& cart); virtual ~CartridgeF6SCWidget() = default; private: struct CartState { ByteArray internalram; uInt16 bank; }; CartridgeF6SC& myCart; PopUpWidget* myBank; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeF6SCWidget() = delete; CartridgeF6SCWidget(const CartridgeF6SCWidget&) = delete; CartridgeF6SCWidget(CartridgeF6SCWidget&&) = delete; CartridgeF6SCWidget& operator=(const CartridgeF6SCWidget&) = delete; CartridgeF6SCWidget& operator=(CartridgeF6SCWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartF6Widget.cxx000066400000000000000000000065071324334165500211340ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartF6.hxx" #include "PopUpWidget.hxx" #include "CartF6Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6Widget::CartridgeF6Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF6& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 4 * 4096; ostringstream info; info << "Standard F6 cartridge, four 4K banks\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF6; i < 4; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF6)"); VarList::push_back(items, "1 ($FFF7)"); VarList::push_back(items, "2 ($FFF8)"); VarList::push_back(items, "3 ($FFF9)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6Widget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF6Widget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF6", "$FFF7", "$FFF8", "$FFF9" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartF6Widget.hxx000066400000000000000000000033341324334165500211340ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF6_WIDGET_HXX #define CARTRIDGEF6_WIDGET_HXX class CartridgeF6; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeF6Widget : public CartDebugWidget { public: CartridgeF6Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF6& cart); virtual ~CartridgeF6Widget() = default; private: CartridgeF6& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeF6Widget() = delete; CartridgeF6Widget(const CartridgeF6Widget&) = delete; CartridgeF6Widget(CartridgeF6Widget&&) = delete; CartridgeF6Widget& operator=(const CartridgeF6Widget&) = delete; CartridgeF6Widget& operator=(CartridgeF6Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartF8SCWidget.cxx000066400000000000000000000123111324334165500213520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartF8SC.hxx" #include "PopUpWidget.hxx" #include "CartF8SCWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8SCWidget::CartridgeF8SCWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF8SC& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 8192; ostringstream info; info << "Standard F8SC cartridge, two 4K banks\n" << "128 bytes RAM @ $F000 - $F0FF\n" << " $F080 - $F0FF (R), $F000 - $F07F (W)\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 2; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x100) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF8)"); VarList::push_back(items, "1 ($FFF9)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8SCWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8SCWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8SCWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF8SCWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF8", "$FFF9" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeF8SCWidget::internalRamSize() { return 128; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeF8SCWidget::internalRamRPort(int start) { return 0xF080 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF8SCWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F07F used for Write Access\n" << "$F080 - $F0FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeF8SCWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeF8SCWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8SCWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF8SCWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF8SCWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF080, false); } stella-5.1.1/src/debugger/gui/CartF8SCWidget.hxx000066400000000000000000000046401324334165500213650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF8SC_WIDGET_HXX #define CARTRIDGEF8SC_WIDGET_HXX class CartridgeF8SC; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeF8SCWidget : public CartDebugWidget { public: CartridgeF8SCWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF8SC& cart); virtual ~CartridgeF8SCWidget() = default; private: CartridgeF8SC& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeF8SCWidget() = delete; CartridgeF8SCWidget(const CartridgeF8SCWidget&) = delete; CartridgeF8SCWidget(CartridgeF8SCWidget&&) = delete; CartridgeF8SCWidget& operator=(const CartridgeF8SCWidget&) = delete; CartridgeF8SCWidget& operator=(CartridgeF8SCWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartF8Widget.cxx000066400000000000000000000063401324334165500211310ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartF8.hxx" #include "PopUpWidget.hxx" #include "CartF8Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8Widget::CartridgeF8Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF8& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 2 * 4096; ostringstream info; info << "Standard F8 cartridge, two 4K banks\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 2; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Atari", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF8)"); VarList::push_back(items, "1 ($FFF9)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8Widget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeF8Widget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF8", "$FFF9" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartF8Widget.hxx000066400000000000000000000033341324334165500211360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF8_WIDGET_HXX #define CARTRIDGEF8_WIDGET_HXX class CartridgeF8; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeF8Widget : public CartDebugWidget { public: CartridgeF8Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeF8& cart); virtual ~CartridgeF8Widget() = default; private: CartridgeF8& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeF8Widget() = delete; CartridgeF8Widget(const CartridgeF8Widget&) = delete; CartridgeF8Widget(CartridgeF8Widget&&) = delete; CartridgeF8Widget& operator=(const CartridgeF8Widget&) = delete; CartridgeF8Widget& operator=(CartridgeF8Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartFA2Widget.cxx000066400000000000000000000153761324334165500212350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartFA2.hxx" #include "PopUpWidget.hxx" #include "CartFA2Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA2Widget::CartridgeFA2Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA2& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = cart.mySize; ostringstream info; info << "Modified FA RAM+, six or seven 4K banks\n" << "256 bytes RAM @ $F000 - $F1FF\n" << " $F100 - $F1FF (R), $F000 - $F0FF (W)\n" << "RAM can be loaded/saved to Harmony flash by accessing $FFF4\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF5; i < cart.bankCount(); ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x200) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "Chris D. Walton (Star Castle 2600)", info.str(), 15) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF5)"); VarList::push_back(items, "1 ($FFF6)"); VarList::push_back(items, "2 ($FFF7)"); VarList::push_back(items, "3 ($FFF8)"); VarList::push_back(items, "4 ($FFF9)"); VarList::push_back(items, "5 ($FFFA)"); if(cart.bankCount() == 7) VarList::push_back(items, "6 ($FFFB)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); ypos += myLineHeight + 20; const int bwidth = _font.getStringWidth("Erase") + 20; StaticTextWidget* t = new StaticTextWidget(boss, _font, xpos, ypos, _font.getStringWidth("Harmony Flash "), myFontHeight, "Harmony Flash ", TextAlign::Left); xpos += t->getWidth() + 4; myFlashErase = new ButtonWidget(boss, _font, xpos, ypos-4, bwidth, myButtonHeight, "Erase", kFlashErase); myFlashErase->setTarget(this); addFocusWidget(myFlashErase); xpos += myFlashErase->getWidth() + 8; myFlashLoad = new ButtonWidget(boss, _font, xpos, ypos-4, bwidth, myButtonHeight, "Load", kFlashLoad); myFlashLoad->setTarget(this); addFocusWidget(myFlashLoad); xpos += myFlashLoad->getWidth() + 8; myFlashSave = new ButtonWidget(boss, _font, xpos, ypos-4, bwidth, myButtonHeight, "Save", kFlashSave); myFlashSave->setTarget(this); addFocusWidget(myFlashSave); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2Widget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2Widget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kBankChanged: myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); break; case kFlashErase: myCart.flash(0); break; case kFlashLoad: myCart.flash(1); break; case kFlashSave: myCart.flash(2); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeFA2Widget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF5", "$FFF6", "$FFF7", "$FFF8", "$FFF9", "$FFFA", "$FFFB" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeFA2Widget::internalRamSize() { return 256; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeFA2Widget::internalRamRPort(int start) { return 0xF100 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeFA2Widget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F0FF used for Write Access\n" << "$F100 - $F1FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeFA2Widget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeFA2Widget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2Widget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFA2Widget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeFA2Widget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF100, false); } stella-5.1.1/src/debugger/gui/CartFA2Widget.hxx000066400000000000000000000050751324334165500212350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEFA2_WIDGET_HXX #define CARTRIDGEFA2_WIDGET_HXX class CartridgeFA2; class ButtonWidget; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeFA2Widget : public CartDebugWidget { public: CartridgeFA2Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA2& cart); virtual ~CartridgeFA2Widget() = default; private: CartridgeFA2& myCart; PopUpWidget* myBank; ButtonWidget *myFlashErase, *myFlashLoad, *myFlashSave; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH', kFlashErase = 'flER', kFlashLoad = 'flLD', kFlashSave = 'flSV' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeFA2Widget() = delete; CartridgeFA2Widget(const CartridgeFA2Widget&) = delete; CartridgeFA2Widget(CartridgeFA2Widget&&) = delete; CartridgeFA2Widget& operator=(const CartridgeFA2Widget&) = delete; CartridgeFA2Widget& operator=(CartridgeFA2Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartFAWidget.cxx000066400000000000000000000123321324334165500211400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartFA.hxx" #include "PopUpWidget.hxx" #include "CartFAWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFAWidget::CartridgeFAWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 3 * 4096; ostringstream info; info << "CBS RAM+ FA cartridge, three 4K banks\n" << "256 bytes RAM @ $F000 - $F1FF\n" << " $F100 - $F1FF (R), $F000 - $F0FF (W)\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0xFF8; i < 3; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << (start + 0x200) << " - " << "$" << (start + 0xFFF) << " (hotspot = $F" << (spot+i) << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "CBS", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($FFF8)"); VarList::push_back(items, "1 ($FFF9)"); VarList::push_back(items, "2 ($FFFA)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFAWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize();i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFAWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFAWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeFAWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$FFF8", "$FFF9", "$FFFA" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeFAWidget::internalRamSize() { return 256; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeFAWidget::internalRamRPort(int start) { return 0xF100 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeFAWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F0FF used for Write Access\n" << "$F100 - $F1FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeFAWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeFAWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFAWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFAWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeFAWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF100, false); } stella-5.1.1/src/debugger/gui/CartFAWidget.hxx000066400000000000000000000045701324334165500211520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEFA_WIDGET_HXX #define CARTRIDGEFA_WIDGET_HXX class CartridgeFA; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeFAWidget : public CartDebugWidget { public: CartridgeFAWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFA& cart); virtual ~CartridgeFAWidget() = default; private: CartridgeFA& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeFAWidget() = delete; CartridgeFAWidget(const CartridgeFAWidget&) = delete; CartridgeFAWidget(CartridgeFAWidget&&) = delete; CartridgeFAWidget& operator=(const CartridgeFAWidget&) = delete; CartridgeFAWidget& operator=(CartridgeFAWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartFEWidget.cxx000066400000000000000000000057071324334165500211540ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartFE.hxx" #include "PopUpWidget.hxx" #include "CartFEWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFEWidget::CartridgeFEWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFE& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { string info = "FE cartridge, two 4K banks\n" "Monitors access to hotspot $01FE, and uses " "upper 3 bits of databus for bank number:\n" "Bank 0 @ $F000 - $FFFF (DATA = 111, D5 = 1)\n" "Bank 1 @ $D000 - $DFFF (DATA = 110, D5 = 0)\n"; int xpos = 10, ypos = addBaseInformation(2 * 4096, "Activision", info) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($01FE, D5=1)"); VarList::push_back(items, "1 ($01FE, D5=0)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($01FE, D5=1)"), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFEWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFEWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeFEWidget::bankState() { ostringstream& buf = buffer(); static const char* const range[] = { "$F000", "$D000" }; buf << "Bank = " << std::dec << myCart.getBank() << ", address range = " << range[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartFEWidget.hxx000066400000000000000000000034171324334165500211550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEFE_WIDGET_HXX #define CARTRIDGEFE_WIDGET_HXX class CartridgeFE; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeFEWidget : public CartDebugWidget { public: CartridgeFEWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeFE& cart); virtual ~CartridgeFEWidget() = default; private: CartridgeFE& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: // No implementation for non-bankswitched ROMs void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeFEWidget() = delete; CartridgeFEWidget(const CartridgeFEWidget&) = delete; CartridgeFEWidget(CartridgeFEWidget&&) = delete; CartridgeFEWidget& operator=(const CartridgeFEWidget&) = delete; CartridgeFEWidget& operator=(CartridgeFEWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartMDMWidget.cxx000066400000000000000000000064301324334165500212710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartMDM.hxx" #include "PopUpWidget.hxx" #include "Widget.hxx" #include "CartMDMWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMDMWidget::CartridgeMDMWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMDM& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = myCart.mySize; ostringstream info; info << "Menu Driven Megacart, containing up to 128 4K banks\n" << "Startup bank = " << cart.myStartBank << "\n" << "\nBanks are selected by reading from $800 - $BFF, where the lower " "byte determines the 4K bank to use."; int xpos = 10, ypos = addBaseInformation(size, "Edwin Blink", info.str(), 15) + myLineHeight; VariantList items; for(uInt32 i = 0x800; i < (0x800u + myCart.bankCount()); ++i) { info.str(""); info << std::dec << (i & 0xFF) << " ($" << Common::Base::HEX4 << i << ")"; VarList::push_back(items, info.str()); } myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("xxx ($0FFF) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); xpos += myBank->getWidth() + 30; myBankDisabled = new CheckboxWidget(boss, _font, xpos, ypos, "Bankswitching is locked/disabled", kBankDisabled); myBankDisabled->setTarget(this); addFocusWidget(myBankDisabled); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMDMWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank()); myBankDisabled->setState(myCart.myBankingDisabled); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMDMWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } else if(cmd == kBankDisabled) { myCart.myBankingDisabled = myBankDisabled->getState(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeMDMWidget::bankState() { ostringstream& buf = buffer(); buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << "$" << Common::Base::HEX4 << (myCart.getBank()+0x800); return buf.str(); } stella-5.1.1/src/debugger/gui/CartMDMWidget.hxx000066400000000000000000000035021324334165500212730ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEMDM_WIDGET_HXX #define CARTRIDGEMDM_WIDGET_HXX class CartridgeMDM; class CheckboxWidget; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeMDMWidget : public CartDebugWidget { public: CartridgeMDMWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMDM& cart); virtual ~CartridgeMDMWidget() = default; private: CartridgeMDM& myCart; PopUpWidget* myBank; CheckboxWidget* myBankDisabled; enum { kBankChanged = 'bkCH', kBankDisabled = 'bkDI' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeMDMWidget() = delete; CartridgeMDMWidget(const CartridgeMDMWidget&) = delete; CartridgeMDMWidget(CartridgeMDMWidget&&) = delete; CartridgeMDMWidget& operator=(const CartridgeMDMWidget&) = delete; CartridgeMDMWidget& operator=(CartridgeMDMWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartMNetworkWidget.cxx000066400000000000000000000127071324334165500224260ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ //#include "CartE7.hxx" #include "CartMNetwork.hxx" #include "PopUpWidget.hxx" #include "CartMNetworkWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMNetworkWidget::CartridgeMNetworkWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeMNetwork& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) {} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetworkWidget::initialize(GuiObject* boss, CartridgeMNetwork& cart, ostringstream& info) { uInt32 size = cart.bankCount() * cart.BANK_SIZE; int xpos = 10, ypos = addBaseInformation(size, "M-Network", info.str(), 15) + myLineHeight; VariantList items0, items1; for(int i = 0; i < cart.bankCount(); ++i) VarList::push_back(items0, getSpotLower(i)); for(int i = 0; i < 4; ++i) VarList::push_back(items1, getSpotUpper(i)); const int lwidth = _font.getStringWidth("Set slice for upper 256B "), fwidth = _font.getStringWidth("3 - RAM ($FFEB)"); myLower2K = new PopUpWidget(boss, _font, xpos, ypos - 2, fwidth, myLineHeight, items0, "Set slice for lower 2K ", lwidth, kLowerChanged); myLower2K->setTarget(this); addFocusWidget(myLower2K); ypos += myLower2K->getHeight() + 4; myUpper256B = new PopUpWidget(boss, _font, xpos, ypos - 2, fwidth, myLineHeight, items1, "Set slice for upper 256B ", lwidth, kUpperChanged); myUpper256B->setTarget(this); addFocusWidget(myUpper256B); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetworkWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < this->internalRamSize(); i++) { myOldState.internalram.push_back(myCart.myRAM[i]); } myOldState.lowerBank = myCart.myCurrentSlice[0]; myOldState.upperBank = myCart.myCurrentRAM; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetworkWidget::loadConfig() { myLower2K->setSelectedIndex(myCart.myCurrentSlice[0], myCart.myCurrentSlice[0] != myOldState.lowerBank); myUpper256B->setSelectedIndex(myCart.myCurrentRAM, myCart.myCurrentRAM != myOldState.upperBank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetworkWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { myCart.unlockBank(); switch(cmd) { case kLowerChanged: myCart.bank(myLower2K->getSelected()); break; case kUpperChanged: myCart.bankRAM(myUpper256B->getSelected()); break; } myCart.lockBank(); invalidate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeMNetworkWidget::bankState() { ostringstream& buf = buffer(); buf << "Slices: " << std::dec << getSpotLower(myCart.myCurrentSlice[0]) << " / " << getSpotUpper(myCart.myCurrentRAM); return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeMNetworkWidget::internalRamSize() { return 2048; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeMNetworkWidget::internalRamRPort(int start) { return 0x0000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeMNetworkWidget::internalRamDescription() { ostringstream desc; desc << "First 1K accessible via:\n" << " $F000 - $F3FF used for Write Access\n" << " $F400 - $F7FF used for Read Access\n" << "256K of second 1K accessible via:\n" << " $F800 - $F8FF used for Write Access\n" << " $F900 - $F9FF used for Read Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeMNetworkWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; i++) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeMNetworkWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; i++) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetworkWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeMNetworkWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } stella-5.1.1/src/debugger/gui/CartMNetworkWidget.hxx000066400000000000000000000054521324334165500224320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_MNETWORK_WIDGET_HXX #define CARTRIDGE_MNETWORK_WIDGET_HXX class CartridgeMNetwork; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeMNetworkWidget : public CartDebugWidget { public: CartridgeMNetworkWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, //CartridgeE7& cart); CartridgeMNetwork& cart); virtual ~CartridgeMNetworkWidget() = default; protected: PopUpWidget *myLower2K, *myUpper256B; //CartridgeE7& myCart; CartridgeMNetwork& myCart; struct CartState { ByteArray internalram; uInt16 lowerBank; uInt16 upperBank; }; CartState myOldState; enum { kLowerChanged = 'lwCH', kUpperChanged = 'upCH' }; protected: void initialize(GuiObject* boss, CartridgeMNetwork& cart, ostringstream& info); virtual const char* getSpotLower(int idx) = 0; virtual const char* getSpotUpper(int idx) = 0; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; // end of functions for Cartridge RAM tab private: // Following constructors and assignment operators not supported CartridgeMNetworkWidget() = delete; CartridgeMNetworkWidget(const CartridgeMNetworkWidget&) = delete; CartridgeMNetworkWidget(CartridgeMNetworkWidget&&) = delete; CartridgeMNetworkWidget& operator=(const CartridgeMNetworkWidget&) = delete; CartridgeMNetworkWidget& operator=(CartridgeMNetworkWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartRamWidget.cxx000066400000000000000000000132201324334165500213660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "EditTextWidget.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "CartDebug.hxx" #include "StringParser.hxx" #include "Widget.hxx" #include "Font.hxx" #include "StringListWidget.hxx" #include "ScrollBarWidget.hxx" #include "CartDebugWidget.hxx" #include "CartRamWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartRamWidget::CartRamWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartDebugWidget& cartDebug) : Widget(boss, lfont, x, y, w, h), CommandSender(boss), _nfont(nfont), myFontWidth(lfont.getMaxCharWidth()), myFontHeight(lfont.getFontHeight()), myLineHeight(lfont.getLineHeight()), myButtonHeight(myLineHeight + 4) { int lwidth = lfont.getStringWidth("Description "), fwidth = w - lwidth - 20; EditTextWidget* etw = nullptr; ostringstream buf; int xpos = 2, ypos = 5; // Add RAM size new StaticTextWidget(_boss, _font, xpos, ypos, lwidth, myFontHeight, "RAM Size ", TextAlign::Left); uInt32 ramsize = cartDebug.internalRamSize(); buf << ramsize << " bytes"; if(ramsize >= 1024) buf << " / " << (ramsize/1024) << "KB"; etw = new EditTextWidget(boss, nfont, xpos+lwidth, ypos, fwidth, myLineHeight, buf.str()); etw->setEditable(false); ypos += myLineHeight + 4; // Add Description const string& desc = cartDebug.internalRamDescription(); const uInt16 maxlines = 6; StringParser bs(desc, (fwidth - kScrollBarWidth) / myFontWidth); const StringList& sl = bs.stringList(); uInt32 lines = uInt32(sl.size()); if(lines < 3) lines = 3; if(lines > maxlines) lines = maxlines; new StaticTextWidget(_boss, _font, xpos, ypos, lwidth, myFontHeight, "Description ", TextAlign::Left); myDesc = new StringListWidget(boss, nfont, xpos+lwidth, ypos, fwidth, lines * myLineHeight, false); myDesc->setEditable(false); myDesc->setList(sl); addFocusWidget(myDesc); ypos += myDesc->getHeight() + myFontHeight / 2; // Add RAM widget xpos = x + _font.getStringWidth("xxxx"); myRam = new InternalRamWidget(boss, lfont, nfont, 2, ypos, w, h-ypos, cartDebug); addToFocusList(myRam->getFocusList()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartRamWidget::loadConfig() { myRam->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartRamWidget::setOpsWidget(DataGridOpsWidget* w) { myRam->setOpsWidget(w); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartRamWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { myRam->handleCommand(sender, cmd, data, id); } /////////////////////////////////// // Internal RAM implementation /////////////////////////////////// // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartRamWidget::InternalRamWidget::InternalRamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartDebugWidget& dbg) : RamWidget(boss, lfont, nfont, x, y, w, h, dbg.internalRamSize(), std::min(dbg.internalRamSize() / 16, 16u), std::min(dbg.internalRamSize() / 16, 16u) * 16), myCart(dbg) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartRamWidget::InternalRamWidget::~InternalRamWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartRamWidget::InternalRamWidget::getValue(int addr) const { return myCart.internalRamGetValue(addr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartRamWidget::InternalRamWidget::setValue(int addr, uInt8 value) { myCart.internalRamSetValue(addr, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartRamWidget::InternalRamWidget::getLabel(int addr) const { return myCart.internalRamLabel(addr); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartRamWidget::InternalRamWidget::fillList(uInt32 start, uInt32 size, IntArray& alist, IntArray& vlist, BoolArray& changed) const { const ByteArray& oldRam = myCart.internalRamOld(start, size); const ByteArray& currRam = myCart.internalRamCurrent(start, size); for(uInt32 i = 0; i < size; i++) { alist.push_back(i+start); vlist.push_back(currRam[i]); changed.push_back(currRam[i] != oldRam[i]); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartRamWidget::InternalRamWidget::readPort(uInt32 start) const { return myCart.internalRamRPort(start); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartRamWidget::InternalRamWidget::currentRam(uInt32 start) const { return myCart.internalRamCurrent(start, myCart.internalRamSize()); } stella-5.1.1/src/debugger/gui/CartRamWidget.hxx000066400000000000000000000062621324334165500214030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CART_RAM_WIDGET_HXX #define CART_RAM_WIDGET_HXX class GuiObject; class DataGridOpsWidget; class StringListWidget; class InternalRamWidget; class CartDebugWidget; #include "RamWidget.hxx" #include "Widget.hxx" #include "Command.hxx" class CartRamWidget : public Widget, public CommandSender { public: CartRamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartDebugWidget& cartDebug); virtual ~CartRamWidget() = default; void loadConfig() override; void setOpsWidget(DataGridOpsWidget* w); private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; protected: // Font used for 'normal' text; _font is for 'label' text const GUI::Font& _nfont; // These will be needed by most of the child classes; // we may as well make them protected variables int myFontWidth, myFontHeight, myLineHeight, myButtonHeight; private: // Following constructors and assignment operators not supported CartRamWidget() = delete; CartRamWidget(const CartRamWidget&) = delete; CartRamWidget(CartRamWidget&&) = delete; CartRamWidget& operator=(const CartRamWidget&) = delete; CartRamWidget& operator=(CartRamWidget&&) = delete; private: class InternalRamWidget : public RamWidget { public: InternalRamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartDebugWidget& cartDebug); virtual ~InternalRamWidget(); private: uInt8 getValue(int addr) const; void setValue(int addr, uInt8 value); string getLabel(int addr) const; void fillList(uInt32 start, uInt32 size, IntArray& alist, IntArray& vlist, BoolArray& changed) const; uInt32 readPort(uInt32 start) const; const ByteArray& currentRam(uInt32 start) const; private: CartDebugWidget& myCart; private: // Following constructors and assignment operators not supported InternalRamWidget() = delete; InternalRamWidget(const InternalRamWidget&) = delete; InternalRamWidget(InternalRamWidget&&) = delete; InternalRamWidget& operator=(const InternalRamWidget&) = delete; InternalRamWidget& operator=(InternalRamWidget&&) = delete; }; private: StringListWidget* myDesc; InternalRamWidget* myRam; }; #endif stella-5.1.1/src/debugger/gui/CartSBWidget.cxx000066400000000000000000000070011324334165500211530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartSB.hxx" #include "PopUpWidget.hxx" #include "CartSBWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeSBWidget::CartridgeSBWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeSB& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = myCart.mySize; VariantList items; ostringstream info, bank; info << "SB SUPERbanking, 32 or 64 4K banks\n" << "Hotspots are from $800 to $" << Common::Base::HEX2 << (0x800 + myCart.bankCount() - 1) << ", including\n" << "mirrors ($900, $A00, $B00, ...)\n" << "Startup bank = " << std::dec << cart.myStartBank << "\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0x800; i < myCart.bankCount(); ++i, offset += 0x1000, ++spot) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n"; bank << std::dec << std::setw(2) << std::setfill(' ') << i << " ($" << Common::Base::HEX2 << spot << ")"; VarList::push_back(items, bank.str()); bank.str(""); } int xpos = 10, ypos = addBaseInformation(size, "Fred X. Quimby", info.str()) + myLineHeight; myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("XX ($800) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeSBWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeSBWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeSBWidget::bankState() { ostringstream& buf = buffer(); buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = $" << Common::Base::HEX2 << (myCart.getBank() + 0x800); return buf.str(); } stella-5.1.1/src/debugger/gui/CartSBWidget.hxx000066400000000000000000000033341324334165500211650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGESB_WIDGET_HXX #define CARTRIDGESB_WIDGET_HXX class CartridgeSB; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeSBWidget : public CartDebugWidget { public: CartridgeSBWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeSB& cart); virtual ~CartridgeSBWidget() = default; private: CartridgeSB& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeSBWidget() = delete; CartridgeSBWidget(const CartridgeSBWidget&) = delete; CartridgeSBWidget(CartridgeSBWidget&&) = delete; CartridgeSBWidget& operator=(const CartridgeSBWidget&) = delete; CartridgeSBWidget& operator=(CartridgeSBWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartUAWidget.cxx000066400000000000000000000063511324334165500211630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartUA.hxx" #include "PopUpWidget.hxx" #include "CartUAWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeUAWidget::CartridgeUAWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeUA& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt16 size = 2 * 4096; ostringstream info; info << "8K UA cartridge, two 4K banks\n" << "Startup bank = " << cart.myStartBank << " or undetermined\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC, spot = 0x220; i < 2; ++i, offset += 0x1000, spot += 0x20) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << " (hotspot = $" << spot << ")\n"; } int xpos = 10, ypos = addBaseInformation(size, "UA Limited", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($220)"); VarList::push_back(items, "1 ($240)"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("0 ($FFx) "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeUAWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeUAWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeUAWidget::bankState() { ostringstream& buf = buffer(); static const char* const spot[] = { "$200", "$240" }; buf << "Bank = " << std::dec << myCart.getBank() << ", hotspot = " << spot[myCart.getBank()]; return buf.str(); } stella-5.1.1/src/debugger/gui/CartUAWidget.hxx000066400000000000000000000033341324334165500211660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEUA_WIDGET_HXX #define CARTRIDGEUA_WIDGET_HXX class CartridgeUA; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeUAWidget : public CartDebugWidget { public: CartridgeUAWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeUA& cart); virtual ~CartridgeUAWidget() = default; private: CartridgeUA& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeUAWidget() = delete; CartridgeUAWidget(const CartridgeUAWidget&) = delete; CartridgeUAWidget(CartridgeUAWidget&&) = delete; CartridgeUAWidget& operator=(const CartridgeUAWidget&) = delete; CartridgeUAWidget& operator=(CartridgeUAWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartWDWidget.cxx000066400000000000000000000137251324334165500211730ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "CartWD.hxx" #include "PopUpWidget.hxx" #include "CartWDWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWDWidget::CartridgeWDWidget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeWD& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { string info = "This scheme has eight 1K slices, which can be mapped into four 1K " "segments in various combinations. Each 'bank' selects a predefined " "segment arrangement (indicated in square brackets)\n" "The last four banks swap in an extra 3 bytes from above the 8K " "cart boundary into the third (uppermost) segment at $3FC - $3FE\n\n" "64 bytes RAM @ $F000 - $F080\n" " $F000 - $F03F (R), $F040 - $F07F (W)\n"; int xpos = 10, ypos = addBaseInformation(myCart.mySize, "Wickstead Design", info, 12) + myLineHeight; VariantList items; VarList::push_back(items, "0 ($30) [0,0,1,2]", 0); VarList::push_back(items, "1 ($31) [0,1,3,2]", 1); VarList::push_back(items, "2 ($32) [4,5,6,7]", 2); VarList::push_back(items, "3 ($33) [7,4,3,2]", 3); VarList::push_back(items, "4 ($34) [0,0,6,7]", 4); VarList::push_back(items, "5 ($35) [0,1,7,6]", 5); VarList::push_back(items, "6 ($36) [3,2,4,5]", 6); VarList::push_back(items, "7 ($37) [6,0,5,1]", 7); VarList::push_back(items, "8 ($38) [0,0,1,2]", 8); VarList::push_back(items, "9 ($39) [0,1,3,2]", 9); VarList::push_back(items, "10 ($3A) [4,5,6,7]", 10); VarList::push_back(items, "11 ($3B) [7,4,3,2]", 11); VarList::push_back(items, "12 ($3C) [0,0,6,7*]", 12); VarList::push_back(items, "13 ($3D) [0,1,7,6*]", 13); VarList::push_back(items, "14 ($3E) [3,2,4,5*]", 14); VarList::push_back(items, "15 ($3F) [6,0,5,1*]", 15); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth("15 ($3F) [6,0,5,1*]"), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWDWidget::saveOldState() { myOldState.internalram.clear(); for(uInt32 i = 0; i < internalRamSize(); ++i) myOldState.internalram.push_back(myCart.myRAM[i]); myOldState.bank = myCart.getBank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWDWidget::loadConfig() { myBank->setSelectedIndex(myCart.getBank(), myCart.getBank() != myOldState.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWDWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeWDWidget::bankState() { ostringstream& buf = buffer(); static const char* const segments[] = { "[0,0,1,2]", "[0,1,3,2]", "[4,5,6,7]", "[7,4,3,2]", "[0,0,6,7]", "[0,1,7,6]", "[3,2,4,5]", "[6,0,5,1]", "[0,0,1,2]", "[0,1,3,2]", "[4,5,6,7]", "[7,4,3,2]", "[0,0,6,7*]", "[0,1,7,6*]", "[3,2,4,5*]", "[6,0,5,1*]" }; uInt16 bank = myCart.getBank(); buf << "Bank = " << std::dec << bank << ", segments = " << segments[bank]; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeWDWidget::internalRamSize() { return 64; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeWDWidget::internalRamRPort(int start) { return 0xF000 + start; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeWDWidget::internalRamDescription() { ostringstream desc; desc << "$F000 - $F03F used for Read Access\n" << "$F040 - $F07F used for Write Access"; return desc.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeWDWidget::internalRamOld(int start, int count) { myRamOld.clear(); for(int i = 0; i < count; ++i) myRamOld.push_back(myOldState.internalram[start + i]); return myRamOld; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& CartridgeWDWidget::internalRamCurrent(int start, int count) { myRamCurrent.clear(); for(int i = 0; i < count; ++i) myRamCurrent.push_back(myCart.myRAM[start + i]); return myRamCurrent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWDWidget::internalRamSetValue(int addr, uInt8 value) { myCart.myRAM[addr] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeWDWidget::internalRamGetValue(int addr) { return myCart.myRAM[addr]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeWDWidget::internalRamLabel(int addr) { CartDebug& dbg = instance().debugger().cartDebug(); return dbg.getLabel(addr + 0xF000, false); } stella-5.1.1/src/debugger/gui/CartWDWidget.hxx000066400000000000000000000046271324334165500212010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEWD_WIDGET_HXX #define CARTRIDGEWD_WIDGET_HXX class CartridgeWD; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeWDWidget : public CartDebugWidget { public: CartridgeWDWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeWD& cart); virtual ~CartridgeWDWidget() = default; private: CartridgeWD& myCart; PopUpWidget* myBank; struct CartState { ByteArray internalram; uInt16 bank; // Current banking layout }; CartState myOldState; enum { kBankChanged = 'bkCH' }; private: void saveOldState() override; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // start of functions for Cartridge RAM tab uInt32 internalRamSize() override; uInt32 internalRamRPort(int start) override; string internalRamDescription() override; const ByteArray& internalRamOld(int start, int count) override; const ByteArray& internalRamCurrent(int start, int count) override; void internalRamSetValue(int addr, uInt8 value) override; uInt8 internalRamGetValue(int addr) override; string internalRamLabel(int addr) override; // end of functions for Cartridge RAM tab // Following constructors and assignment operators not supported CartridgeWDWidget() = delete; CartridgeWDWidget(const CartridgeWDWidget&) = delete; CartridgeWDWidget(CartridgeWDWidget&&) = delete; CartridgeWDWidget& operator=(const CartridgeWDWidget&) = delete; CartridgeWDWidget& operator=(CartridgeWDWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CartX07Widget.cxx000066400000000000000000000073241324334165500212350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CartX07.hxx" #include "PopUpWidget.hxx" #include "CartX07Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeX07Widget::CartridgeX07Widget( GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeX07& cart) : CartDebugWidget(boss, lfont, nfont, x, y, w, h), myCart(cart) { uInt32 size = 16 * 4096; ostringstream info; info << "64K X07 cartridge, 16 4K banks\n" << "Startup bank = " << cart.myStartBank << "\n" << "Multiple hotspots, all below $1000\n" << "See documentation for further details\n"; // Eventually, we should query this from the debugger/disassembler for(uInt32 i = 0, offset = 0xFFC; i < 16; ++i, offset += 0x1000) { uInt16 start = (cart.myImage[offset+1] << 8) | cart.myImage[offset]; start -= start % 0x1000; info << "Bank " << std::dec << i << " @ $" << Common::Base::HEX4 << start << " - " << "$" << (start + 0xFFF) << "\n"; } int xpos = 10, ypos = addBaseInformation(size, "AtariAge / John Payson / Fred Quimby", info.str()) + myLineHeight; VariantList items; VarList::push_back(items, " 0"); VarList::push_back(items, " 1"); VarList::push_back(items, " 2"); VarList::push_back(items, " 3"); VarList::push_back(items, " 4"); VarList::push_back(items, " 5"); VarList::push_back(items, " 6"); VarList::push_back(items, " 7"); VarList::push_back(items, " 8"); VarList::push_back(items, " 9"); VarList::push_back(items, " 10"); VarList::push_back(items, " 11"); VarList::push_back(items, " 12"); VarList::push_back(items, " 13"); VarList::push_back(items, " 14"); VarList::push_back(items, " 15"); myBank = new PopUpWidget(boss, _font, xpos, ypos-2, _font.getStringWidth(" 15 "), myLineHeight, items, "Set bank ", _font.getStringWidth("Set bank "), kBankChanged); myBank->setTarget(this); addFocusWidget(myBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeX07Widget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); myBank->setSelectedIndex(myCart.getBank(), state.bank != oldstate.bank); CartDebugWidget::loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeX07Widget::handleCommand(CommandSender* sender, int cmd, int data, int id) { if(cmd == kBankChanged) { myCart.unlockBank(); myCart.bank(myBank->getSelected()); myCart.lockBank(); invalidate(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string CartridgeX07Widget::bankState() { ostringstream& buf = buffer(); buf << "Bank = " << std::dec << myCart.myCurrentBank; return buf.str(); } stella-5.1.1/src/debugger/gui/CartX07Widget.hxx000066400000000000000000000033601324334165500212360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEX07_WIDGET_HXX #define CARTRIDGEX07_WIDGET_HXX class CartridgeX07; class PopUpWidget; #include "CartDebugWidget.hxx" class CartridgeX07Widget : public CartDebugWidget { public: CartridgeX07Widget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, CartridgeX07& cart); virtual ~CartridgeX07Widget() = default; private: CartridgeX07& myCart; PopUpWidget* myBank; enum { kBankChanged = 'bkCH' }; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; string bankState() override; // Following constructors and assignment operators not supported CartridgeX07Widget() = delete; CartridgeX07Widget(const CartridgeX07Widget&) = delete; CartridgeX07Widget(CartridgeX07Widget&&) = delete; CartridgeX07Widget& operator=(const CartridgeX07Widget&) = delete; CartridgeX07Widget& operator=(CartridgeX07Widget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/ControllerWidget.hxx000066400000000000000000000042231324334165500221700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CONTROLLER_WIDGET_HXX #define CONTROLLER_WIDGET_HXX class GuiObject; class ButtonWidget; #include "Font.hxx" #include "Widget.hxx" #include "Console.hxx" #include "Command.hxx" class ControllerWidget : public Widget, public CommandSender { public: ControllerWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : Widget(boss, font, x, y, 16, 16), CommandSender(boss), myController(controller) { _w = 18 * font.getMaxCharWidth(); _h = 8 * font.getLineHeight(); } virtual ~ControllerWidget() = default; virtual void loadConfig() override { } protected: Controller& myController; protected: bool isLeftPort() { bool swappedPorts = instance().console().properties().get(Console_SwapPorts) == "YES"; return (myController.jack() == Controller::Left) ^ swappedPorts; } string getHeader() { return (isLeftPort() ? "Left (" : "Right (") + myController.name() + ")"; } private: virtual void handleCommand(CommandSender* sender, int cmd, int data, int id) override { } // Following constructors and assignment operators not supported ControllerWidget() = delete; ControllerWidget(const ControllerWidget&) = delete; ControllerWidget(ControllerWidget&&) = delete; ControllerWidget& operator=(const ControllerWidget&) = delete; ControllerWidget& operator=(ControllerWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/CpuWidget.cxx000066400000000000000000000252121324334165500205700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "OSystem.hxx" #include "GuiObject.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "CpuDebug.hxx" #include "Widget.hxx" #include "Font.hxx" #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "ToggleBitWidget.hxx" #include "CpuWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CpuWidget::CpuWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int max_w) : Widget(boss, lfont, x, y, 16, 16), CommandSender(boss) { const int fontWidth = lfont.getMaxCharWidth(), fontHeight = lfont.getFontHeight(), lineHeight = lfont.getLineHeight(); int xpos, ypos, lwidth; // Create a 1x1 grid with label for the PC register xpos = x; ypos = y; lwidth = 4 * fontWidth; new StaticTextWidget(boss, lfont, xpos, ypos+1, lwidth-2, fontHeight, "PC ", TextAlign::Left); myPCGrid = new DataGridWidget(boss, nfont, xpos + lwidth, ypos, 1, 1, 4, 16, Common::Base::F_16); myPCGrid->setTarget(this); myPCGrid->setID(kPCRegID); addFocusWidget(myPCGrid); // Create a read-only textbox containing the current PC label xpos += lwidth + myPCGrid->getWidth() + 10; myPCLabel = new EditTextWidget(boss, nfont, xpos, ypos, (max_w - xpos + x) - 10, fontHeight+1, ""); myPCLabel->setEditable(false, true); // Create a 1x4 grid with labels for the other CPU registers xpos = x + lwidth; ypos += myPCGrid->getHeight() + 1; myCpuGrid = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 2, 8, Common::Base::F_16); myCpuGrid->setTarget(this); myCpuGrid->setID(kCpuRegID); addFocusWidget(myCpuGrid); // Create a 1x4 grid with decimal and binary values for the other CPU registers xpos = x + lwidth + myPCGrid->getWidth() + 10; myCpuGridDecValue = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 3, 8, Common::Base::F_10); myCpuGridDecValue->setTarget(this); myCpuGridDecValue->setID(kCpuRegDecID); addFocusWidget(myCpuGridDecValue); xpos += myCpuGridDecValue->getWidth() + 5; myCpuGridBinValue = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 8, 8, Common::Base::F_2); myCpuGridBinValue->setTarget(this); myCpuGridBinValue->setID(kCpuRegBinID); addFocusWidget(myCpuGridBinValue); // Calculate real dimensions (_y will be calculated at the end) _w = lwidth + myPCGrid->getWidth() + myPCLabel->getWidth() + 20; // Create labels showing the source of data for SP/A/X/Y registers xpos += myCpuGridBinValue->getWidth() + 20; int src_y = ypos, src_w = (max_w - xpos + x) - 10; for(int i = 0; i < 4; ++i) { myCpuDataSrc[i] = new EditTextWidget(boss, nfont, xpos, src_y, src_w, fontHeight+1, ""); myCpuDataSrc[i]->setEditable(false, true); src_y += fontHeight+2; } int swidth = lfont.getStringWidth("Source Address"); new StaticTextWidget(boss, lfont, xpos, src_y + 4, src_w, fontHeight, swidth <= src_w ? "Source Address" : "Source Addr", TextAlign::Center); // Add labels for other CPU registers xpos = x; string labels[4] = { "SP ", "A ", "X ", "Y " }; for(int row = 0; row < 4; ++row) { new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 1, lwidth-2, fontHeight, labels[row], TextAlign::Left); } // Create a bitfield widget for changing the processor status xpos = x; ypos += 4*lineHeight + 2; new StaticTextWidget(boss, lfont, xpos, ypos+1, lwidth-2, fontHeight, "PS ", TextAlign::Left); myPSRegister = new ToggleBitWidget(boss, nfont, xpos+lwidth, ypos, 8, 1); myPSRegister->setTarget(this); addFocusWidget(myPSRegister); // Set the strings to be used in the PSRegister // We only do this once because it's the state that changes, not the strings const char* const offstr[] = { "n", "v", "-", "b", "d", "i", "z", "c" }; const char* const onstr[] = { "N", "V", "-", "B", "D", "I", "Z", "C" }; StringList off, on; for(int i = 0; i < 8; ++i) { off.push_back(offstr[i]); on.push_back(onstr[i]); } myPSRegister->setList(off, on); _h = ypos + myPSRegister->getHeight() - y; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuWidget::setOpsWidget(DataGridOpsWidget* w) { myPCGrid->setOpsWidget(w); myCpuGrid->setOpsWidget(w); myCpuGridDecValue->setOpsWidget(w); myCpuGridBinValue->setOpsWidget(w); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { int addr = -1, value = -1; CpuDebug& dbg = instance().debugger().cpuDebug(); switch(cmd) { case DataGridWidget::kItemDataChangedCmd: switch(id) { case kPCRegID: addr = myPCGrid->getSelectedAddr(); value = myPCGrid->getSelectedValue(); break; case kCpuRegID: addr = myCpuGrid->getSelectedAddr(); value = myCpuGrid->getSelectedValue(); break; case kCpuRegDecID: addr = myCpuGridDecValue->getSelectedAddr(); value = myCpuGridDecValue->getSelectedValue(); break; case kCpuRegBinID: addr = myCpuGridBinValue->getSelectedAddr(); value = myCpuGridBinValue->getSelectedValue(); break; } switch(addr) { case kPCRegAddr: { // Use the parser to set PC, since we want to propagate the // event the rest of the debugger widgets ostringstream command; command << "pc #" << value; instance().debugger().run(command.str()); break; } case kSPRegAddr: dbg.setSP(value); myCpuGrid->setValueInternal(0, value); myCpuGridDecValue->setValueInternal(0, value); myCpuGridBinValue->setValueInternal(0, value); break; case kARegAddr: dbg.setA(value); myCpuGrid->setValueInternal(1, value); myCpuGridDecValue->setValueInternal(1, value); myCpuGridBinValue->setValueInternal(1, value); break; case kXRegAddr: dbg.setX(value); myCpuGrid->setValueInternal(2, value); myCpuGridDecValue->setValueInternal(2, value); myCpuGridBinValue->setValueInternal(2, value); break; case kYRegAddr: dbg.setY(value); myCpuGrid->setValueInternal(3, value); myCpuGridDecValue->setValueInternal(3, value); myCpuGridBinValue->setValueInternal(3, value); break; } break; case ToggleWidget::kItemDataChangedCmd: { bool state = myPSRegister->getSelectedState(); switch(data) { case kPSRegN: dbg.setN(state); break; case kPSRegV: dbg.setV(state); break; case kPSRegB: dbg.setB(state); break; case kPSRegD: dbg.setD(state); break; case kPSRegI: dbg.setI(state); break; case kPSRegZ: dbg.setZ(state); break; case kPSRegC: dbg.setC(state); break; } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CpuWidget::loadConfig() { IntArray alist; IntArray vlist; BoolArray changed; // We push the enumerated items as addresses, and deal with the real // address in the callback (handleCommand) Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); CpuDebug& cpu = dbg.cpuDebug(); const CpuState& state = static_cast(cpu.getState()); const CpuState& oldstate = static_cast(cpu.getOldState()); // Add PC to its own DataGridWidget alist.push_back(kPCRegAddr); vlist.push_back(state.PC); changed.push_back(state.PC != oldstate.PC); myPCGrid->setList(alist, vlist, changed); // Add the other registers alist.clear(); vlist.clear(); changed.clear(); alist.push_back(kSPRegAddr); alist.push_back(kARegAddr); alist.push_back(kXRegAddr); alist.push_back(kYRegAddr); // And now fill the values vlist.push_back(state.SP); vlist.push_back(state.A); vlist.push_back(state.X); vlist.push_back(state.Y); // Figure out which items have changed changed.push_back(state.SP != oldstate.SP); changed.push_back(state.A != oldstate.A); changed.push_back(state.X != oldstate.X); changed.push_back(state.Y != oldstate.Y); // Finally, update the register list myCpuGrid->setList(alist, vlist, changed); myCpuGridDecValue->setList(alist, vlist, changed); myCpuGridBinValue->setList(alist, vlist, changed); // Update the data sources for the SP/A/X/Y registers const string& srcS = state.srcS < 0 ? "IMM" : cart.getLabel(state.srcS, true); myCpuDataSrc[0]->setText((srcS != EmptyString ? srcS : Common::Base::toString(state.srcS)), state.srcS != oldstate.srcS); const string& srcA = state.srcA < 0 ? "IMM" : cart.getLabel(state.srcA, true); myCpuDataSrc[1]->setText((srcA != EmptyString ? srcA : Common::Base::toString(state.srcA)), state.srcA != oldstate.srcA); const string& srcX = state.srcX < 0 ? "IMM" : cart.getLabel(state.srcX, true); myCpuDataSrc[2]->setText((srcX != EmptyString ? srcX : Common::Base::toString(state.srcX)), state.srcX != oldstate.srcX); const string& srcY = state.srcY < 0 ? "IMM" : cart.getLabel(state.srcY, true); myCpuDataSrc[3]->setText((srcY != EmptyString ? srcY : Common::Base::toString(state.srcY)), state.srcY != oldstate.srcY); // Update the PS register booleans changed.clear(); for(uInt32 i = 0; i < state.PSbits.size(); ++i) changed.push_back(state.PSbits[i] != oldstate.PSbits[i]); myPSRegister->setState(state.PSbits, changed); myPCLabel->setText(dbg.cartDebug().getLabel(state.PC, true)); } stella-5.1.1/src/debugger/gui/CpuWidget.hxx000066400000000000000000000044361324334165500206020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CPU_WIDGET_HXX #define CPU_WIDGET_HXX class GuiObject; class ButtonWidget; class DataGridWidget; class DataGridOpsWidget; class EditTextWidget; class ToggleBitWidget; #include "Widget.hxx" #include "Command.hxx" class CpuWidget : public Widget, public CommandSender { public: CpuWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int max_w); virtual ~CpuWidget() = default; void setOpsWidget(DataGridOpsWidget* w); void loadConfig() override; private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: // ID's for the various widgets // We need ID's, since there are more than one of several types of widgets enum { kPCRegID, kCpuRegID, kCpuRegDecID, kCpuRegBinID }; enum { kPCRegAddr, kSPRegAddr, kARegAddr, kXRegAddr, kYRegAddr }; enum { kPSRegN = 0, kPSRegV = 1, kPSRegB = 3, kPSRegD = 4, kPSRegI = 5, kPSRegZ = 6, kPSRegC = 7 }; DataGridWidget* myPCGrid; DataGridWidget* myCpuGrid; DataGridWidget* myCpuGridDecValue; DataGridWidget* myCpuGridBinValue; EditTextWidget* myCpuDataSrc[4]; ToggleBitWidget* myPSRegister; EditTextWidget* myPCLabel; private: // Following constructors and assignment operators not supported CpuWidget() = delete; CpuWidget(const CpuWidget&) = delete; CpuWidget(CpuWidget&&) = delete; CpuWidget& operator=(const CpuWidget&) = delete; CpuWidget& operator=(CpuWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/DataGridOpsWidget.cxx000066400000000000000000000073531324334165500222100ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Font.hxx" #include "DataGridOpsWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DataGridOpsWidget::DataGridOpsWidget(GuiObject* boss, const GUI::Font& font, int x, int y) : Widget(boss, font, x, y, 16, 16), CommandSender(boss), _zeroButton(nullptr), _invButton(nullptr), _negButton(nullptr), _incButton(nullptr), _decButton(nullptr), _shiftLeftButton(nullptr), _shiftRightButton(nullptr) { const int bwidth = _font.getMaxCharWidth() * 4+2, bheight = _font.getFontHeight() + 3, space = 4; int xpos, ypos; // Create operations buttons xpos = x; ypos = y; _zeroButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "0", kDGZeroCmd); ypos += bheight + space; _invButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "Inv", kDGInvertCmd); ypos += bheight + space; _incButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "++", kDGIncCmd); ypos += bheight + space; _shiftLeftButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "<<", kDGShiftLCmd); // Move to next column, skip a row xpos = x + bwidth + space; ypos = y + bheight + space; _negButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "Neg", kDGNegateCmd); ypos += bheight + space; _decButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "--", kDGDecCmd); ypos += bheight + space; _shiftRightButton = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, ">>", kDGShiftRCmd); // Calculate real dimensions _w = 2 * (bwidth+space); _h = 4 * (bheight+space); // We don't enable the buttons until the DataGridWidget is attached // Don't call setEnabled(false), since that does an immediate redraw _zeroButton->clearFlags(WIDGET_ENABLED); _invButton->clearFlags(WIDGET_ENABLED); _negButton->clearFlags(WIDGET_ENABLED); _incButton->clearFlags(WIDGET_ENABLED); _decButton->clearFlags(WIDGET_ENABLED); _shiftLeftButton->clearFlags(WIDGET_ENABLED); _shiftRightButton->clearFlags(WIDGET_ENABLED); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridOpsWidget::setTarget(CommandReceiver* target) { _zeroButton->setTarget(target); _invButton->setTarget(target); _negButton->setTarget(target); _incButton->setTarget(target); _decButton->setTarget(target); _shiftLeftButton->setTarget(target); _shiftRightButton->setTarget(target); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridOpsWidget::setEnabled(bool e) { _zeroButton->setEnabled(e); _invButton->setEnabled(e); _negButton->setEnabled(e); _incButton->setEnabled(e); _decButton->setEnabled(e); _shiftLeftButton->setEnabled(e); _shiftRightButton->setEnabled(e); } stella-5.1.1/src/debugger/gui/DataGridOpsWidget.hxx000066400000000000000000000035541324334165500222140ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DATA_GRID_OPS_WIDGET_HXX #define DATA_GRID_OPS_WIDGET_HXX #include "Widget.hxx" #include "Command.hxx" // DataGridWidget operations enum { kDGZeroCmd = 'DGze', kDGInvertCmd = 'DGiv', kDGNegateCmd = 'DGng', kDGIncCmd = 'DGic', kDGDecCmd = 'DGdc', kDGShiftLCmd = 'DGls', kDGShiftRCmd = 'DGrs' }; class DataGridOpsWidget : public Widget, public CommandSender { public: DataGridOpsWidget(GuiObject* boss, const GUI::Font& font, int x, int y); virtual ~DataGridOpsWidget() = default; void setTarget(CommandReceiver* target); void setEnabled(bool e); private: ButtonWidget* _zeroButton; ButtonWidget* _invButton; ButtonWidget* _negButton; ButtonWidget* _incButton; ButtonWidget* _decButton; ButtonWidget* _shiftLeftButton; ButtonWidget* _shiftRightButton; private: // Following constructors and assignment operators not supported DataGridOpsWidget() = delete; DataGridOpsWidget(const DataGridOpsWidget&) = delete; DataGridOpsWidget(DataGridOpsWidget&&) = delete; DataGridOpsWidget& operator=(const DataGridOpsWidget&) = delete; DataGridOpsWidget& operator=(DataGridOpsWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/DataGridWidget.cxx000066400000000000000000000523121324334165500215210ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Widget.hxx" #include "Dialog.hxx" #include "Font.hxx" #include "Debugger.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "DataGridWidget.hxx" #include "DataGridOpsWidget.hxx" #include "RamWidget.hxx" #include "ScrollBarWidget.hxx" #include "StellaKeys.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DataGridWidget::DataGridWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows, int colchars, int bits, Common::Base::Format base, bool useScrollbar) : EditableWidget(boss, font, x, y, cols*(colchars * font.getMaxCharWidth() + 8) + 1, font.getLineHeight()*rows + 1), _rows(rows), _cols(cols), _currentRow(0), _currentCol(0), _rowHeight(font.getLineHeight()), _colWidth(colchars * font.getMaxCharWidth() + 8), _bits(bits), _crossGrid(false), _base(base), _selectedItem(0), _currentKeyDown(KBDK_UNKNOWN), _opsWidget(nullptr), _scrollBar(nullptr) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANTS_RAWDATA; _editMode = false; // The item is selected, thus _bgcolor is used to draw the caret and // _textcolorhi to erase it _caretInverse = true; // Make sure all lists contain some default values _hiliteList.clear(); int size = _rows * _cols; while(size--) { _addrList.push_back(0); _valueList.push_back(0); _valueStringList.push_back(""); _changedList.push_back(0); _hiliteList.push_back(false); } // Set lower and upper bounds to sane values setRange(0, 1 << bits); // Add a scrollbar if necessary if(useScrollbar) { _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h); _scrollBar->setTarget(this); _scrollBar->_numEntries = 1; _scrollBar->_currentPos = 0; _scrollBar->_entriesPerPage = 1; _scrollBar->_wheel_lines = 1; } // Add filtering EditableWidget::TextFilter f; switch(base) { case Common::Base::F_16: case Common::Base::F_16_1: case Common::Base::F_16_2: case Common::Base::F_16_4: case Common::Base::F_16_8: setTextFilter([](char c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); }); break; case Common::Base::F_10: setTextFilter([](char c) { return (c >= '0' && c <= '9'); }); break; case Common::Base::F_2: case Common::Base::F_2_8: case Common::Base::F_2_16: setTextFilter([](char c) { return (c >= '0' && c <= '1'); }); break; default: break; // no filtering for now } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setList(const IntArray& alist, const IntArray& vlist, const BoolArray& changed) { /* cerr << "alist.size() = " << alist.size() << ", vlist.size() = " << vlist.size() << ", changed.size() = " << changed.size() << ", _rows*_cols = " << _rows * _cols << endl << endl; */ int size = int(vlist.size()); // assume the alist is the same size assert(size == _rows * _cols); _addrList.clear(); _valueList.clear(); _valueStringList.clear(); _changedList.clear(); _addrList = alist; _valueList = vlist; _changedList = changed; // An efficiency thing string temp; for(int i = 0; i < size; ++i) _valueStringList.push_back(Common::Base::toString(_valueList[i], _base)); /* cerr << "_addrList.size() = " << _addrList.size() << ", _valueList.size() = " << _valueList.size() << ", _changedList.size() = " << _changedList.size() << ", _valueStringList.size() = " << _valueStringList.size() << ", _rows*_cols = " << _rows * _cols << endl << endl; */ enableEditMode(false); // Send item selected signal for starting with cell 0 sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setList(int a, int v, bool c) { IntArray alist, vlist; BoolArray changed; alist.push_back(a); vlist.push_back(v); changed.push_back(c); setList(alist, vlist, changed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setList(int a, int v) { IntArray alist, vlist; BoolArray changed; alist.push_back(a); vlist.push_back(v); bool diff = _addrList.size() == 1 ? getSelectedValue() != v : false; changed.push_back(diff); setList(alist, vlist, changed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setEditable(bool editable, bool hiliteBG) { // Override parent method; enable hilite when widget is not editable EditableWidget::setEditable(editable, hiliteBG); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setHiliteList(const BoolArray& hilitelist) { assert(hilitelist.size() == uInt32(_rows * _cols)); _hiliteList.clear(); _hiliteList = hilitelist; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setNumRows(int rows) { if(_scrollBar) _scrollBar->_numEntries = rows; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setSelectedValue(int value) { setValue(_selectedItem, value, _valueList[_selectedItem] != value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setValue(int position, int value) { setValue(position, value, _valueList[position] != value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setValueInternal(int position, int value, bool changed) { setValue(position, value, changed, false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setValue(int position, int value, bool changed, bool emitSignal) { if(position >= 0 && uInt32(position) < _valueList.size()) { // Correctly format the data for viewing editString() = Common::Base::toString(value, _base); _valueStringList[position] = editString(); _changedList[position] = changed; _valueList[position] = value; if(emitSignal) sendCommand(DataGridWidget::kItemDataChangedCmd, position, _id); setDirty(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::setRange(int lower, int upper) { _lowerBound = std::max(0, lower); _upperBound = std::min(1 << _bits, upper); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { if (!isEnabled()) return; // First check whether the selection changed int newSelectedItem; newSelectedItem = findItem(x, y); if (newSelectedItem > int(_valueList.size()) - 1) newSelectedItem = -1; if (_selectedItem != newSelectedItem) { if (_editMode) abortEditMode(); _selectedItem = newSelectedItem; _currentRow = _selectedItem / _cols; _currentCol = _selectedItem - (_currentRow * _cols); sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id); setDirty(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { // If this was a double click and the mouse is still over the selected item, // send the double click command if (clickCount == 2 && (_selectedItem == findItem(x, y))) { sendCommand(DataGridWidget::kItemDoubleClickedCmd, _selectedItem, _id); // Start edit mode if(isEditable() && !_editMode) startEditMode(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::handleMouseWheel(int x, int y, int direction) { if(_scrollBar) _scrollBar->handleMouseWheel(x, y, direction); else if(isEditable()) { if(direction > 0) decrementCell(); else if(direction < 0) incrementCell(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int DataGridWidget::findItem(int x, int y) { int row = (y - 1) / _rowHeight; if(row >= _rows) row = _rows - 1; int col = x / _colWidth; if(col >= _cols) col = _cols - 1; return row * _cols + col; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DataGridWidget::handleText(char text) { if(_editMode) { // Class EditableWidget handles all text editing related key presses for us return EditableWidget::handleText(text); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DataGridWidget::handleKeyDown(StellaKey key, StellaMod mod) { // Ignore all mod keys if(StellaModTest::isControl(mod) || StellaModTest::isAlt(mod)) return true; bool handled = true; bool dirty = false; if (_editMode) { // Class EditableWidget handles all single-key presses for us handled = EditableWidget::handleKeyDown(key, mod); } else { switch(key) { case KBDK_RETURN: case KBDK_KP_ENTER: if (_currentRow >= 0 && _currentCol >= 0) { dirty = true; _selectedItem = _currentRow*_cols + _currentCol; startEditMode(); } break; case KBDK_UP: if (_currentRow > 0) { _currentRow--; dirty = true; } else if(_currentCol > 0) { _currentRow = _rows - 1; _currentCol--; dirty = true; } break; case KBDK_DOWN: if (_currentRow < int(_rows) - 1) { _currentRow++; dirty = true; } else if(_currentCol < int(_cols) - 1) { _currentRow = 0; _currentCol++; dirty = true; } break; case KBDK_LEFT: if (_currentCol > 0) { _currentCol--; dirty = true; } else if(_currentRow > 0) { _currentCol = _cols - 1; _currentRow--; dirty = true; } break; case KBDK_RIGHT: if (_currentCol < int(_cols) - 1) { _currentCol++; dirty = true; } else if(_currentRow < int(_rows) - 1) { _currentCol = 0; _currentRow++; dirty = true; } break; case KBDK_PAGEUP: if(StellaModTest::isShift(mod) && _scrollBar) handleMouseWheel(0, 0, -1); else if (_currentRow > 0) { _currentRow = 0; dirty = true; } break; case KBDK_PAGEDOWN: if(StellaModTest::isShift(mod) && _scrollBar) handleMouseWheel(0, 0, +1); else if (_currentRow < int(_rows) - 1) { _currentRow = _rows - 1; dirty = true; } break; case KBDK_HOME: if (_currentCol > 0) { _currentCol = 0; dirty = true; } break; case KBDK_END: if (_currentCol < int(_cols) - 1) { _currentCol = _cols - 1; dirty = true; } break; case KBDK_N: // negate if(isEditable()) negateCell(); break; case KBDK_I: // invert if(isEditable()) invertCell(); break; case KBDK_MINUS: // decrement case KBDK_KP_MINUS: if(isEditable()) decrementCell(); break; case KBDK_EQUALS: // increment case KBDK_KP_PLUS: if(isEditable()) incrementCell(); break; case KBDK_COMMA: // shift left if(isEditable()) lshiftCell(); break; case KBDK_PERIOD: // shift right if(isEditable()) rshiftCell(); break; case KBDK_Z: // zero if(isEditable()) zeroCell(); break; default: handled = false; } } if (dirty) { int oldItem = _selectedItem; _selectedItem = _currentRow*_cols + _currentCol; if(_selectedItem != oldItem) sendCommand(DataGridWidget::kSelectionChangedCmd, _selectedItem, _id); setDirty(); } _currentKeyDown = key; return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool DataGridWidget::handleKeyUp(StellaKey key, StellaMod mod) { if (key == _currentKeyDown) _currentKeyDown = KBDK_UNKNOWN; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::receivedFocusWidget() { // Enable the operations widget and make it send its signals here if(_opsWidget) { _opsWidget->setEnabled(true); _opsWidget->setTarget(this); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::lostFocusWidget() { enableEditMode(false); // Disable the operations widget if(_opsWidget) _opsWidget->setEnabled(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kSetPositionCmd: // Chain access; pass to parent sendCommand(GuiObject::kSetPositionCmd, data, _id); break; case kDGZeroCmd: zeroCell(); break; case kDGInvertCmd: invertCell(); break; case kDGNegateCmd: negateCell(); break; case kDGIncCmd: incrementCell(); break; case kDGDecCmd: decrementCell(); break; case kDGShiftLCmd: lshiftCell(); break; case kDGShiftRCmd: rshiftCell(); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); int row, col; // Draw the internal grid and labels int linewidth = _cols * _colWidth; #ifndef FLAT_UI for (row = 0; row <= _rows; row++) s.hLine(_x, _y + (row * _rowHeight), _x + linewidth, kColor); int lineheight = _rows * _rowHeight; for (col = 0; col <= _cols; col++) s.vLine(_x + (col * _colWidth), _y, _y + lineheight, kColor); #else s.frameRect(_x, _y, _w, _h, kColor); for(row = 1; row <= _rows-1; row++) s.hLine(_x+1, _y + (row * _rowHeight), _x + linewidth-1, kBGColorLo); int lineheight = _rows * _rowHeight; for(col = 1; col <= _cols-1; col++) s.vLine(_x + (col * _colWidth), _y+1, _y + lineheight-1, kBGColorLo); #endif // Draw the list items for (row = 0; row < _rows; row++) { for (col = 0; col < _cols; col++) { int x = _x + 4 + (col * _colWidth); int y = _y + 2 + (row * _rowHeight); int pos = row*_cols + col; uInt32 textColor = kTextColor; // Draw the selected item inverted, on a highlighted background. if (_currentRow == row && _currentCol == col && _hasFocus && !_editMode) { s.fillRect(x - 4, y - 2, _colWidth+1, _rowHeight+1, kTextColorHi); textColor = kTextColorInv; } if (_selectedItem == pos && _editMode) { adjustOffset(); s.drawString(_font, editString(), x, y, _colWidth, textColor, TextAlign::Left, -_editScrollOffset, false); } else { if(_changedList[pos]) { s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, kDbgChangedColor); if(_hiliteList[pos]) textColor = kDbgColorHi; else textColor = kDbgChangedTextColor; } else if(_hiliteList[pos]) textColor = kDbgColorHi; s.drawString(_font, _valueStringList[pos], x, y, _colWidth, textColor); } } } // Only draw the caret while editing, and if it's in the current viewport if(_editMode) drawCaret(); // Draw the scrollbar if(_scrollBar) _scrollBar->recalc(); // takes care of the draw // Cross out the grid? if(_crossGrid) for(row = 1; row < 4; ++row) s.hLine(_x, _y + (row * lineheight/4), _x + linewidth, kColor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect DataGridWidget::getEditRect() const { GUI::Rect r(1, 0, _colWidth, _rowHeight); const int rowoffset = _currentRow * _rowHeight; const int coloffset = _currentCol * _colWidth + 4; r.top += rowoffset; r.bottom += rowoffset; r.left += coloffset; r.right += coloffset - 5; return r; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int DataGridWidget::getWidth() const { return _w + (_scrollBar ? kScrollBarWidth : 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::startEditMode() { if (isEditable() && !_editMode && _selectedItem >= 0) { enableEditMode(true); setText("", true); // Erase current entry when starting editing } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::endEditMode() { if (!_editMode) return; enableEditMode(false); // Update the both the string representation and the real data if(editString().size() > 0 && !(editString()[0] == '$' || editString()[0] == '#' || editString()[0] == '\\')) { switch(_base) { case Common::Base::F_16: case Common::Base::F_16_1: case Common::Base::F_16_2: case Common::Base::F_16_4: case Common::Base::F_16_8: editString().insert(0, 1, '$'); break; case Common::Base::F_2: case Common::Base::F_2_8: case Common::Base::F_2_16: editString().insert(0, 1, '\\'); break; case Common::Base::F_10: editString().insert(0, 1, '#'); break; case Common::Base::F_DEFAULT: default: // TODO - properly handle all other cases break; } } int value = instance().debugger().stringToValue(editString()); if(value < _lowerBound || value >= _upperBound) { abortEditMode(); return; } setSelectedValue(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::abortEditMode() { if(_editMode) { // Undo any changes made assert(_selectedItem >= 0); enableEditMode(false); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::negateCell() { int mask = (1 << _bits) - 1; int value = getSelectedValue(); if(mask != _upperBound - 1) // ignore when values aren't byte-aligned return; value = ((~value) + 1) & mask; setSelectedValue(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::invertCell() { int mask = (1 << _bits) - 1; int value = getSelectedValue(); if(mask != _upperBound - 1) // ignore when values aren't byte-aligned return; value = ~value & mask; setSelectedValue(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::decrementCell() { int mask = (1 << _bits) - 1; int value = getSelectedValue(); if(value <= _lowerBound) // take care of wrap-around value = _upperBound; value = (value - 1) & mask; setSelectedValue(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::incrementCell() { int mask = (1 << _bits) - 1; int value = getSelectedValue(); if(value >= _upperBound - 1) // take care of wrap-around value = _lowerBound - 1; value = (value + 1) & mask; setSelectedValue(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::lshiftCell() { int mask = (1 << _bits) - 1; int value = getSelectedValue(); if(mask != _upperBound - 1) // ignore when values aren't byte-aligned return; value = (value << 1) & mask; setSelectedValue(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::rshiftCell() { int mask = (1 << _bits) - 1; int value = getSelectedValue(); if(mask != _upperBound - 1) // ignore when values aren't byte-aligned return; value = (value >> 1) & mask; setSelectedValue(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DataGridWidget::zeroCell() { setSelectedValue(0); } stella-5.1.1/src/debugger/gui/DataGridWidget.hxx000066400000000000000000000115541324334165500215310ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DATA_GRID_WIDGET_HXX #define DATA_GRID_WIDGET_HXX class DataGridOpsWidget; class ScrollBarWidget; class CommandSender; #include "Widget.hxx" #include "EditableWidget.hxx" #include "Base.hxx" #include "Rect.hxx" /* DataGridWidget */ class DataGridWidget : public EditableWidget { public: // Commands emitted by this commandsender enum { kItemDoubleClickedCmd = 'DGdb', kItemActivatedCmd = 'DGac', kItemDataChangedCmd = 'DGch', kSelectionChangedCmd = 'DGsc' }; public: DataGridWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows, int colchars, int bits, Common::Base::Format format = Common::Base::F_DEFAULT, bool useScrollbar = false); virtual ~DataGridWidget() = default; void setList(const IntArray& alist, const IntArray& vlist, const BoolArray& changed); /** Convenience method for when the datagrid contains only one value */ void setList(int a, int v, bool changed); void setList(int a, int v); // automatically calculate if changed void setEditable(bool editable, bool hiliteBG = true) override; void setHiliteList(const BoolArray& hilitelist); void setNumRows(int rows); /** Set value at current selection point */ void setSelectedValue(int value); /** Set value at given position */ void setValue(int position, int value); /** Set value at given position, do not emit any signals */ void setValueInternal(int position, int value, bool changed = true); /** Set value at given position, manually specifying if the value changed */ void setValue(int position, int value, bool changed, bool emitSignal = true); int getSelectedAddr() const { return _addrList[_selectedItem]; } int getSelectedValue() const { return _valueList[_selectedItem]; } void setRange(int lower, int upper); bool wantsFocus() const override { return true; } // Account for the extra width of embedded scrollbar int getWidth() const override; int colWidth() { return _colWidth; } void setOpsWidget(DataGridOpsWidget* w) { _opsWidget = w; } void setCrossed(bool enable) { _crossGrid = enable; } protected: void drawWidget(bool hilite) override; int findItem(int x, int y); void startEditMode() override; void endEditMode() override; void abortEditMode() override; GUI::Rect getEditRect() const override; void receivedFocusWidget() override; void lostFocusWidget() override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; bool handleText(char text) override; bool handleKeyDown(StellaKey key, StellaMod mod) override; bool handleKeyUp(StellaKey key, StellaMod mod) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; protected: int _rows; int _cols; int _currentRow; int _currentCol; int _rowHeight; int _colWidth; int _bits; int _lowerBound; int _upperBound; bool _crossGrid; Common::Base::Format _base; IntArray _addrList; IntArray _valueList; StringList _valueStringList; BoolArray _changedList; BoolArray _hiliteList; bool _editMode; int _selectedItem; StellaKey _currentKeyDown; string _backupString; DataGridOpsWidget* _opsWidget; ScrollBarWidget* _scrollBar; private: /** Common operations on the currently selected cell */ void negateCell(); void invertCell(); void decrementCell(); void incrementCell(); void lshiftCell(); void rshiftCell(); void zeroCell(); void enableEditMode(bool state) { _editMode = state; } private: // Following constructors and assignment operators not supported DataGridWidget() = delete; DataGridWidget(const DataGridWidget&) = delete; DataGridWidget(DataGridWidget&&) = delete; DataGridWidget& operator=(const DataGridWidget&) = delete; DataGridWidget& operator=(DataGridWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/DebuggerDialog.cxx000066400000000000000000000452621324334165500215500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Cart.hxx" #include "Widget.hxx" #include "Dialog.hxx" #include "Settings.hxx" #include "StellaKeys.hxx" #include "EventHandler.hxx" #include "TabWidget.hxx" #include "TiaInfoWidget.hxx" #include "TiaOutputWidget.hxx" #include "TiaZoomWidget.hxx" #include "AudioWidget.hxx" #include "PromptWidget.hxx" #include "CpuWidget.hxx" #include "RiotRamWidget.hxx" #include "RiotWidget.hxx" #include "RomWidget.hxx" #include "TiaWidget.hxx" #include "CartDebugWidget.hxx" #include "CartRamWidget.hxx" #include "DataGridOpsWidget.hxx" #include "EditTextWidget.hxx" #include "MessageBox.hxx" #include "Debugger.hxx" #include "DebuggerParser.hxx" #include "ConsoleFont.hxx" #include "ConsoleBFont.hxx" #include "ConsoleMediumFont.hxx" #include "ConsoleMediumBFont.hxx" #include "StellaMediumFont.hxx" #include "OptionsDialog.hxx" #include "DebuggerDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DebuggerDialog::DebuggerDialog(OSystem& osystem, DialogContainer& parent, int x, int y, int w, int h) : Dialog(osystem, parent, x, y, w, h), myTab(nullptr), myRomTab(nullptr), myFatalError(nullptr) { createFont(); // Font is sized according to available space addTiaArea(); addTabArea(); addStatusArea(); addRomArea(); // Inform the TIA output widget about its associated zoom widget myTiaOutput->setZoomWidget(myTiaZoom); myOptions = make_unique(osystem, parent, this, w, h, OptionsDialog::debugger); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::loadConfig() { myTab->loadConfig(); myTiaInfo->loadConfig(); myTiaOutput->loadConfig(); myTiaZoom->loadConfig(); myCpu->loadConfig(); myRam->loadConfig(); myRomTab->loadConfig(); myMessageBox->setText(""); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod) { if(key == KBDK_GRAVE && !StellaModTest::isShift(mod)) { // Swallow backtick, so we don't see it when exiting the debugger instance().eventHandler().enableTextEvents(false); } else if(key == KBDK_F12) { instance().debugger().parser().run("savesnap"); return; } else if(StellaModTest::isAlt(mod) && !StellaModTest::isControl(mod)) { switch(key) { case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states if(StellaModTest::isShift(mod)) doRewind10(); else doRewind(); return; case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states if(StellaModTest::isShift(mod)) doUnwind10(); else doUnwind(); return; case KBDK_DOWN: // Alt-down rewinds to start of list doRewindAll(); return; case KBDK_UP: // Alt-up rewinds to end of list doUnwindAll(); return; default: break; } } else if(StellaModTest::isControl(mod)) { switch(key) { #if 0 case KBDK_R: if(StellaModTest::isAlt(mod)) doRewindAll(); else if(StellaModTest::isShift(mod)) doRewind10(); else doRewind(); return; case KBDK_Y: if(StellaModTest::isAlt(mod)) doUnwindAll(); else if(StellaModTest::isShift(mod)) doUnwind10(); else doUnwind(); return; #endif case KBDK_S: doStep(); return; case KBDK_T: doTrace(); return; case KBDK_L: doScanlineAdvance(); return; case KBDK_F: doAdvance(); return; default: break; } } Dialog::handleKeyDown(key, mod); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { // We reload the tabs in the cases where the actions could possibly // change their contents switch(cmd) { case kDDStepCmd: doStep(); break; case kDDTraceCmd: doTrace(); break; case kDDAdvCmd: doAdvance(); break; case kDDSAdvCmd: doScanlineAdvance(); break; case kDDRewindCmd: doRewind(); break; case kDDUnwindCmd: doUnwind(); break; case kDDExitCmd: doExitDebugger(); break; case kDDExitFatalCmd: doExitRom(); break; case kDDOptionsCmd: myOptions->open(); loadConfig(); break; case RomWidget::kInvalidateListing: // Only do a full redraw if the disassembly tab is actually showing myRom->invalidate(myRomTab->getActiveTab() == 0); break; default: Dialog::handleCommand(sender, cmd, data, id); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doStep() { instance().debugger().parser().run("step"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doTrace() { instance().debugger().parser().run("trace"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doAdvance() { instance().debugger().parser().run("frame #1"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doScanlineAdvance() { instance().debugger().parser().run("scanline #1"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doRewind() { instance().debugger().parser().run("rewind"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doUnwind() { instance().debugger().parser().run("unwind"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doRewind10() { instance().debugger().parser().run("rewind #10"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doUnwind10() { instance().debugger().parser().run("unwind #10"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doRewindAll() { instance().debugger().parser().run("rewind #1000"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doUnwindAll() { instance().debugger().parser().run("unwind #1000"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doExitDebugger() { instance().debugger().parser().run("run"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::doExitRom() { instance().debugger().parser().run("exitrom"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::createFont() { string fontSize = instance().settings().getString("dbg.fontsize"); int fontStyle = instance().settings().getInt("dbg.fontstyle"); if(fontSize == "large") { // Large font doesn't use fontStyle at all myLFont = make_unique(GUI::stellaMediumDesc); myNFont = make_unique(GUI::stellaMediumDesc); } else if(fontSize == "medium") { switch(fontStyle) { case 1: myLFont = make_unique(GUI::consoleMediumBDesc); myNFont = make_unique(GUI::consoleMediumDesc); break; case 2: myLFont = make_unique(GUI::consoleMediumDesc); myNFont = make_unique(GUI::consoleMediumBDesc); break; case 3: myLFont = make_unique(GUI::consoleMediumBDesc); myNFont = make_unique(GUI::consoleMediumBDesc); break; default: // default to zero myLFont = make_unique(GUI::consoleMediumDesc); myNFont = make_unique(GUI::consoleMediumDesc); break; }; } else { switch(fontStyle) { case 1: myLFont = make_unique(GUI::consoleBDesc); myNFont = make_unique(GUI::consoleDesc); break; case 2: myLFont = make_unique(GUI::consoleDesc); myNFont = make_unique(GUI::consoleBDesc); break; case 3: myLFont = make_unique(GUI::consoleBDesc); myNFont = make_unique(GUI::consoleBDesc); break; default: // default to zero myLFont = make_unique(GUI::consoleDesc); myNFont = make_unique(GUI::consoleDesc); break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::showFatalMessage(const string& msg) { myFatalError = make_unique(this, *myLFont, msg, _w/2, _h/2, kDDExitFatalCmd, "Exit ROM", "Continue"); myFatalError->show(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::addTiaArea() { const GUI::Rect& r = getTiaBounds(); myTiaOutput = new TiaOutputWidget(this, *myNFont, r.left, r.top, r.width(), r.height()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::addTabArea() { const GUI::Rect& r = getTabBounds(); const int vBorder = 4; // The tab widget // Since there are two tab widgets in this dialog, we specifically // assign an ID of 0 myTab = new TabWidget(this, *myLFont, r.left, r.top + vBorder, r.width(), r.height() - vBorder); myTab->setID(0); addTabWidget(myTab); const int widWidth = r.width() - vBorder; const int widHeight = r.height() - myTab->getTabHeight() - vBorder - 4; int tabID; // The Prompt/console tab #ifndef FLAT_UI tabID = myTab->addTab(" Prompt "); myPrompt = new PromptWidget(myTab, *myNFont, 2, 2, widWidth, widHeight); #else tabID = myTab->addTab("Prompt"); myPrompt = new PromptWidget(myTab, *myNFont, 2, 2, widWidth - 4, widHeight); #endif myTab->setParentWidget(tabID, myPrompt); addToFocusList(myPrompt->getFocusList(), myTab, tabID); // The TIA tab tabID = myTab->addTab("TIA"); TiaWidget* tia = new TiaWidget(myTab, *myLFont, *myNFont, 2, 2, widWidth, widHeight); myTab->setParentWidget(tabID, tia); addToFocusList(tia->getFocusList(), myTab, tabID); // The input/output tab (includes RIOT and INPTx from TIA) tabID = myTab->addTab("I/O"); RiotWidget* riot = new RiotWidget(myTab, *myLFont, *myNFont, 2, 2, widWidth, widHeight); myTab->setParentWidget(tabID, riot); addToFocusList(riot->getFocusList(), myTab, tabID); // The Audio tab tabID = myTab->addTab("Audio"); AudioWidget* aud = new AudioWidget(myTab, *myLFont, *myNFont, 2, 2, widWidth, widHeight); myTab->setParentWidget(tabID, aud); addToFocusList(aud->getFocusList(), myTab, tabID); myTab->setActiveTab(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::addStatusArea() { const int lineHeight = myLFont->getLineHeight(); const GUI::Rect& r = getStatusBounds(); int xpos, ypos; xpos = r.left; ypos = r.top; myTiaInfo = new TiaInfoWidget(this, *myLFont, *myNFont, xpos, ypos, r.width()); ypos += myTiaInfo->getHeight() + 10; myTiaZoom = new TiaZoomWidget(this, *myNFont, xpos+10, ypos, r.width()-10, r.height()-lineHeight-ypos-10); addToFocusList(myTiaZoom->getFocusList()); xpos += 10; ypos += myTiaZoom->getHeight() + 10; myMessageBox = new EditTextWidget(this, *myLFont, xpos, ypos, myTiaZoom->getWidth(), myLFont->getLineHeight(), ""); myMessageBox->setEditable(false, false); myMessageBox->clearFlags(WIDGET_RETAIN_FOCUS); myMessageBox->setTextColor(kTextColorEm); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DebuggerDialog::addRomArea() { static uInt32 LEFT_ARROW[11] = { 0b0000010, 0b0000110, 0b0001110, 0b0011110, 0b0111110, 0b1111110, 0b0111110, 0b0011110, 0b0001110, 0b0000110, 0b0000010 }; static uInt32 RIGHT_ARROW[11] = { 0b0100000, 0b0110000, 0b0111000, 0b0111100, 0b0111110, 0b0111111, 0b0111110, 0b0111100, 0b0111000, 0b0110000, 0b0100000 }; const GUI::Rect& r = getRomBounds(); const int VBORDER = 4; const string ELLIPSIS = "\x1d"; int bwidth = myLFont->getStringWidth("Frame +1 "), bheight = myLFont->getLineHeight() + 2; int buttonX = r.right - bwidth - 5, buttonY = r.top + 5; new ButtonWidget(this, *myLFont, buttonX, buttonY, bwidth, bheight, "Step", kDDStepCmd); buttonY += bheight + 4; new ButtonWidget(this, *myLFont, buttonX, buttonY, bwidth, bheight, "Trace", kDDTraceCmd); buttonY += bheight + 4; new ButtonWidget(this, *myLFont, buttonX, buttonY, bwidth, bheight, "Scan +1", kDDSAdvCmd); buttonY += bheight + 4; new ButtonWidget(this, *myLFont, buttonX, buttonY, bwidth, bheight, "Frame +1", kDDAdvCmd); buttonY += bheight + 4; new ButtonWidget(this, *myLFont, buttonX, buttonY, bwidth, bheight, "Exit", kDDExitCmd); bwidth = bheight; // 7 + 12; bheight = bheight * 3 + 4 * 2; buttonX -= (bwidth + 5); buttonY = r.top + 5; myRewindButton = new ButtonWidget(this, *myLFont, buttonX, buttonY, bwidth, bheight, LEFT_ARROW, 7, 11, kDDRewindCmd); myRewindButton->clearFlags(WIDGET_ENABLED); buttonY += bheight + 4; bheight = (myLFont->getLineHeight() + 2) * 2 + 4 * 1; myUnwindButton = new ButtonWidget(this, *myLFont, buttonX, buttonY, bwidth, bheight, RIGHT_ARROW, 7, 11, kDDUnwindCmd); myUnwindButton->clearFlags(WIDGET_ENABLED); int xpos = buttonX - 8*myLFont->getMaxCharWidth() - 20, ypos = 30; bwidth = myLFont->getStringWidth("Options " + ELLIPSIS); bheight = myLFont->getLineHeight() + 2; new ButtonWidget(this, *myLFont, xpos, r.top + 5, bwidth, bheight, "Options" + ELLIPSIS, kDDOptionsCmd); DataGridOpsWidget* ops = new DataGridOpsWidget(this, *myLFont, xpos, ypos); int max_w = xpos - r.left - 10; xpos = r.left + 10; ypos = 10; myCpu = new CpuWidget(this, *myLFont, *myNFont, xpos, ypos, max_w); addToFocusList(myCpu->getFocusList()); xpos = r.left + 10; ypos += myCpu->getHeight() + 10; myRam = new RiotRamWidget(this, *myLFont, *myNFont, xpos, ypos, r.width() - 10); addToFocusList(myRam->getFocusList()); // Add the DataGridOpsWidget to any widgets which contain a // DataGridWidget which we want controlled myCpu->setOpsWidget(ops); myRam->setOpsWidget(ops); //////////////////////////////////////////////////////////////////// // Disassembly area xpos = r.left + VBORDER; ypos += myRam->getHeight() + 5; const int tabWidth = r.width() - VBORDER - 1; const int tabHeight = r.height() - ypos - 1; int tabID; // Since there are two tab widgets in this dialog, we specifically // assign an ID of 1 myRomTab = new TabWidget( this, *myLFont, xpos, ypos, tabWidth, tabHeight); myRomTab->setID(1); addTabWidget(myRomTab); // The main disassembly tab tabID = myRomTab->addTab(" Disassembly "); myRom = new RomWidget(myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, tabHeight - myRomTab->getTabHeight() - 2); myRomTab->setParentWidget(tabID, myRom); addToFocusList(myRom->getFocusList(), myRomTab, tabID); // The 'cart-specific' information tab tabID = myRomTab->addTab(instance().console().cartridge().name()); myCartDebug = instance().console().cartridge().debugWidget( myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, tabHeight - myRomTab->getTabHeight() - 2); if(myCartDebug) // TODO - make this always non-null { myRomTab->setParentWidget(tabID, myCartDebug); addToFocusList(myCartDebug->getFocusList(), myRomTab, tabID); // The cartridge RAM tab if (myCartDebug->internalRamSize() > 0) { tabID = myRomTab->addTab(" Cartridge RAM "); myCartRam = new CartRamWidget(myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, tabHeight - myRomTab->getTabHeight() - 2, *myCartDebug); if(myCartRam) // TODO - make this always non-null { myRomTab->setParentWidget(tabID, myCartRam); addToFocusList(myCartRam->getFocusList(), myRomTab, tabID); myCartRam->setOpsWidget(ops); } } } myRomTab->setActiveTab(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect DebuggerDialog::getTiaBounds() const { // The area showing the TIA image (NTSC and PAL supported, up to 260 lines) GUI::Rect r(0, 0, 320, std::max(260, int(_h * 0.35))); return r; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect DebuggerDialog::getRomBounds() const { // The ROM area is the full area to the right of the tabs const GUI::Rect& status = getStatusBounds(); GUI::Rect r(status.right + 1, 0, _w, _h); return r; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect DebuggerDialog::getStatusBounds() const { // The status area is the full area to the right of the TIA image // extending as far as necessary // 30% of any space above 1030 pixels will be allocated to this area const GUI::Rect& tia = getTiaBounds(); int x1 = tia.right + 1; int y1 = 0; int x2 = tia.right + 225 + (_w > 1030 ? int(0.35 * (_w - 1030)) : 0); int y2 = tia.bottom; GUI::Rect r(x1, y1, x2, y2); return r; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect DebuggerDialog::getTabBounds() const { // The tab area is the full area below the TIA image const GUI::Rect& tia = getTiaBounds(); const GUI::Rect& status = getStatusBounds(); GUI::Rect r(0, tia.bottom + 1, status.right + 1, _h); return r; } stella-5.1.1/src/debugger/gui/DebuggerDialog.hxx000066400000000000000000000107451324334165500215530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DEBUGGER_DIALOG_HXX #define DEBUGGER_DIALOG_HXX class Debugger; class OSystem; class DialogContainer; class ButtonWidget; class CpuWidget; class PromptWidget; class RamWidget; class RomWidget; class TabWidget; class EditTextWidget; class TiaInfoWidget; class TiaOutputWidget; class TiaZoomWidget; class CartDebugWidget; class CartRamWidget; class OptionsDialog; namespace GUI { class MessageBox; struct Rect; } #include "Dialog.hxx" class DebuggerDialog : public Dialog { public: // Note: these sizes make sure that all major tabs are fully visible // cart dependend information (e.g. DPC+) may require more space enum { kSmallFontMinW = 1090, kSmallFontMinH = 720, kMediumFontMinW = 1160, kMediumFontMinH = 770, kLargeFontMinW = 1160, kLargeFontMinH = 870 }; DebuggerDialog(OSystem& osystem, DialogContainer& parent, int x, int y, int w, int h); virtual ~DebuggerDialog() = default; const GUI::Font& lfont() const { return *myLFont; } const GUI::Font& nfont() const { return *myNFont; } PromptWidget& prompt() const { return *myPrompt; } TiaInfoWidget& tiaInfo() const { return *myTiaInfo; } TiaOutputWidget& tiaOutput() const { return *myTiaOutput; } TiaZoomWidget& tiaZoom() const { return *myTiaZoom; } RomWidget& rom() const { return *myRom; } CartDebugWidget& cartDebug() const { return *myCartDebug; } CartRamWidget& cartRam() const { return *myCartRam; } EditTextWidget& message() const { return *myMessageBox; } ButtonWidget& rewindButton() const { return *myRewindButton; } ButtonWidget& unwindButton() const { return *myUnwindButton; } void showFatalMessage(const string& msg); private: void loadConfig() override; void handleKeyDown(StellaKey key, StellaMod mod) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void doStep(); void doTrace(); void doScanlineAdvance(); void doAdvance(); void doRewind(); void doUnwind(); void doRewind10(); void doUnwind10(); void doRewindAll(); void doUnwindAll(); void doExitDebugger(); void doExitRom(); void createFont(); void addTiaArea(); void addTabArea(); void addStatusArea(); void addRomArea(); GUI::Rect getTiaBounds() const; GUI::Rect getRomBounds() const; GUI::Rect getStatusBounds() const; GUI::Rect getTabBounds() const; private: enum { kDDStepCmd = 'DDst', kDDTraceCmd = 'DDtr', kDDAdvCmd = 'DDav', kDDSAdvCmd = 'DDsv', kDDRewindCmd = 'DDrw', kDDUnwindCmd = 'DDuw', kDDExitCmd = 'DDex', kDDExitFatalCmd = 'DDer', kDDOptionsCmd = 'DDop' }; TabWidget *myTab, *myRomTab; PromptWidget* myPrompt; TiaInfoWidget* myTiaInfo; TiaOutputWidget* myTiaOutput; TiaZoomWidget* myTiaZoom; CpuWidget* myCpu; RamWidget* myRam; RomWidget* myRom; CartDebugWidget* myCartDebug; CartRamWidget* myCartRam; EditTextWidget* myMessageBox; ButtonWidget* myRewindButton; ButtonWidget* myUnwindButton; //ButtonWidget* myOptionsButton; unique_ptr myFatalError; unique_ptr myOptions; unique_ptr myLFont; // used for labels unique_ptr myNFont; // used for normal text private: // Following constructors and assignment operators not supported DebuggerDialog() = delete; DebuggerDialog(const DebuggerDialog&) = delete; DebuggerDialog(DebuggerDialog&&) = delete; DebuggerDialog& operator=(const DebuggerDialog&) = delete; DebuggerDialog& operator=(DebuggerDialog&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/DelayQueueWidget.cxx000066400000000000000000000060021324334165500221000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "DelayQueueWidget.hxx" #include "DelayQueueIterator.hxx" #include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "TIADebug.hxx" #include "TIAConstants.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "Base.hxx" #include "TIA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DelayQueueWidget::DelayQueueWidget( GuiObject* boss, const GUI::Font& font, int x, int y ) : Widget(boss, font, x, y, 0, 0) { _textcolor = kTextColor; _w = 20 * font.getMaxCharWidth() + 6; _h = lineCount * font.getLineHeight() + 6; for (auto&& line : myLines) line = ""; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DelayQueueWidget::loadConfig() { shared_ptr delayQueueIterator = instance().debugger().tiaDebug().delayQueueIterator(); using Common::Base; for (auto&& line : myLines) { if (!delayQueueIterator->isValid()) { line = ""; continue; }; stringstream ss; const auto address = delayQueueIterator->address(); const int delay = delayQueueIterator->delay(); switch (address) { case TIA::DummyRegisters::shuffleP0: ss << delay << " clk, shuffle GRP0"; break; case TIA::DummyRegisters::shuffleP1: ss << delay << " clk, shuffle GRP1"; break; case TIA::DummyRegisters::shuffleBL: ss << delay << " clk, shuffle ENABL"; break; default: if (address < 64) ss << delay << " clk, $" << Base::toString(delayQueueIterator->value(), Base::Format::F_16_2) << " -> " << instance().debugger().cartDebug().getLabel(address, false); break; } line = ss.str(); delayQueueIterator->next(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DelayQueueWidget::drawWidget(bool hilite) { FBSurface& surface = _boss->dialog().surface(); int y = _y, x = _x, w = _w, lineHeight = _font.getLineHeight(); surface.frameRect(x, y, w, _h, kShadowColor); y += 1; x += 1; w -= 1; surface.fillRect(x, y, w - 1, _h - 2, kBGColorHi); y += 2; x += 2; w -= 3; for (const auto& line : myLines) { surface.drawString(_font, line, x, y, w, _textcolor); y += lineHeight; } } stella-5.1.1/src/debugger/gui/DelayQueueWidget.hxx000066400000000000000000000026551324334165500221170ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DELAY_QUEUE_WIDGET_HXX #define DELAY_QUEUE_WIDGET_HXX #include "Widget.hxx" class DelayQueueWidget : public Widget { public: DelayQueueWidget( GuiObject* boss, const GUI::Font& font, int x, int y ); virtual ~DelayQueueWidget() = default; void loadConfig() override; protected: void drawWidget(bool hilite) override; private: static constexpr uInt8 lineCount = 4; string myLines[lineCount]; private: DelayQueueWidget() = delete; DelayQueueWidget(const DelayQueueWidget&) = delete; DelayQueueWidget(DelayQueueWidget&&) = delete; DelayQueueWidget& operator=(const DelayQueueWidget&); DelayQueueWidget& operator=(DelayQueueWidget&&); }; #endif // DELAY_QUEUE_WIDGET_HXX stella-5.1.1/src/debugger/gui/DrivingWidget.cxx000066400000000000000000000076161324334165500214530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "DataGridWidget.hxx" #include "DrivingWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DrivingWidget::DrivingWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller), myGrayIndex(0) { const string& label = getHeader(); const int fontHeight = font.getFontHeight(), bwidth = font.getStringWidth("Gray code +") + 10, bheight = font.getLineHeight() + 4; int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Driving)"); StaticTextWidget* t; t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth, fontHeight, label, TextAlign::Left); ypos += t->getHeight() + 20; myGrayUp = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "Gray code +", kGrayUpCmd); myGrayUp->setTarget(this); ypos += myGrayUp->getHeight() + 5; myGrayDown = new ButtonWidget(boss, font, xpos, ypos, bwidth, bheight, "Gray code -", kGrayDownCmd); myGrayDown->setTarget(this); xpos += myGrayDown->getWidth() + 10; ypos -= 10; myGrayValue = new DataGridWidget(boss, font, xpos, ypos, 1, 1, 2, 8, Common::Base::F_16); myGrayValue->setTarget(this); myGrayValue->setEditable(false); xpos = x + 30; ypos += myGrayDown->getHeight() + 20; myFire = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kFireCmd); myFire->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DrivingWidget::loadConfig() { uInt8 gray = 0; if(myController.read(Controller::One)) gray += 1; if(myController.read(Controller::Two)) gray += 2; for(myGrayIndex = 0; myGrayIndex < 4; ++myGrayIndex) if(ourGrayTable[myGrayIndex] == gray) break; myFire->setState(!myController.read(Controller::Six)); setValue(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DrivingWidget::handleCommand( CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kGrayUpCmd: myGrayIndex = (myGrayIndex + 1) % 4; myController.set(Controller::One, (ourGrayTable[myGrayIndex] & 0x1) != 0); myController.set(Controller::Two, (ourGrayTable[myGrayIndex] & 0x2) != 0); setValue(); break; case kGrayDownCmd: myGrayIndex = myGrayIndex == 0 ? 3 : myGrayIndex - 1; myController.set(Controller::One, (ourGrayTable[myGrayIndex] & 0x1) != 0); myController.set(Controller::Two, (ourGrayTable[myGrayIndex] & 0x2) != 0); setValue(); break; case kFireCmd: myController.set(Controller::Six, !myFire->getState()); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DrivingWidget::setValue() { int grayCode = ourGrayTable[myGrayIndex]; // FIXME * 8 = a nasty hack, because the DataGridWidget does not support 2 digit binary output myGrayValue->setList(0, (grayCode & 0b01) + (grayCode & 0b10) * 8); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 DrivingWidget::ourGrayTable[4] = { 0x03, 0x01, 0x00, 0x02 }; stella-5.1.1/src/debugger/gui/DrivingWidget.hxx000066400000000000000000000034441324334165500214530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DRIVING_WIDGET_HXX #define DRIVING_WIDGET_HXX class Controller; class ButtonWidget; class CheckboxWidget; class DataGridWidget; #include "ControllerWidget.hxx" class DrivingWidget : public ControllerWidget { public: DrivingWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~DrivingWidget() = default; private: enum { kGrayUpCmd = 'DWup', kGrayDownCmd = 'DWdn', kFireCmd = 'DWfr' }; ButtonWidget *myGrayUp, *myGrayDown; DataGridWidget* myGrayValue; CheckboxWidget* myFire; int myGrayIndex; static uInt8 ourGrayTable[4]; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void setValue(); // Following constructors and assignment operators not supported DrivingWidget() = delete; DrivingWidget(const DrivingWidget&) = delete; DrivingWidget(DrivingWidget&&) = delete; DrivingWidget& operator=(const DrivingWidget&) = delete; DrivingWidget& operator=(DrivingWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/FlashWidget.cxx000066400000000000000000000062361324334165500211030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Base.hxx" #include "MT24LC256.hxx" #include "FlashWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FlashWidget::FlashWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FlashWidget::init(GuiObject* boss, const GUI::Font& font, int x, int y) { const GUI::Font& ifont = instance().frameBuffer().infoFont(); const int lineHeight = font.getLineHeight(); int xpos = x, ypos = y; new StaticTextWidget(boss, font, xpos, ypos + 2, getHeader()); ypos += lineHeight + 6; new StaticTextWidget(boss, ifont, xpos, ypos, "Pages/Ranges used:"); ypos += lineHeight + 2; xpos += 8; for(uInt32 page = 0; page < MAX_PAGES; ++page) { myPage[page] = new StaticTextWidget(boss, ifont, xpos, ypos, page ? " " : "none "); ypos += lineHeight; } xpos -= 8; ypos += 2; myEEPROMEraseCurrent = new ButtonWidget(boss, font, xpos, ypos, "Erase used pages", kEEPROMEraseCurrent); myEEPROMEraseCurrent->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FlashWidget::handleCommand(CommandSender*, int cmd, int, int) { if(cmd == kEEPROMEraseCurrent) { eraseCurrent(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // display the pages used by the current ROM and update erase button status void FlashWidget::loadConfig() { int useCount = 0, startPage = -1; for(uInt32 page = 0; page < MT24LC256::PAGE_NUM; ++page) { if(isPageUsed(page)) { if (startPage == -1) startPage = page; } else { if(startPage != -1) { int from = startPage * MT24LC256::PAGE_SIZE; int to = page * MT24LC256::PAGE_SIZE - 1; ostringstream label; label.str(""); label << Common::Base::HEX3 << startPage; if(int(page) - 1 != startPage) label << "-" << Common::Base::HEX3 << page - 1; else label << " "; label << ": " << Common::Base::HEX4 << from << "-" << Common::Base::HEX4 << to; myPage[useCount]->setLabel(label.str()); startPage = -1; if(++useCount == MAX_PAGES) break; } } } myEEPROMEraseCurrent->setEnabled(useCount != 0); } stella-5.1.1/src/debugger/gui/FlashWidget.hxx000066400000000000000000000036211324334165500211030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FLASH_WIDGET_HXX #define FLASH_WIDGET_HXX class Controller; class ButtonWidget; #include "ControllerWidget.hxx" class FlashWidget : public ControllerWidget { public: FlashWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~FlashWidget() = default; protected: void init(GuiObject* boss, const GUI::Font& font, int x, int y); private: ButtonWidget* myEEPROMEraseCurrent; enum { kEEPROMEraseCurrent = 'eeEC' }; static constexpr uInt32 MAX_PAGES = 5; StaticTextWidget* myPage[MAX_PAGES]; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; /** Erase the EEPROM pages used by the current ROM */ virtual void eraseCurrent() = 0; /** Check if a page is used by the current ROM */ virtual bool isPageUsed(uInt32 page) = 0; // Following constructors and assignment operators not supported FlashWidget() = delete; FlashWidget(const FlashWidget&) = delete; FlashWidget(FlashWidget&&) = delete; FlashWidget& operator=(const FlashWidget&) = delete; FlashWidget& operator=(FlashWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/GenesisWidget.cxx000066400000000000000000000103741324334165500214410ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "GenesisWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GenesisWidget::GenesisWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { const string& label = getHeader(); const int fontHeight = font.getFontHeight(); int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Genesis)"); StaticTextWidget* t; t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth, fontHeight, label, TextAlign::Left); xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 20; myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJUp]->setID(kJUp); myPins[kJUp]->setTarget(this); ypos += myPins[kJUp]->getHeight() * 2 + 10; myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJDown]->setID(kJDown); myPins[kJDown]->setTarget(this); xpos -= myPins[kJUp]->getWidth() + 5; ypos -= myPins[kJUp]->getHeight() + 5; myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJLeft]->setID(kJLeft); myPins[kJLeft]->setTarget(this); xpos += (myPins[kJUp]->getWidth() + 5) * 2; myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJRight]->setID(kJRight); myPins[kJRight]->setTarget(this); xpos -= (myPins[kJUp]->getWidth() + 5) * 2; ypos = 30 + (myPins[kJUp]->getHeight() + 10) * 3; myPins[kJBbtn] = new CheckboxWidget(boss, font, xpos, ypos, "B button", CheckboxWidget::kCheckActionCmd); myPins[kJBbtn]->setID(kJBbtn); myPins[kJBbtn]->setTarget(this); ypos += myPins[kJBbtn]->getHeight() + 5; myPins[kJCbtn] = new CheckboxWidget(boss, font, xpos, ypos, "C button", CheckboxWidget::kCheckActionCmd); myPins[kJCbtn]->setID(kJCbtn); myPins[kJCbtn]->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GenesisWidget::loadConfig() { myPins[kJUp]->setState(!myController.read(ourPinNo[kJUp])); myPins[kJDown]->setState(!myController.read(ourPinNo[kJDown])); myPins[kJLeft]->setState(!myController.read(ourPinNo[kJLeft])); myPins[kJRight]->setState(!myController.read(ourPinNo[kJRight])); myPins[kJBbtn]->setState(!myController.read(ourPinNo[kJBbtn])); myPins[kJCbtn]->setState( myController.read(Controller::Five) == Controller::maximumResistance); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GenesisWidget::handleCommand( CommandSender* sender, int cmd, int data, int id) { if(cmd == CheckboxWidget::kCheckActionCmd) { switch(id) { case kJUp: case kJDown: case kJLeft: case kJRight: case kJBbtn: myController.set(ourPinNo[id], !myPins[id]->getState()); break; case kJCbtn: myController.set(Controller::Five, myPins[id]->getState() ? Controller::maximumResistance : Controller::minimumResistance); break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller::DigitalPin GenesisWidget::ourPinNo[5] = { Controller::One, Controller::Two, Controller::Three, Controller::Four, Controller::Six }; stella-5.1.1/src/debugger/gui/GenesisWidget.hxx000066400000000000000000000031321324334165500214400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef GENESIS_WIDGET_HXX #define GENESIS_WIDGET_HXX #include "Control.hxx" #include "ControllerWidget.hxx" class GenesisWidget : public ControllerWidget { public: GenesisWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~GenesisWidget() = default; private: enum { kJUp = 0, kJDown, kJLeft, kJRight, kJBbtn, kJCbtn }; CheckboxWidget* myPins[6]; static Controller::DigitalPin ourPinNo[5]; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Following constructors and assignment operators not supported GenesisWidget() = delete; GenesisWidget(const GenesisWidget&) = delete; GenesisWidget(GenesisWidget&&) = delete; GenesisWidget& operator=(const GenesisWidget&) = delete; GenesisWidget& operator=(GenesisWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/JoystickWidget.cxx000066400000000000000000000070571324334165500216470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "JoystickWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JoystickWidget::JoystickWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { const string& label = getHeader(); const int fontHeight = font.getFontHeight(); int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Joystick)"); StaticTextWidget* t; t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth, fontHeight, label, TextAlign::Left); xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 20; myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJUp]->setID(kJUp); myPins[kJUp]->setTarget(this); ypos += myPins[kJUp]->getHeight() * 2 + 10; myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJDown]->setID(kJDown); myPins[kJDown]->setTarget(this); xpos -= myPins[kJUp]->getWidth() + 5; ypos -= myPins[kJUp]->getHeight() + 5; myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJLeft]->setID(kJLeft); myPins[kJLeft]->setTarget(this); xpos += (myPins[kJUp]->getWidth() + 5) * 2; myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myPins[kJRight]->setID(kJRight); myPins[kJRight]->setTarget(this); xpos -= (myPins[kJUp]->getWidth() + 5) * 2; ypos = 30 + (myPins[kJUp]->getHeight() + 10) * 3; myPins[kJFire] = new CheckboxWidget(boss, font, xpos, ypos, "Fire", CheckboxWidget::kCheckActionCmd); myPins[kJFire]->setID(kJFire); myPins[kJFire]->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JoystickWidget::loadConfig() { myPins[kJUp]->setState(!myController.read(ourPinNo[kJUp])); myPins[kJDown]->setState(!myController.read(ourPinNo[kJDown])); myPins[kJLeft]->setState(!myController.read(ourPinNo[kJLeft])); myPins[kJRight]->setState(!myController.read(ourPinNo[kJRight])); myPins[kJFire]->setState(!myController.read(ourPinNo[kJFire])); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JoystickWidget::handleCommand( CommandSender* sender, int cmd, int data, int id) { if(cmd == CheckboxWidget::kCheckActionCmd) myController.set(ourPinNo[id], !myPins[id]->getState()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller::DigitalPin JoystickWidget::ourPinNo[5] = { Controller::One, Controller::Two, Controller::Three, Controller::Four, Controller::Six }; stella-5.1.1/src/debugger/gui/JoystickWidget.hxx000066400000000000000000000031411324334165500216420ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef JOYSTICK_WIDGET_HXX #define JOYSTICK_WIDGET_HXX #include "Control.hxx" #include "ControllerWidget.hxx" class JoystickWidget : public ControllerWidget { public: JoystickWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~JoystickWidget() = default; private: enum { kJUp = 0, kJDown, kJLeft, kJRight, kJFire }; CheckboxWidget* myPins[5]; static Controller::DigitalPin ourPinNo[5]; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Following constructors and assignment operators not supported JoystickWidget() = delete; JoystickWidget(const JoystickWidget&) = delete; JoystickWidget(JoystickWidget&&) = delete; JoystickWidget& operator=(const JoystickWidget&) = delete; JoystickWidget& operator=(JoystickWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/KeyboardWidget.cxx000066400000000000000000000062711324334165500216050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "EventHandler.hxx" #include "KeyboardWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - KeyboardWidget::KeyboardWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { bool leftport = isLeftPort(); const string& label = leftport ? "Left (Keyboard)" : "Right (Keyboard)"; const int fontHeight = font.getFontHeight(); int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Keyboard)"); StaticTextWidget* t; t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth, fontHeight, label, TextAlign::Left); xpos += 30; ypos += t->getHeight() + 20; for(int i = 0; i < 12; ++i) { myBox[i] = new CheckboxWidget(boss, font, xpos, ypos, "", CheckboxWidget::kCheckActionCmd); myBox[i]->setID(i); myBox[i]->setTarget(this); xpos += myBox[i]->getWidth() + 5; if((i+1) % 3 == 0) { xpos = x + 30; ypos += myBox[i]->getHeight() + 5; } } myEvent = leftport ? ourLeftEvents : ourRightEvents; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KeyboardWidget::loadConfig() { const Event& event = instance().eventHandler().event(); for(int i = 0; i < 12; ++i) myBox[i]->setState(event.get(myEvent[i])); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KeyboardWidget::handleCommand( CommandSender* sender, int cmd, int data, int id) { if(cmd == CheckboxWidget::kCheckActionCmd) instance().eventHandler().handleEvent(myEvent[id], myBox[id]->getState()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Event::Type KeyboardWidget::ourLeftEvents[12] = { Event::KeyboardZero1, Event::KeyboardZero2, Event::KeyboardZero3, Event::KeyboardZero4, Event::KeyboardZero5, Event::KeyboardZero6, Event::KeyboardZero7, Event::KeyboardZero8, Event::KeyboardZero9, Event::KeyboardZeroStar, Event::KeyboardZero0, Event::KeyboardZeroPound }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Event::Type KeyboardWidget::ourRightEvents[12] = { Event::KeyboardOne1, Event::KeyboardOne2, Event::KeyboardOne3, Event::KeyboardOne4, Event::KeyboardOne5, Event::KeyboardOne6, Event::KeyboardOne7, Event::KeyboardOne8, Event::KeyboardOne9, Event::KeyboardOneStar, Event::KeyboardOne0, Event::KeyboardOnePound }; stella-5.1.1/src/debugger/gui/KeyboardWidget.hxx000066400000000000000000000031201324334165500216000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef KEYBOARD_WIDGET_HXX #define KEYBOARD_WIDGET_HXX #include "Event.hxx" #include "ControllerWidget.hxx" class KeyboardWidget : public ControllerWidget { public: KeyboardWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~KeyboardWidget() = default; private: CheckboxWidget* myBox[12]; Event::Type* myEvent; static Event::Type ourLeftEvents[12], ourRightEvents[12]; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Following constructors and assignment operators not supported KeyboardWidget() = delete; KeyboardWidget(const KeyboardWidget&) = delete; KeyboardWidget(KeyboardWidget&&) = delete; KeyboardWidget& operator=(const KeyboardWidget&) = delete; KeyboardWidget& operator=(KeyboardWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/NullControlWidget.hxx000066400000000000000000000042231324334165500223200ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef NULLCONTROL_WIDGET_HXX #define NULLCONTROL_WIDGET_HXX class GuiObject; #include "ControllerWidget.hxx" class NullControlWidget : public ControllerWidget { public: NullControlWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { ostringstream buf; buf << getHeader(); const int fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), lwidth = std::max(font.getStringWidth(buf.str()), font.getStringWidth("Controller input")); new StaticTextWidget(boss, font, x, y+2, lwidth, fontHeight, buf.str(), TextAlign::Left); new StaticTextWidget(boss, font, x, y+2+2*lineHeight, lwidth, fontHeight, "Controller input", TextAlign::Center); new StaticTextWidget(boss, font, x, y+2+3*lineHeight, lwidth, fontHeight, "not available", TextAlign::Center); } virtual ~NullControlWidget() = default; private: // Following constructors and assignment operators not supported NullControlWidget() = delete; NullControlWidget(const NullControlWidget&) = delete; NullControlWidget(NullControlWidget&&) = delete; NullControlWidget& operator=(const NullControlWidget&) = delete; NullControlWidget& operator=(NullControlWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/PaddleWidget.cxx000066400000000000000000000074171324334165500212410ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Paddles.hxx" #include "PaddleWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaddleWidget::PaddleWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { bool leftport = isLeftPort(); const string& label = getHeader(); const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(); int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Paddles)"); new StaticTextWidget(boss, font, xpos, ypos+2, lwidth, fontHeight, label, TextAlign::Left); ypos += lineHeight + 20; const string& p0string = leftport ? "P0 pot " : "P2 pot "; const string& p1string = leftport ? "P1 pot " : "P3 pot "; lwidth = font.getStringWidth("P3 pot: "); myP0Resistance = new SliderWidget(boss, font, xpos, ypos, 10*fontWidth, lineHeight, p0string, lwidth, kP0Changed); myP0Resistance->setMinValue(0); myP0Resistance->setMaxValue(uInt32(Paddles::MAX_RESISTANCE)); myP0Resistance->setStepValue(uInt32(Paddles::MAX_RESISTANCE/100)); myP0Resistance->setTarget(this); xpos += 20; ypos += myP0Resistance->getHeight() + 4; myP0Fire = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kP0Fire); myP0Fire->setTarget(this); xpos = x; ypos += 2*lineHeight; myP1Resistance = new SliderWidget(boss, font, xpos, ypos, 10*fontWidth, lineHeight, p1string, lwidth, kP1Changed); myP1Resistance->setMinValue(0); myP1Resistance->setMaxValue(uInt32(Paddles::MAX_RESISTANCE)); myP1Resistance->setStepValue(uInt32(Paddles::MAX_RESISTANCE/100)); myP1Resistance->setTarget(this); xpos += 20; ypos += myP1Resistance->getHeight() + 4; myP1Fire = new CheckboxWidget(boss, font, xpos, ypos, "Fire", kP1Fire); myP1Fire->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaddleWidget::loadConfig() { myP0Resistance->setValue(Int32(Paddles::MAX_RESISTANCE - myController.read(Controller::Nine))); myP1Resistance->setValue(Int32(Paddles::MAX_RESISTANCE - myController.read(Controller::Five))); myP0Fire->setState(!myController.read(Controller::Four)); myP1Fire->setState(!myController.read(Controller::Three)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaddleWidget::handleCommand( CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kP0Changed: myController.set(Controller::Nine, Int32(Paddles::MAX_RESISTANCE - myP0Resistance->getValue())); break; case kP1Changed: myController.set(Controller::Five, Int32(Paddles::MAX_RESISTANCE - myP1Resistance->getValue())); break; case kP0Fire: myController.set(Controller::Four, !myP0Fire->getState()); break; case kP1Fire: myController.set(Controller::Three, !myP1Fire->getState()); break; } } stella-5.1.1/src/debugger/gui/PaddleWidget.hxx000066400000000000000000000031731324334165500212410ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PADDLE_WIDGET_HXX #define PADDLE_WIDGET_HXX class Controller; #include "ControllerWidget.hxx" class PaddleWidget : public ControllerWidget { public: PaddleWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~PaddleWidget() = default; private: enum { kP0Changed = 'P0ch', kP1Changed = 'P1ch', kP0Fire = 'P0fr', kP1Fire = 'P1fr' }; SliderWidget *myP0Resistance, *myP1Resistance; CheckboxWidget *myP0Fire, *myP1Fire; private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Following constructors and assignment operators not supported PaddleWidget() = delete; PaddleWidget(const PaddleWidget&) = delete; PaddleWidget(PaddleWidget&&) = delete; PaddleWidget& operator=(const PaddleWidget&) = delete; PaddleWidget& operator=(PaddleWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/PointingDeviceWidget.cxx000066400000000000000000000107101324334165500227450ustar00rootroot00000000000000 //============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "PointingDevice.hxx" #include "DataGridWidget.hxx" #include "PointingDeviceWidget.hxx" PointingDeviceWidget::PointingDeviceWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : ControllerWidget(boss, font, x, y, controller) { int ypos = y; int xLeft = x + 10; int xMid = xLeft + 30; int xRight = xLeft + 60; int xValue = xLeft + 87; StaticTextWidget* t; t = new StaticTextWidget(boss, font, x, y + 2, getHeader()); ypos += t->getHeight() + 8; // add gray code and up widgets myGrayValueV = new DataGridWidget(boss, font, xMid, ypos, 1, 1, 2, 8, Common::Base::F_16); myGrayValueV->setTarget(this); myGrayValueV->setEditable(false); ypos += myGrayValueV->getHeight() + 2; myGrayUp = new ButtonWidget(boss, font, xMid, ypos, 17, "+", kTBUp); myGrayUp->setTarget(this); ypos += myGrayUp->getHeight() + 5; // add horizontal direction and gray code widgets myGrayLeft = new ButtonWidget(boss, font, xLeft, ypos, 17, "-", kTBLeft); myGrayLeft->setTarget(this); myGrayRight = new ButtonWidget(boss, font, xRight, ypos, 17, "+", kTBRight); myGrayRight->setTarget(this); myGrayValueH = new DataGridWidget(boss, font, xValue, ypos + 2, 1, 1, 2, 8, Common::Base::F_16); myGrayValueH->setTarget(this); myGrayValueH->setEditable(false); ypos += myGrayLeft->getHeight() + 5; // add down widget myGrayDown = new ButtonWidget(boss, font, xMid, ypos, 17, "-", kTBDown); myGrayDown->setTarget(this); ypos += myGrayDown->getHeight() + 8; myFire = new CheckboxWidget(boss, font, xLeft, ypos, "Fire", kTBFire); myFire->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PointingDeviceWidget::loadConfig() { setGrayCodeH(); setGrayCodeV(); myFire->setState(!myController.read(Controller::Six)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PointingDeviceWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { // since the PointingDevice uses its own, internal state (not reading the controller), // we have to communicate directly with it PointingDevice& pDev = static_cast(myController); switch(cmd) { case kTBLeft: pDev.myCountH++; pDev.myTrackBallLeft = false; setGrayCodeH(); break; case kTBRight: pDev.myCountH--; pDev.myTrackBallLeft = true; setGrayCodeH(); break; case kTBUp: pDev.myCountV++; pDev.myTrackBallDown = true; setGrayCodeV(); break; case kTBDown: pDev.myCountV--; pDev.myTrackBallDown = false; setGrayCodeV(); break; case kTBFire: myController.set(Controller::Six, !myFire->getState()); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PointingDeviceWidget::setGrayCodeH() { PointingDevice& pDev = static_cast(myController); pDev.myCountH &= 0b11; setValue(myGrayValueH, pDev.myCountH, pDev.myTrackBallLeft); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PointingDeviceWidget::setGrayCodeV() { PointingDevice& pDev = static_cast(myController); pDev.myCountV &= 0b11; setValue(myGrayValueV, pDev.myCountV, !pDev.myTrackBallDown); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PointingDeviceWidget::setValue(DataGridWidget* grayValue, const int index, const int direction) { uInt8 grayCode = getGrayCodeTable(index, direction); // FIXME * 8 = a nasty hack, because the DataGridWidget does not support 2 digit binary output grayValue->setList(0, (grayCode & 0b01) + (grayCode & 0b10) * 8); } stella-5.1.1/src/debugger/gui/PointingDeviceWidget.hxx000066400000000000000000000041321324334165500227530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef POINTINGDEVICE_WIDGET_HXX #define POINTINGDEVICE_WIDGET_HXX class Controller; class DataGridWidget; #include "ControllerWidget.hxx" class PointingDeviceWidget : public ControllerWidget { public: PointingDeviceWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~PointingDeviceWidget() = default; private: enum { kTBLeft = 'TWlf', kTBRight = 'TWrt', kTBUp = 'TWup', kTBDown = 'TWdn', kTBFire = 'TWfr' }; ButtonWidget *myGrayLeft, *myGrayRight; DataGridWidget* myGrayValueH; ButtonWidget *myGrayUp, *myGrayDown; DataGridWidget* myGrayValueV; CheckboxWidget* myFire; private: virtual uInt8 getGrayCodeTable(const int index, const int direction) = 0; void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void setGrayCodeH(); void setGrayCodeV(); void setValue(DataGridWidget* greyValue, const int index, const int direction); // Following constructors and assignment operators not supported PointingDeviceWidget() = delete; PointingDeviceWidget(const PointingDeviceWidget&) = delete; PointingDeviceWidget(PointingDeviceWidget&&) = delete; PointingDeviceWidget& operator=(const PointingDeviceWidget&) = delete; PointingDeviceWidget& operator=(PointingDeviceWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/PromptWidget.cxx000066400000000000000000000601661324334165500213310ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "ScrollBarWidget.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "StellaKeys.hxx" #include "Version.hxx" #include "Debugger.hxx" #include "DebuggerDialog.hxx" #include "DebuggerParser.hxx" #include "PromptWidget.hxx" #include "CartDebug.hxx" #define PROMPT "> " // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PromptWidget::PromptWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : Widget(boss, font, x, y, w - kScrollBarWidth, h), CommandSender(boss), _historyIndex(0), _makeDirty(false), _firstTime(true), _exitedEarly(false) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANTS_TAB | WIDGET_WANTS_RAWDATA; _textcolor = kTextColor; _bgcolor = kWidColor; _kConsoleCharWidth = font.getMaxCharWidth(); _kConsoleCharHeight = font.getFontHeight(); _kConsoleLineHeight = _kConsoleCharHeight + 2; // Calculate depending values _lineWidth = (_w - kScrollBarWidth - 2) / _kConsoleCharWidth; _linesPerPage = (_h - 2) / _kConsoleLineHeight; _linesInBuffer = kBufferSize / _lineWidth; // Add scrollbar _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h); _scrollBar->setTarget(this); // Init colors _inverse = false; clearScreen(); addFocusWidget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::drawWidget(bool hilite) { //cerr << "PromptWidget::drawWidget\n"; uInt32 fgcolor, bgcolor; FBSurface& s = _boss->dialog().surface(); // Draw text int start = _scrollLine - _linesPerPage + 1; int y = _y + 2; for (int line = 0; line < _linesPerPage; ++line) { int x = _x + 1; for (int column = 0; column < _lineWidth; ++column) { int c = buffer((start + line) * _lineWidth + column); if(c & (1 << 17)) // inverse video flag { fgcolor = _bgcolor; bgcolor = (c & 0x1ffff) >> 8; s.fillRect(x, y, _kConsoleCharWidth, _kConsoleCharHeight, bgcolor); } else fgcolor = c >> 8; s.drawChar(_font, c & 0x7f, x, y, fgcolor); x += _kConsoleCharWidth; } y += _kConsoleLineHeight; } // Draw the caret drawCaret(); // Draw the scrollbar _scrollBar->draw(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { // cerr << "PromptWidget::handleMouseDown\n"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::handleMouseWheel(int x, int y, int direction) { _scrollBar->handleMouseWheel(x, y, direction); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::printPrompt() { string watches = instance().debugger().showWatches(); if(watches.length() > 0) print(watches); print(PROMPT); _promptStartPos = _promptEndPos = _currentPos; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PromptWidget::handleText(char text) { if(text >= 0) { // FIXME - convert this class to inherit from EditableWidget for(int i = _promptEndPos - 1; i >= _currentPos; i--) buffer(i + 1) = buffer(i); _promptEndPos++; putcharIntern(text); scrollToCurrent(); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PromptWidget::handleKeyDown(StellaKey key, StellaMod mod) { bool handled = true; bool dirty = false; switch(key) { case KBDK_RETURN: case KBDK_KP_ENTER: { nextLine(); assert(_promptEndPos >= _promptStartPos); int len = _promptEndPos - _promptStartPos; if (len > 0) { // Copy the user input to command string command; for (int i = 0; i < len; i++) command += buffer(_promptStartPos + i) & 0x7f; // Add the input to the history addToHistory(command.c_str()); // Pass the command to the debugger, and print the result string result = instance().debugger().run(command); // This is a bit of a hack // Certain commands remove the debugger dialog from underneath us, // so we shouldn't print any messages // Those commands will return '_EXIT_DEBUGGER' as their result if(result == "_EXIT_DEBUGGER") { _exitedEarly = true; return true; } else if(result != "") print(result + "\n"); } printPrompt(); dirty = true; break; } case KBDK_TAB: { // Tab completion: we complete either commands or labels, but not // both at once. if(_currentPos <= _promptStartPos) break; scrollToCurrent(); int len = _promptEndPos - _promptStartPos; if(len > 255) len = 255; int lastDelimPos = -1; char delimiter = '\0'; char inputStr[256]; for (int i = 0; i < len; i++) { inputStr[i] = buffer(_promptStartPos + i) & 0x7f; // whitespace characters if(strchr("{*@<> =[]()+-/&|!^~%", inputStr[i])) { lastDelimPos = i; delimiter = inputStr[i]; } } inputStr[len] = '\0'; size_t strLen = len - lastDelimPos - 1; StringList list; string completionList; string prefix; if(lastDelimPos < 0) { // no delimiters, do only command completion: const DebuggerParser& parser = instance().debugger().parser(); parser.getCompletions(inputStr, list); if(list.size() < 1) break; sort(list.begin(), list.end()); completionList = list[0]; for(uInt32 i = 1; i < list.size(); ++i) completionList += " " + list[i]; prefix = getCompletionPrefix(list); } else { // Special case for 'help' command if(BSPF::startsWithIgnoreCase(inputStr, "help")) { instance().debugger().parser().getCompletions(inputStr + lastDelimPos + 1, list); } else { // do not show ALL labels without any filter as it makes no sense if(strLen > 0) { // we got a delimiter, so this must be a label or a function const Debugger& dbg = instance().debugger(); dbg.cartDebug().getCompletions(inputStr + lastDelimPos + 1, list); dbg.getCompletions(inputStr + lastDelimPos + 1, list); } } if(list.size() < 1) break; sort(list.begin(), list.end()); completionList = list[0]; for(uInt32 i = 1; i < list.size(); ++i) completionList += " " + list[i]; prefix = getCompletionPrefix(list); } // TODO: tab through list if(list.size() == 1) { // add to buffer as though user typed it (plus a space) _currentPos = _promptStartPos + lastDelimPos + 1; const char* clptr = completionList.c_str(); while(*clptr != '\0') putcharIntern(*clptr++); putcharIntern(' '); _promptEndPos = _currentPos; } else { nextLine(); // add to buffer as-is, then add PROMPT plus whatever we have so far _currentPos = _promptStartPos + lastDelimPos + 1; print("\n"); print(completionList); print("\n"); print(PROMPT); _promptStartPos = _currentPos; if(prefix.length() < strLen) { for(int i = 0; i < len; i++) putcharIntern(inputStr[i]); } else { for(int i = 0; i < lastDelimPos; i++) putcharIntern(inputStr[i]); if(lastDelimPos > 0) putcharIntern(delimiter); print(prefix); } _promptEndPos = _currentPos; } dirty = true; break; } case KBDK_BACKSPACE: if (_currentPos > _promptStartPos) killChar(-1); scrollToCurrent(); dirty = true; break; case KBDK_DELETE: killChar(+1); dirty = true; break; case KBDK_PAGEUP: if (StellaModTest::isShift(mod)) { // Don't scroll up when at top of buffer if(_scrollLine < _linesPerPage) break; _scrollLine -= _linesPerPage - 1; if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1) _scrollLine = _firstLineInBuffer + _linesPerPage - 1; updateScrollBuffer(); dirty = true; } break; case KBDK_PAGEDOWN: if (StellaModTest::isShift(mod)) { // Don't scroll down when at bottom of buffer if(_scrollLine >= _promptEndPos / _lineWidth) break; _scrollLine += _linesPerPage - 1; if (_scrollLine > _promptEndPos / _lineWidth) _scrollLine = _promptEndPos / _lineWidth; updateScrollBuffer(); dirty = true; } break; case KBDK_HOME: if (StellaModTest::isShift(mod)) { _scrollLine = _firstLineInBuffer + _linesPerPage - 1; updateScrollBuffer(); } else _currentPos = _promptStartPos; dirty = true; break; case KBDK_END: if (StellaModTest::isShift(mod)) { _scrollLine = _promptEndPos / _lineWidth; if (_scrollLine < _linesPerPage - 1) _scrollLine = _linesPerPage - 1; updateScrollBuffer(); } else _currentPos = _promptEndPos; dirty = true; break; case KBDK_UP: if (StellaModTest::isShift(mod)) { if(_scrollLine <= _firstLineInBuffer + _linesPerPage - 1) break; _scrollLine -= 1; updateScrollBuffer(); dirty = true; } else historyScroll(+1); break; case KBDK_DOWN: if (StellaModTest::isShift(mod)) { // Don't scroll down when at bottom of buffer if(_scrollLine >= _promptEndPos / _lineWidth) break; _scrollLine += 1; updateScrollBuffer(); dirty = true; } else historyScroll(-1); break; case KBDK_RIGHT: if (_currentPos < _promptEndPos) _currentPos++; dirty = true; break; case KBDK_LEFT: if (_currentPos > _promptStartPos) _currentPos--; dirty = true; break; default: if (StellaModTest::isControl(mod)) { specialKeys(key); } else if (StellaModTest::isAlt(mod)) { // Placeholder only - this will never be reached } else handled = false; break; } // Take care of changes made above if(dirty) setDirty(); // There are times when we want the prompt and scrollbar to be marked // as dirty *after* they've been drawn above. One such occurrence is // when we issue a command that indirectly redraws the entire parent // dialog (such as 'scanline' or 'frame'). // In those cases, the return code of the command must be shown, but the // entire dialog contents are redrawn at a later time. So the prompt and // scrollbar won't be redrawn unless they're dirty again. if(_makeDirty) { setDirty(); _scrollBar->setDirty(); _makeDirty = false; } return handled; } #if 0 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::insertIntoPrompt(const char* str) { Int32 l = (Int32)strlen(str); for(Int32 i = _promptEndPos - 1; i >= _currentPos; i--) buffer(i + l) = buffer(i); for(Int32 j = 0; j < l; ++j) { _promptEndPos++; putcharIntern(str[j]); } } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case GuiObject::kSetPositionCmd: int newPos = int(data) + _linesPerPage - 1 + _firstLineInBuffer; if (newPos != _scrollLine) { _scrollLine = newPos; setDirty(); } break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::loadConfig() { // See logic at the end of handleKeyDown for an explanation of this _makeDirty = true; // Show the prompt the first time we draw this widget if(_firstTime) { _firstTime = false; // Display greetings & prompt string version = string("Stella ") + STELLA_VERSION + "\n"; print(version); print(PROMPT); // Take care of one-time debugger stuff // fill the history from the saved breaks, traps and watches commands StringList history; print(instance().debugger().autoExec(&history)); for(uInt32 i = 0; i < history.size(); i++) { addToHistory(history[i].c_str()); } history.clear(); print(instance().debugger().cartDebug().loadConfigFile() + "\n"); print(instance().debugger().cartDebug().loadListFile() + "\n"); print(instance().debugger().cartDebug().loadSymbolFile() + "\n"); print(PROMPT); _promptStartPos = _promptEndPos = _currentPos; _exitedEarly = false; } else if(_exitedEarly) { printPrompt(); _exitedEarly = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int PromptWidget::getWidth() const { return _w + kScrollBarWidth; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::specialKeys(StellaKey key) { bool handled = true; switch(key) { case KBDK_D: killChar(+1); break; case KBDK_K: killLine(+1); break; case KBDK_U: killLine(-1); break; case KBDK_W: killLastWord(); break; case KBDK_A: textSelectAll(); break; case KBDK_X: textCut(); break; case KBDK_C: textCopy(); break; case KBDK_V: textPaste(); break; default: handled = false; break; } if(handled) setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::killChar(int direction) { if(direction == -1) // Delete previous character (backspace) { if(_currentPos <= _promptStartPos) return; _currentPos--; for (int i = _currentPos; i < _promptEndPos; i++) buffer(i) = buffer(i + 1); buffer(_promptEndPos) = ' '; _promptEndPos--; } else if(direction == 1) // Delete next character (delete) { if(_currentPos >= _promptEndPos) return; // There are further characters to the right of cursor if(_currentPos + 1 <= _promptEndPos) { for (int i = _currentPos; i < _promptEndPos; i++) buffer(i) = buffer(i + 1); buffer(_promptEndPos) = ' '; _promptEndPos--; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::killLine(int direction) { if(direction == -1) // erase from current position to beginning of line { int count = _currentPos - _promptStartPos; if(count > 0) for (int i = 0; i < count; i++) killChar(-1); } else if(direction == 1) // erase from current position to end of line { for (int i = _currentPos; i < _promptEndPos; i++) buffer(i) = ' '; _promptEndPos = _currentPos; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::killLastWord() { int cnt = 0; bool space = true; while (_currentPos > _promptStartPos) { if ((buffer(_currentPos - 1) & 0xff) == ' ') { if (!space) break; } else space = false; _currentPos--; cnt++; } for (int i = _currentPos; i < _promptEndPos; i++) buffer(i) = buffer(i + cnt); buffer(_promptEndPos) = ' '; _promptEndPos -= cnt; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::textSelectAll() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::textCut() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::textCopy() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::textPaste() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::addToHistory(const char* str) { strncpy(_history[_historyIndex], str, kLineBufferSize-1); _historyIndex = (_historyIndex + 1) % kHistorySize; _historyLine = 0; if (_historySize < kHistorySize) _historySize++; } #if 0 // FIXME // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int PromptWidget::compareHistory(const char *histLine) { return 1; } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::historyScroll(int direction) { if (_historySize == 0) return; if (_historyLine == 0 && direction > 0) { int i; for (i = 0; i < _promptEndPos - _promptStartPos; i++) _history[_historyIndex][i] = buffer(_promptStartPos + i); _history[_historyIndex][i] = '\0'; } // Advance to the next line in the history int line = _historyLine + direction; if(line < 0) line += _historySize + 1; line %= (_historySize + 1); // If they press arrow-up with anything in the buffer, search backwards // in the history. /* if(direction < 0 && _currentPos > _promptStartPos) { for(;line > 0; line--) { if(compareHistory(_history[line]) == 0) break; } } */ _historyLine = line; // Remove the current user text _currentPos = _promptStartPos; killLine(1); // to end of line // ... and ensure the prompt is visible scrollToCurrent(); // Print the text from the history int idx; if (_historyLine > 0) idx = (_historyIndex - _historyLine + _historySize) % _historySize; else idx = _historyIndex; for (int i = 0; i < kLineBufferSize && _history[idx][i] != '\0'; i++) putcharIntern(_history[idx][i]); _promptEndPos = _currentPos; // Ensure once more the caret is visible (in case of very long history entries) scrollToCurrent(); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::nextLine() { // Reset colors every line, so I don't have to remember to do it myself _textcolor = kTextColor; _inverse = false; int line = _currentPos / _lineWidth; if (line == _scrollLine) _scrollLine++; _currentPos = (line + 1) * _lineWidth; updateScrollBuffer(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Call this (at least) when the current line changes or when a new line is added void PromptWidget::updateScrollBuffer() { int lastchar = std::max(_promptEndPos, _currentPos); int line = lastchar / _lineWidth; int numlines = (line < _linesInBuffer) ? line + 1 : _linesInBuffer; int firstline = line - numlines + 1; if (firstline > _firstLineInBuffer) { // clear old line from buffer for (int i = lastchar; i < (line+1) * _lineWidth; ++i) buffer(i) = ' '; _firstLineInBuffer = firstline; } _scrollBar->_numEntries = numlines; _scrollBar->_currentPos = _scrollBar->_numEntries - (line - _scrollLine + _linesPerPage); _scrollBar->_entriesPerPage = _linesPerPage; _scrollBar->recalc(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int PromptWidget::printf(const char* format, ...) { va_list argptr; va_start(argptr, format); int count = this->vprintf(format, argptr); va_end (argptr); return count; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int PromptWidget::vprintf(const char* format, va_list argptr) { char buf[2048]; // Note: generates warnings about 'nonliteral' format int count = std::vsnprintf(buf, sizeof(buf), format, argptr); print(buf); return count; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::putcharIntern(int c) { if (c == '\n') nextLine(); else if(c & 0x80) { // set foreground color to TIA color // don't print or advance cursor // there are only 128 TIA colors, but // OverlayColor contains 256 of them _textcolor = (c & 0x7f) << 1; } else if(c && c < 0x1e) { // first actual character is large dash // More colors (the regular GUI ones) _textcolor = c + 0x100; } else if(c == 0x7f) { // toggle inverse video (DEL char) _inverse = !_inverse; } else if(isprint(c)) { buffer(_currentPos) = c | (_textcolor << 8) | (_inverse << 17); _currentPos++; if ((_scrollLine + 1) * _lineWidth == _currentPos) { _scrollLine++; updateScrollBuffer(); } } setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::print(const string& str) { for(char c: str) putcharIntern(c); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::drawCaret() { //cerr << "PromptWidget::drawCaret()\n"; FBSurface& s = _boss->dialog().surface(); int line = _currentPos / _lineWidth; // Don't draw the cursor if it's not in the current view if(_scrollLine < line) return; int displayLine = line - _scrollLine + _linesPerPage - 1; int x = _x + 1 + (_currentPos % _lineWidth) * _kConsoleCharWidth; int y = _y + displayLine * _kConsoleLineHeight; char c = buffer(_currentPos); s.fillRect(x, y, _kConsoleCharWidth, _kConsoleLineHeight, kTextColor); s.drawChar(_font, c, x, y + 2, kBGColor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::scrollToCurrent() { int line = _promptEndPos / _lineWidth; if (line + _linesPerPage <= _scrollLine) { // TODO - this should only occur for long edit lines, though } else if (line > _scrollLine) { _scrollLine = line; updateScrollBuffer(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PromptWidget::saveBuffer(const FilesystemNode& file) { ofstream out(file.getPath()); if(!out.is_open()) return false; for(int start = 0; start < _promptStartPos; start += _lineWidth) { int end = start + _lineWidth - 1; // Look for first non-space, printing char from end of line while( char(_buffer[end] & 0xff) <= ' ' && end >= start) end--; // Spit out the line minus its trailing junk // Strip off any color/inverse bits for(int j = start; j <= end; ++j) out << char(_buffer[j] & 0xff); // add a \n out << endl; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string PromptWidget::getCompletionPrefix(const StringList& completions) { // Find the number of characters matching for each of the completions provided for(uInt32 len = 1;; len++) { for(uInt32 i = 0; i < completions.size(); i++) { string s1 = completions[i]; if(s1.length() < len) { return s1.substr(0, len - 1); } string find = s1.substr(0, len); for(uInt32 j = i + 1; j < completions.size(); j++) { if(!BSPF::startsWithIgnoreCase(completions[j], find)) return s1.substr(0, len - 1); } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PromptWidget::clearScreen() { // Initialize start position _currentPos = 0; _scrollLine = _linesPerPage - 1; _firstLineInBuffer = 0; _promptStartPos = _promptEndPos = -1; memset(_buffer, 0, kBufferSize * sizeof(int)); if(!_firstTime) updateScrollBuffer(); } stella-5.1.1/src/debugger/gui/PromptWidget.hxx000066400000000000000000000072661324334165500213400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PROMPT_WIDGET_HXX #define PROMPT_WIDGET_HXX #include class ScrollBarWidget; class FilesystemNode; #include "Widget.hxx" #include "Command.hxx" #include "bspf.hxx" class PromptWidget : public Widget, public CommandSender { public: PromptWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~PromptWidget() = default; public: ATTRIBUTE_FMT_PRINTF int printf(const char* format, ...); ATTRIBUTE_FMT_PRINTF int vprintf(const char* format, va_list argptr); void print(const string& str); void printPrompt(); bool saveBuffer(const FilesystemNode& file); // Clear screen and erase all history void clearScreen(); protected: int& buffer(int idx) { return _buffer[idx % kBufferSize]; } void drawWidget(bool hilite) override; void drawCaret(); void putcharIntern(int c); // void insertIntoPrompt(const char *str); void updateScrollBuffer(); void scrollToCurrent(); // Line editing void specialKeys(StellaKey key); void nextLine(); void killChar(int direction); void killLine(int direction); void killLastWord(); // Clipboard void textSelectAll(); void textCut(); void textCopy(); void textPaste(); // History void addToHistory(const char *str); void historyScroll(int direction); void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; bool handleText(char text) override; bool handleKeyDown(StellaKey key, StellaMod mod) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Account for the extra width of embedded scrollbar int getWidth() const override; bool wantsFocus() const override { return true; } void loadConfig() override; private: // Get the longest prefix (initially 's') that is in every string in the list string getCompletionPrefix(const StringList& completions); private: enum { kBufferSize = 32768, kLineBufferSize = 256, kHistorySize = 20 }; int _buffer[kBufferSize]; int _linesInBuffer; int _lineWidth; int _linesPerPage; int _currentPos; int _scrollLine; int _firstLineInBuffer; int _promptStartPos; int _promptEndPos; ScrollBarWidget* _scrollBar; char _history[kHistorySize][kLineBufferSize]; int _historySize; int _historyIndex; int _historyLine; int _kConsoleCharWidth, _kConsoleCharHeight, _kConsoleLineHeight; bool _inverse; bool _makeDirty; bool _firstTime; bool _exitedEarly; // int compareHistory(const char *histLine); private: // Following constructors and assignment operators not supported PromptWidget() = delete; PromptWidget(const PromptWidget&) = delete; PromptWidget(PromptWidget&&) = delete; PromptWidget& operator=(const PromptWidget&) = delete; PromptWidget& operator=(PromptWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/RamWidget.cxx000066400000000000000000000345051324334165500205650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "GuiObject.hxx" #include "InputTextDialog.hxx" #include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "Font.hxx" #include "Widget.hxx" #include "RamWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RamWidget::RamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, uInt32 ramsize, uInt32 numrows, uInt32 pagesize) : Widget(boss, lfont, x, y, w, h), CommandSender(boss), _nfont(nfont), myFontWidth(lfont.getMaxCharWidth()), myFontHeight(lfont.getFontHeight()), myLineHeight(lfont.getLineHeight()), myButtonHeight(myLineHeight + 4), myCurrentRamBank(0), myRamSize(ramsize), myNumRows(numrows), myPageSize(pagesize) { const string ELLIPSIS = "\x1d"; const int bwidth = lfont.getStringWidth("Compare " + ELLIPSIS), bheight = myLineHeight + 2; const int VGAP = 4; int ypos = y + myLineHeight; // Add RAM grid (with scrollbar) int xpos = x + _font.getStringWidth("xxxx"); myRamGrid = new DataGridWidget(_boss, _nfont, xpos, ypos, 16, myNumRows, 2, 8, Common::Base::F_16, true); myRamGrid->setTarget(this); myRamGrid->setID(kRamHexID); addFocusWidget(myRamGrid); // Create actions buttons to the left of the RAM grid int bx = xpos + myRamGrid->getWidth() + 4; int by = ypos; myUndoButton = new ButtonWidget(boss, lfont, bx, by, bwidth, bheight, "Undo", kUndoCmd); myUndoButton->setTarget(this); by += bheight + VGAP; myRevertButton = new ButtonWidget(boss, lfont, bx, by, bwidth, bheight, "Revert", kRevertCmd); myRevertButton->setTarget(this); by += bheight + VGAP * 6; mySearchButton = new ButtonWidget(boss, lfont, bx, by, bwidth, bheight, "Search" + ELLIPSIS, kSearchCmd); mySearchButton->setTarget(this); by += bheight + VGAP; myCompareButton = new ButtonWidget(boss, lfont, bx, by, bwidth, bheight, "Compare" + ELLIPSIS, kCmpCmd); myCompareButton->setTarget(this); by += bheight + VGAP; myRestartButton = new ButtonWidget(boss, lfont, bx, by, bwidth, bheight, "Reset", kRestartCmd); myRestartButton->setTarget(this); // Labels for RAM grid myRamStart = new StaticTextWidget(_boss, lfont, xpos - _font.getStringWidth("xxxx"), ypos - myLineHeight, lfont.getStringWidth("xxxx"), myFontHeight, "00xx", TextAlign::Left); for(int col = 0; col < 16; ++col) { new StaticTextWidget(_boss, lfont, xpos + col*myRamGrid->colWidth() + 8, ypos - myLineHeight, myFontWidth, myFontHeight, Common::Base::toString(col, Common::Base::F_16_1), TextAlign::Left); } uInt32 row; for(row = 0; row < myNumRows; ++row) { myRamLabels[row] = new StaticTextWidget(_boss, _font, xpos - _font.getStringWidth("x "), ypos + row*myLineHeight + 2, myFontWidth, myFontHeight, "", TextAlign::Left); } // For smaller grids, make sure RAM cell detail fields are below the RESET button row = myNumRows < 8 ? 9 : myNumRows + 1; ypos += row * myLineHeight; // We need to define these widgets from right to left since the leftmost // one resizes as much as possible // Add Binary display of selected RAM cell xpos = x + w - 11*myFontWidth - 22; new StaticTextWidget(boss, lfont, xpos, ypos, "Bin"); myBinValue = new DataGridWidget(boss, nfont, xpos + 3*myFontWidth + 5, ypos-2, 1, 1, 8, 8, Common::Base::F_2); myBinValue->setTarget(this); myBinValue->setID(kRamBinID); // Add Decimal display of selected RAM cell xpos -= 7*myFontWidth + 5 + 20; new StaticTextWidget(boss, lfont, xpos, ypos, "Dec"); myDecValue = new DataGridWidget(boss, nfont, xpos + 3*myFontWidth + 5, ypos-2, 1, 1, 3, 8, Common::Base::F_10); myDecValue->setTarget(this); myDecValue->setID(kRamDecID); addFocusWidget(myDecValue); addFocusWidget(myBinValue); // Add Label of selected RAM cell int xpos_r = xpos - 20; xpos = x; new StaticTextWidget(boss, lfont, xpos, ypos, "Label"); xpos += 5*myFontWidth + 5; myLabel = new EditTextWidget(boss, nfont, xpos, ypos-2, xpos_r-xpos, myLineHeight); myLabel->setEditable(false, true); // Inputbox which will pop up when searching RAM StringList labels = { "Search " }; myInputBox = make_unique(boss, lfont, nfont, labels); myInputBox->setTarget(this); // Start with these buttons disabled myCompareButton->clearFlags(WIDGET_ENABLED); myRestartButton->clearFlags(WIDGET_ENABLED); // Calculate final height if(_h == 0) _h = ypos + myLineHeight - y; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RamWidget::~RamWidget() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { // We simply change the values in the DataGridWidget // It will then send the 'kDGItemDataChangedCmd' signal to change the actual // memory location int addr = 0, value = 0; switch(cmd) { case DataGridWidget::kItemDataChangedCmd: { switch(id) { case kRamHexID: addr = myRamGrid->getSelectedAddr(); value = myRamGrid->getSelectedValue(); break; case kRamDecID: addr = myRamGrid->getSelectedAddr(); value = myDecValue->getSelectedValue(); break; case kRamBinID: addr = myRamGrid->getSelectedAddr(); value = myBinValue->getSelectedValue(); break; } uInt8 oldval = getValue(addr); setValue(addr, value); myUndoAddress = addr; myUndoValue = oldval; myRamGrid->setValueInternal(addr - myCurrentRamBank*myPageSize, value, true); myDecValue->setValueInternal(0, value, true); myBinValue->setValueInternal(0, value, true); myRevertButton->setEnabled(true); myUndoButton->setEnabled(true); break; } case DataGridWidget::kSelectionChangedCmd: { addr = myRamGrid->getSelectedAddr(); value = myRamGrid->getSelectedValue(); myLabel->setText(getLabel(addr)); myDecValue->setValueInternal(0, value, false); myBinValue->setValueInternal(0, value, false); break; } case kRevertCmd: for(uInt32 i = 0; i < myOldValueList.size(); ++i) setValue(i, myOldValueList[i]); fillGrid(true); break; case kUndoCmd: setValue(myUndoAddress, myUndoValue); myUndoButton->setEnabled(false); fillGrid(false); break; case kSearchCmd: showInputBox(kSValEntered); break; case kCmpCmd: showInputBox(kCValEntered); break; case kRestartCmd: doRestart(); break; case kSValEntered: { const string& result = doSearch(myInputBox->getResult()); if(result != "") myInputBox->setTitle(result); else myInputBox->close(); break; } case kCValEntered: { const string& result = doCompare(myInputBox->getResult()); if(result != "") myInputBox->setTitle(result); else myInputBox->close(); break; } case GuiObject::kSetPositionCmd: myCurrentRamBank = data; showSearchResults(); fillGrid(false); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::setOpsWidget(DataGridOpsWidget* w) { myRamGrid->setOpsWidget(w); myBinValue->setOpsWidget(w); myDecValue->setOpsWidget(w); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::loadConfig() { fillGrid(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::fillGrid(bool updateOld) { IntArray alist; IntArray vlist; BoolArray changed; uInt32 start = myCurrentRamBank * myPageSize; fillList(start, myPageSize, alist, vlist, changed); if(updateOld) myOldValueList = currentRam(start); myRamGrid->setNumRows(myRamSize / myPageSize); myRamGrid->setList(alist, vlist, changed); if(updateOld) { myRevertButton->setEnabled(false); myUndoButton->setEnabled(false); } // Update RAM labels uInt32 rport = readPort(start), page = rport & 0xf0; char buf[5]; std::snprintf(buf, 5, "%04X", rport); buf[2] = buf[3] = 'x'; myRamStart->setLabel(buf); for(uInt32 row = 0; row < myNumRows; ++row, page += 0x10) myRamLabels[row]->setLabel(Common::Base::toString(page>>4, Common::Base::F_16_1)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::showInputBox(int cmd) { // Add inputbox in the middle of the RAM widget uInt32 x = getAbsX() + ((getWidth() - myInputBox->getWidth()) >> 1); uInt32 y = getAbsY() + ((getHeight() - myInputBox->getHeight()) >> 1); myInputBox->show(x, y); myInputBox->setText(""); myInputBox->setTitle(""); myInputBox->setFocus(0); myInputBox->setEmitSignal(cmd); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RamWidget::doSearch(const string& str) { bool comparisonSearch = true; if(str.length() == 0) { // An empty field means return all memory locations comparisonSearch = false; } else if(str.find_first_of("+-", 0) != string::npos) { // Don't accept these characters here, only in compare return "Invalid input +|-"; } int searchVal = instance().debugger().stringToValue(str); // Clear the search array of previous items mySearchAddr.clear(); mySearchValue.clear(); mySearchState.clear(); // Now, search all memory locations for this value, and add it to the // search array const ByteArray& ram = currentRam(0); bool hitfound = false; for(uInt32 addr = 0; addr < ram.size(); ++addr) { int value = ram[addr]; if(comparisonSearch && searchVal != value) { mySearchState.push_back(false); } else { mySearchAddr.push_back(addr); mySearchValue.push_back(value); mySearchState.push_back(true); hitfound = true; } } // If we have some hits, enable the comparison methods if(hitfound) { mySearchButton->setEnabled(false); myCompareButton->setEnabled(true); myRestartButton->setEnabled(true); } // Finally, show the search results in the list showSearchResults(); return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RamWidget::doCompare(const string& str) { bool comparativeSearch = false; int searchVal = 0, offset = 0; if(str.length() == 0) return "Enter an absolute or comparative value"; // Do some pre-processing on the string string::size_type pos = str.find_first_of("+-", 0); if(pos > 0 && pos != string::npos) { // Only accept '+' or '-' at the start of the string return "Input must be [+|-]NUM"; } // A comparative search searches memory for locations that have changed by // the specified amount, vs. for exact values if(str[0] == '+' || str[0] == '-') { comparativeSearch = true; bool negative = false; if(str[0] == '-') negative = true; string tmp = str; tmp.erase(0, 1); // remove the operator offset = instance().debugger().stringToValue(tmp); if(negative) offset = -offset; } else searchVal = instance().debugger().stringToValue(str); // Now, search all memory locations previously 'found' for this value const ByteArray& ram = currentRam(0); bool hitfound = false; IntArray tempAddrList, tempValueList; mySearchState.clear(); for(uInt32 i = 0; i < ram.size(); ++i) mySearchState.push_back(false); for(uInt32 i = 0; i < mySearchAddr.size(); ++i) { if(comparativeSearch) { searchVal = mySearchValue[i] + offset; if(searchVal < 0 || searchVal > 255) continue; } int addr = mySearchAddr[i]; if(ram[addr] == searchVal) { tempAddrList.push_back(addr); tempValueList.push_back(searchVal); mySearchState[addr] = hitfound = true; } } // Update the searchArray for the new addresses and data mySearchAddr = tempAddrList; mySearchValue = tempValueList; // If we have some hits, enable the comparison methods if(hitfound) { myCompareButton->setEnabled(true); myRestartButton->setEnabled(true); } // Finally, show the search results in the list showSearchResults(); return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::doRestart() { // Erase all search buffers, reset to start mode mySearchAddr.clear(); mySearchValue.clear(); mySearchState.clear(); showSearchResults(); mySearchButton->setEnabled(true); myCompareButton->setEnabled(false); myRestartButton->setEnabled(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RamWidget::showSearchResults() { // Only update the search results for the bank currently being shown BoolArray temp; uInt32 start = myCurrentRamBank * myPageSize; if(mySearchState.size() == 0 || start > mySearchState.size()) { for(uInt32 i = 0; i < myPageSize; ++i) temp.push_back(false); } else { for(uInt32 i = start; i < start + myPageSize; ++i) temp.push_back(mySearchState[i]); } myRamGrid->setHiliteList(temp); } stella-5.1.1/src/debugger/gui/RamWidget.hxx000066400000000000000000000067751324334165500206020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef RAM_WIDGET_HXX #define RAM_WIDGET_HXX class GuiObject; class ButtonWidget; class DataGridWidget; class DataGridOpsWidget; class EditTextWidget; class StaticTextWidget; class InputTextDialog; #include "Widget.hxx" #include "Command.hxx" class RamWidget : public Widget, public CommandSender { public: RamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h, uInt32 ramsize, uInt32 numrows, uInt32 pagesize); virtual ~RamWidget(); void loadConfig() override; void setOpsWidget(DataGridOpsWidget* w); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: // To be implemented by derived classes virtual uInt8 getValue(int addr) const = 0; virtual void setValue(int addr, uInt8 value) = 0; virtual string getLabel(int addr) const = 0; virtual void fillList(uInt32 start, uInt32 size, IntArray& alist, IntArray& vlist, BoolArray& changed) const = 0; virtual uInt32 readPort(uInt32 start) const = 0; virtual const ByteArray& currentRam(uInt32 start) const = 0; private: void fillGrid(bool updateOld); void showInputBox(int cmd); string doSearch(const string& str); string doCompare(const string& str); void doRestart(); void showSearchResults(); protected: // Font used for 'normal' text; _font is for 'label' text const GUI::Font& _nfont; // These will be needed by most of the child classes; // we may as well make them protected variables int myFontWidth, myFontHeight, myLineHeight, myButtonHeight; private: enum { kUndoCmd = 'RWud', kRevertCmd = 'RWrv', kSearchCmd = 'RWse', kCmpCmd = 'RWcp', kRestartCmd = 'RWrs', kSValEntered = 'RWsv', kCValEntered = 'RWcv', kRamHexID, kRamDecID, kRamBinID }; uInt32 myUndoAddress, myUndoValue; uInt32 myCurrentRamBank; uInt32 myRamSize; uInt32 myNumRows; uInt32 myPageSize; unique_ptr myInputBox; StaticTextWidget* myRamStart; StaticTextWidget* myRamLabels[16]; DataGridWidget* myRamGrid; DataGridWidget* myDecValue; DataGridWidget* myBinValue; EditTextWidget* myLabel; ButtonWidget* myRevertButton; ButtonWidget* myUndoButton; ButtonWidget* mySearchButton; ButtonWidget* myCompareButton; ButtonWidget* myRestartButton; ByteArray myOldValueList; IntArray mySearchAddr; IntArray mySearchValue; BoolArray mySearchState; private: // Following constructors and assignment operators not supported RamWidget() = delete; RamWidget(const RamWidget&) = delete; RamWidget(RamWidget&&) = delete; RamWidget& operator=(const RamWidget&) = delete; RamWidget& operator=(RamWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/RiotRamWidget.cxx000066400000000000000000000055331324334165500214220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Debugger.hxx" #include "CartDebug.hxx" #include "RiotRamWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RiotRamWidget::RiotRamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w) : RamWidget(boss, lfont, nfont, x, y, w, 0, 128, 8, 128), myDbg(instance().debugger().cartDebug()) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 RiotRamWidget::getValue(int addr) const { const CartState& state = static_cast(myDbg.getState()); return instance().debugger().peek(state.rport[addr]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RiotRamWidget::setValue(int addr, uInt8 value) { const CartState& state = static_cast(myDbg.getState()); instance().debugger().poke(state.wport[addr], value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string RiotRamWidget::getLabel(int addr) const { const CartState& state = static_cast(myDbg.getState()); return myDbg.getLabel(state.rport[addr], true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RiotRamWidget::fillList(uInt32 start, uInt32 size, IntArray& alist, IntArray& vlist, BoolArray& changed) const { const CartState& state = static_cast(myDbg.getState()); const CartState& oldstate = static_cast(myDbg.getOldState()); for(uInt32 i = 0; i < size; i++) { alist.push_back(i+start); vlist.push_back(state.ram[i]); changed.push_back(state.ram[i] != oldstate.ram[i]); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 RiotRamWidget::readPort(uInt32 start) const { const CartState& state = static_cast(myDbg.getState()); return state.rport[start]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const ByteArray& RiotRamWidget::currentRam(uInt32) const { const CartState& state = static_cast(myDbg.getState()); return state.ram; } stella-5.1.1/src/debugger/gui/RiotRamWidget.hxx000066400000000000000000000035271324334165500214300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef RIOT_RAM_WIDGET_HXX #define RIOT_RAM_WIDGET_HXX class GuiObject; class InputTextDialog; class ButtonWidget; class DataGridWidget; class DataGridOpsWidget; class EditTextWidget; class StaticTextWidget; class CartDebug; #include "RamWidget.hxx" class RiotRamWidget : public RamWidget { public: RiotRamWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w); virtual ~RiotRamWidget() = default; private: uInt8 getValue(int addr) const; void setValue(int addr, uInt8 value); string getLabel(int addr) const; void fillList(uInt32 start, uInt32 size, IntArray& alist, IntArray& vlist, BoolArray& changed) const; uInt32 readPort(uInt32 start) const; const ByteArray& currentRam(uInt32 start) const; private: CartDebug& myDbg; private: // Following constructors and assignment operators not supported RiotRamWidget() = delete; RiotRamWidget(const RiotRamWidget&) = delete; RiotRamWidget(RiotRamWidget&&) = delete; RiotRamWidget& operator=(const RiotRamWidget&) = delete; RiotRamWidget& operator=(RiotRamWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/RiotWidget.cxx000066400000000000000000000445431324334165500207660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Settings.hxx" #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "FrameBuffer.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "Debugger.hxx" #include "RiotDebug.hxx" #include "PopUpWidget.hxx" #include "ToggleBitWidget.hxx" #include "Widget.hxx" #include "NullControlWidget.hxx" #include "JoystickWidget.hxx" #include "PaddleWidget.hxx" #include "BoosterWidget.hxx" #include "DrivingWidget.hxx" #include "GenesisWidget.hxx" #include "KeyboardWidget.hxx" #include "AtariVoxWidget.hxx" #include "SaveKeyWidget.hxx" #include "AmigaMouseWidget.hxx" #include "AtariMouseWidget.hxx" #include "TrakBallWidget.hxx" #include "RiotWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) : Widget(boss, lfont, x, y, w, h), CommandSender(boss) { const int fontWidth = lfont.getMaxCharWidth(), fontHeight = lfont.getFontHeight(), lineHeight = lfont.getLineHeight(); int xpos = 10, ypos = 25, lwidth = 8 * fontWidth, col = 0; StaticTextWidget* t; VariantList items; // Set the strings to be used in the various bit registers // We only do this once because it's the state that changes, not the strings StringList off, on; for(int i = 0; i < 8; ++i) { off.push_back("0"); on.push_back("1"); } #define CREATE_IO_REGS(desc, bits, bitsID, editable) \ t = new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight,\ desc, TextAlign::Left); \ xpos += t->getWidth() + 5; \ bits = new ToggleBitWidget(boss, nfont, xpos, ypos, 8, 1); \ bits->setTarget(this); \ bits->setID(bitsID); \ if(editable) addFocusWidget(bits); else bits->setEditable(false); \ xpos += bits->getWidth() + 5; \ bits->setList(off, on); // SWCHA bits in 'poke' mode CREATE_IO_REGS("SWCHA(W)", mySWCHAWriteBits, kSWCHABitsID, true); col = xpos + 20; // remember this for adding widgets to the second column // SWACNT bits xpos = 10; ypos += lineHeight + 5; CREATE_IO_REGS("SWACNT", mySWACNTBits, kSWACNTBitsID, true); // SWCHA bits in 'peek' mode xpos = 10; ypos += lineHeight + 5; CREATE_IO_REGS("SWCHA(R)", mySWCHAReadBits, kSWCHARBitsID, true); // SWCHB bits in 'poke' mode xpos = 10; ypos += 2 * lineHeight; CREATE_IO_REGS("SWCHB(W)", mySWCHBWriteBits, kSWCHBBitsID, true); // SWBCNT bits xpos = 10; ypos += lineHeight + 5; CREATE_IO_REGS("SWBCNT", mySWBCNTBits, kSWBCNTBitsID, true); // SWCHB bits in 'peek' mode xpos = 10; ypos += lineHeight + 5; CREATE_IO_REGS("SWCHB(R)", mySWCHBReadBits, 0, false); // Timer registers (R/W) const char* const writeNames[] = { "TIM1T", "TIM8T", "TIM64T", "T1024T" }; xpos = 10; ypos += 2*lineHeight; for(int row = 0; row < 4; ++row) { t = new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2, lwidth, fontHeight, writeNames[row], TextAlign::Left); } xpos += t->getWidth() + 5; myTimWrite = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 2, 8, Common::Base::F_16); myTimWrite->setTarget(this); myTimWrite->setID(kTimWriteID); addFocusWidget(myTimWrite); // Timer registers (RO) const char* const readNames[] = { "INTIM", "TIMINT", "Total Clks", "INTIM Clks" }; xpos = 10; ypos += myTimWrite->getHeight() + lineHeight; for(int row = 0; row < 4; ++row) { t = new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2, 10*fontWidth, fontHeight, readNames[row], TextAlign::Left); } xpos += t->getWidth() + 5; myTimRead = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 8, 32, Common::Base::F_16); myTimRead->setTarget(this); myTimRead->setEditable(false); // Controller ports const RiotDebug& riot = instance().debugger().riotDebug(); xpos = col; ypos = 10; myLeftControl = addControlWidget(boss, lfont, xpos, ypos, riot.controller(Controller::Left)); xpos += myLeftControl->getWidth() + 15; myRightControl = addControlWidget(boss, lfont, xpos, ypos, riot.controller(Controller::Right)); // TIA INPTx registers (R), left port const char* const contLeftReadNames[] = { "INPT0", "INPT1", "INPT4" }; xpos = col; ypos += myLeftControl->getHeight() + 2 * lineHeight; for(int row = 0; row < 3; ++row) { new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2, 5*fontWidth, fontHeight, contLeftReadNames[row], TextAlign::Left); } xpos += 5*fontWidth + 5; myLeftINPT = new DataGridWidget(boss, nfont, xpos, ypos, 1, 3, 2, 8, Common::Base::F_16); myLeftINPT->setTarget(this); myLeftINPT->setEditable(false); // TIA INPTx registers (R), right port const char* const contRightReadNames[] = { "INPT2", "INPT3", "INPT5" }; xpos = col + myLeftControl->getWidth() + 15; for(int row = 0; row < 3; ++row) { new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2, 5*fontWidth, fontHeight, contRightReadNames[row], TextAlign::Left); } xpos += 5*fontWidth + 5; myRightINPT = new DataGridWidget(boss, nfont, xpos, ypos, 1, 3, 2, 8, Common::Base::F_16); myRightINPT->setTarget(this); myRightINPT->setEditable(false); // TIA INPTx VBLANK bits (D6-latch, D7-dump) (R) xpos = col + 20; ypos += myLeftINPT->getHeight() + lineHeight; myINPTLatch = new CheckboxWidget(boss, lfont, xpos, ypos, "INPT latch (VBlank D6)"); myINPTLatch->setTarget(this); myINPTLatch->setEditable(false); ypos += lineHeight + 5; myINPTDump = new CheckboxWidget(boss, lfont, xpos, ypos, "INPT dump to gnd (VBlank D7)"); myINPTDump->setTarget(this); myINPTDump->setEditable(false); // PO & P1 difficulty switches int pwidth = lfont.getStringWidth("B/easy"); lwidth = lfont.getStringWidth("P0 Diff "); xpos = col; ypos += 2 * lineHeight; int col2_ypos = ypos; items.clear(); VarList::push_back(items, "B/easy", "b"); VarList::push_back(items, "A/hard", "a"); myP0Diff = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items, "P0 Diff ", lwidth, kP0DiffChanged); myP0Diff->setTarget(this); addFocusWidget(myP0Diff); ypos += myP0Diff->getHeight() + 5; myP1Diff = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items, "P1 Diff ", lwidth, kP1DiffChanged); myP1Diff->setTarget(this); addFocusWidget(myP1Diff); // TV Type ypos += myP1Diff->getHeight() + 5; items.clear(); VarList::push_back(items, "B&W", "bw"); VarList::push_back(items, "Color", "color"); myTVType = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items, "TV Type ", lwidth, kTVTypeChanged); myTVType->setTarget(this); addFocusWidget(myTVType); // 2600/7800 mode lwidth = lfont.getStringWidth("Console") + 29; pwidth = lfont.getStringWidth("Atari 2600") + 4; new StaticTextWidget(boss, lfont, 10, ypos+1, "Console"); myConsole = new EditTextWidget(boss, lfont, 10 + lwidth, ypos - 1, pwidth, lineHeight); myConsole->setEditable(false, true); addFocusWidget(myConsole); // Select and Reset xpos += myP0Diff->getWidth() + 20; ypos = col2_ypos + 1; mySelect = new CheckboxWidget(boss, lfont, xpos, ypos, "Select", CheckboxWidget::kCheckActionCmd); mySelect->setID(kSelectID); mySelect->setTarget(this); addFocusWidget(mySelect); ypos += myP0Diff->getHeight() + 5; myReset = new CheckboxWidget(boss, lfont, xpos, ypos, "Reset", CheckboxWidget::kCheckActionCmd); myReset->setID(kResetID); myReset->setTarget(this); addFocusWidget(myReset); ypos += myP0Diff->getHeight() + 5; myPause = new CheckboxWidget(boss, lfont, xpos, ypos, "Pause", CheckboxWidget::kCheckActionCmd); myPause->setID(kPauseID); myPause->setTarget(this); addFocusWidget(myPause); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RiotWidget::loadConfig() { #define IO_REGS_UPDATE(bits, s_bits) \ changed.clear(); \ for(uInt32 i = 0; i < state.s_bits.size(); ++i) \ changed.push_back(state.s_bits[i] != oldstate.s_bits[i]); \ bits->setState(state.s_bits, changed); IntArray alist; IntArray vlist; BoolArray changed; // We push the enumerated items as addresses, and deal with the real // address in the callback (handleCommand) Debugger& dbg = instance().debugger(); RiotDebug& riot = dbg.riotDebug(); const RiotState& state = static_cast(riot.getState()); const RiotState& oldstate = static_cast(riot.getOldState()); // Update the SWCHA register booleans (poke mode) IO_REGS_UPDATE(mySWCHAWriteBits, swchaWriteBits); // Update the SWACNT register booleans IO_REGS_UPDATE(mySWACNTBits, swacntBits); // Update the SWCHA register booleans (peek mode) IO_REGS_UPDATE(mySWCHAReadBits, swchaReadBits); // Update the SWCHB register booleans (poke mode) IO_REGS_UPDATE(mySWCHBWriteBits, swchbWriteBits); // Update the SWBCNT register booleans IO_REGS_UPDATE(mySWBCNTBits, swbcntBits); // Update the SWCHB register booleans (peek mode) IO_REGS_UPDATE(mySWCHBReadBits, swchbReadBits); // Update TIA INPTx registers alist.clear(); vlist.clear(); changed.clear(); alist.push_back(0); vlist.push_back(state.INPT0); changed.push_back(state.INPT0 != oldstate.INPT0); alist.push_back(1); vlist.push_back(state.INPT1); changed.push_back(state.INPT1 != oldstate.INPT1); alist.push_back(4); vlist.push_back(state.INPT4); changed.push_back(state.INPT4 != oldstate.INPT4); myLeftINPT->setList(alist, vlist, changed); alist.clear(); vlist.clear(); changed.clear(); alist.push_back(2); vlist.push_back(state.INPT2); changed.push_back(state.INPT2 != oldstate.INPT2); alist.push_back(3); vlist.push_back(state.INPT3); changed.push_back(state.INPT3 != oldstate.INPT3); alist.push_back(5); vlist.push_back(state.INPT5); changed.push_back(state.INPT5 != oldstate.INPT5); myRightINPT->setList(alist, vlist, changed); // Update TIA VBLANK bits myINPTLatch->setState(riot.vblank(6), state.INPTLatch != oldstate.INPTLatch); myINPTDump->setState(riot.vblank(7), state.INPTDump != oldstate.INPTDump); // Update timer write registers alist.clear(); vlist.clear(); changed.clear(); alist.push_back(kTim1TID); vlist.push_back(state.TIM1T); changed.push_back(state.TIM1T != oldstate.TIM1T); alist.push_back(kTim8TID); vlist.push_back(state.TIM8T); changed.push_back(state.TIM8T != oldstate.TIM8T); alist.push_back(kTim64TID); vlist.push_back(state.TIM64T); changed.push_back(state.TIM64T != oldstate.TIM64T); alist.push_back(kTim1024TID); vlist.push_back(state.T1024T); changed.push_back(state.T1024T != oldstate.T1024T); myTimWrite->setList(alist, vlist, changed); // Update timer read registers alist.clear(); vlist.clear(); changed.clear(); alist.push_back(0); vlist.push_back(state.INTIM); changed.push_back(state.INTIM != oldstate.INTIM); alist.push_back(0); vlist.push_back(state.TIMINT); changed.push_back(state.TIMINT != oldstate.TIMINT); alist.push_back(0); vlist.push_back(state.TIMCLKS); changed.push_back(state.TIMCLKS != oldstate.TIMCLKS); alist.push_back(0); vlist.push_back(state.INTIMCLKS); changed.push_back(state.INTIMCLKS != oldstate.INTIMCLKS); myTimRead->setList(alist, vlist, changed); // Console switches (inverted, since 'selected' in the UI // means 'grounded' in the system) myP0Diff->setSelectedIndex(riot.diffP0(), state.swchbReadBits[1] != oldstate.swchbReadBits[1]); myP1Diff->setSelectedIndex(riot.diffP1(), state.swchbReadBits[0] != oldstate.swchbReadBits[0]); bool devSettings = instance().settings().getBool("dev.settings"); myConsole->setText(instance().settings().getString(devSettings ? "dev.console" : "plr.console") == "7800" ? "Atari 7800" : "Atari 2600"); myConsole->setEditable(false, true); myTVType->setSelectedIndex(riot.tvType(), state.swchbReadBits[4] != oldstate.swchbReadBits[4]); myPause->setState(!riot.tvType(), state.swchbReadBits[4] != oldstate.swchbReadBits[4]); mySelect->setState(!riot.select(), state.swchbReadBits[6] != oldstate.swchbReadBits[6]); myReset->setState(!riot.reset(), state.swchbReadBits[7] != oldstate.swchbReadBits[7]); myLeftControl->loadConfig(); myRightControl->loadConfig(); handleConsole(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RiotWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { int value = -1; RiotDebug& riot = instance().debugger().riotDebug(); switch(cmd) { case DataGridWidget::kItemDataChangedCmd: switch(id) { case kTimWriteID: switch(myTimWrite->getSelectedAddr()) { case kTim1TID: riot.tim1T(myTimWrite->getSelectedValue()); break; case kTim8TID: riot.tim8T(myTimWrite->getSelectedValue()); break; case kTim64TID: riot.tim64T(myTimWrite->getSelectedValue()); break; case kTim1024TID: riot.tim1024T(myTimWrite->getSelectedValue()); break; } break; } break; case ToggleWidget::kItemDataChangedCmd: switch(id) { case kSWCHABitsID: value = Debugger::get_bits(mySWCHAWriteBits->getState()); riot.swcha(value & 0xff); break; case kSWACNTBitsID: value = Debugger::get_bits(mySWACNTBits->getState()); riot.swacnt(value & 0xff); break; case kSWCHBBitsID: value = Debugger::get_bits(mySWCHBWriteBits->getState()); riot.swchb(value & 0xff); break; case kSWBCNTBitsID: value = Debugger::get_bits(mySWBCNTBits->getState()); riot.swbcnt(value & 0xff); break; case kSWCHARBitsID: { // TODO: Check if there is a nicer way to do this value = Debugger::get_bits(mySWCHAReadBits->getState()); riot.controller(Controller::Left).set(Controller::One, value & 0b00010000); riot.controller(Controller::Left).set(Controller::Two, value & 0b00100000); riot.controller(Controller::Left).set(Controller::Three, value & 0b01000000); riot.controller(Controller::Left).set(Controller::Four, value & 0b10000000); riot.controller(Controller::Right).set(Controller::One, value & 0b00000001); riot.controller(Controller::Right).set(Controller::Two, value & 0b00000010); riot.controller(Controller::Right).set(Controller::Three, value & 0b00000100); riot.controller(Controller::Right).set(Controller::Four, value & 0b00001000); break; } } break; case CheckboxWidget::kCheckActionCmd: switch(id) { case kSelectID: riot.select(!mySelect->getState()); break; case kResetID: riot.reset(!myReset->getState()); break; case kPauseID: handleConsole(); break; } break; case kP0DiffChanged: riot.diffP0(myP0Diff->getSelectedTag().toString() != "b"); break; case kP1DiffChanged: riot.diffP1(myP1Diff->getSelectedTag().toString() != "b"); break; case kTVTypeChanged: handleConsole(); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ControllerWidget* RiotWidget::addControlWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) { switch(controller.type()) { case Controller::AmigaMouse: return new AmigaMouseWidget(boss, font, x, y, controller); case Controller::AtariMouse: return new AtariMouseWidget(boss, font, x, y, controller); case Controller::AtariVox: return new AtariVoxWidget(boss, font, x, y, controller); case Controller::BoosterGrip: return new BoosterWidget(boss, font, x, y, controller); case Controller::Driving: return new DrivingWidget(boss, font, x, y, controller); case Controller::Genesis: return new GenesisWidget(boss, font, x, y, controller); case Controller::Joystick: return new JoystickWidget(boss, font, x, y, controller); case Controller::Keyboard: return new KeyboardWidget(boss, font, x, y, controller); // case Controller::KidVid: // TODO - implement this // case Controller::MindLink: // TODO - implement this case Controller::Paddles: return new PaddleWidget(boss, font, x, y, controller); case Controller::SaveKey: return new SaveKeyWidget(boss, font, x, y, controller); case Controller::TrakBall: return new TrakBallWidget(boss, font, x, y, controller); default: return new NullControlWidget(boss, font, x, y, controller); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RiotWidget::handleConsole() { RiotDebug& riot = instance().debugger().riotDebug(); bool devSettings = instance().settings().getBool("dev.settings"); bool is7800 = instance().settings().getString(devSettings ? "dev.console" : "plr.console") == "7800"; myTVType->setEnabled(!is7800); myPause->setEnabled(is7800); if(is7800) myTVType->setSelectedIndex(myPause->getState() ? 0 : 1); else myPause->setState(myTVType->getSelected() == 0); riot.tvType(myTVType->getSelected()); } stella-5.1.1/src/debugger/gui/RiotWidget.hxx000066400000000000000000000053471324334165500207720ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef RIOT_WIDGET_HXX #define RIOT_WIDGET_HXX class GuiObject; class ButtonWidget; class DataGridWidget; class PopUpWidget; class ToggleBitWidget; class ControllerWidget; class Controller; #include "Widget.hxx" #include "Command.hxx" class RiotWidget : public Widget, public CommandSender { public: RiotWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h); virtual ~RiotWidget() = default; private: ControllerWidget* addControlWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); void handleConsole(); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void loadConfig() override; private: ToggleBitWidget* mySWCHAReadBits; ToggleBitWidget* mySWCHAWriteBits; ToggleBitWidget* mySWACNTBits; ToggleBitWidget* mySWCHBReadBits; ToggleBitWidget* mySWCHBWriteBits; ToggleBitWidget* mySWBCNTBits; DataGridWidget* myLeftINPT; DataGridWidget* myRightINPT; CheckboxWidget* myINPTLatch; CheckboxWidget* myINPTDump; DataGridWidget* myTimWrite; DataGridWidget* myTimRead; ControllerWidget *myLeftControl, *myRightControl; PopUpWidget *myP0Diff, *myP1Diff; PopUpWidget *myTVType; CheckboxWidget* mySelect; CheckboxWidget* myReset; CheckboxWidget* myPause; EditTextWidget* myConsole; // ID's for the various widgets // We need ID's, since there are more than one of several types of widgets enum { kTim1TID, kTim8TID, kTim64TID, kTim1024TID, kTimWriteID, kSWCHABitsID, kSWACNTBitsID, kSWCHBBitsID, kSWBCNTBitsID, kP0DiffChanged, kP1DiffChanged, kTVTypeChanged, kSelectID, kResetID, kSWCHARBitsID, kPauseID }; private: // Following constructors and assignment operators not supported RiotWidget() = delete; RiotWidget(const RiotWidget&) = delete; RiotWidget(RiotWidget&&) = delete; RiotWidget& operator=(const RiotWidget&) = delete; RiotWidget& operator=(RiotWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/RomListSettings.cxx000066400000000000000000000134411324334165500220100ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Settings.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "RomListWidget.hxx" #include "RomListSettings.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomListSettings::RomListSettings(GuiObject* boss, const GUI::Font& font) : Dialog(boss->instance(), boss->parent()), CommandSender(boss), _xorig(0), _yorig(0), _item(0) { const int buttonWidth = font.getStringWidth("RunTo PC @ current line") + 20, buttonHeight = font.getLineHeight() + 4; int xpos = 8, ypos = 8; WidgetArray wid; // Set PC to current line ButtonWidget* setPC = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Set PC @ current line", RomListWidget::kSetPCCmd); wid.push_back(setPC); // RunTo PC on current line ypos += buttonHeight + 4; ButtonWidget* runtoPC = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "RunTo PC @ current line", RomListWidget::kRuntoPCCmd); wid.push_back(runtoPC); // Re-disassemble ypos += buttonHeight + 4; ButtonWidget* disasm = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Re-disassemble", RomListWidget::kDisassembleCmd); wid.push_back(disasm); // Settings for Distella xpos += 4; ypos += buttonHeight + 8; myShowTentative = new CheckboxWidget(this, font, xpos, ypos, "Show tentative code", RomListWidget::kTentativeCodeCmd); wid.push_back(myShowTentative); ypos += buttonHeight + 4; myShowAddresses = new CheckboxWidget(this, font, xpos, ypos, "Show PC addresses", RomListWidget::kPCAddressesCmd); wid.push_back(myShowAddresses); ypos += buttonHeight + 4; myShowGFXBinary = new CheckboxWidget(this, font, xpos, ypos, "Show GFX as binary", RomListWidget::kGfxAsBinaryCmd); wid.push_back(myShowGFXBinary); ypos += buttonHeight + 4; myUseRelocation = new CheckboxWidget(this, font, xpos, ypos, "Use address relocation", RomListWidget::kAddrRelocationCmd); wid.push_back(myUseRelocation); // Set real dimensions _w = buttonWidth + 20; _h = ypos + buttonHeight + 8; addToFocusList(wid); // We don't have a close/cancel button, but we still want the cancel // event to be processed processCancelWithoutWidget(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListSettings::show(uInt32 x, uInt32 y, int data) { _xorig = x; _yorig = y; _item = data; open(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListSettings::center() { // Make sure the menu is exactly where it should be, in case the image // offset has changed const GUI::Rect& image = instance().frameBuffer().imageRect(); uInt32 x = image.x() + _xorig; uInt32 y = image.y() + _yorig; uInt32 tx = image.x() + image.width(); uInt32 ty = image.y() + image.height(); if(x + _w > tx) x -= (x + _w - tx); if(y + _h > ty) y -= (y + _h - ty); surface().setDstPos(x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListSettings::loadConfig() { myShowTentative->setState(instance().settings().getBool("dis.resolve")); myShowAddresses->setState(instance().settings().getBool("dis.showaddr")); myShowGFXBinary->setState(instance().settings().getString("dis.gfxformat") == "2"); myUseRelocation->setState(instance().settings().getBool("dis.relocate")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListSettings::handleMouseDown(int x, int y, MouseButton b, int clickCount) { // Close dialog if mouse click is outside it (simulates a context menu) // Otherwise let the base dialog class process it if(x >= 0 && x < _w && y >= 0 && y < _h) Dialog::handleMouseDown(x, y, b, clickCount); else close(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListSettings::handleCommand(CommandSender* sender, int cmd, int data, int id) { // We remove the dialog when the user has selected an item // Make sure the dialog is removed before sending any commands, // since one consequence of sending a command may be to add another // dialog/menu close(); switch(cmd) { case RomListWidget::kSetPCCmd: case RomListWidget::kRuntoPCCmd: { sendCommand(cmd, _item, -1); break; } case RomListWidget::kDisassembleCmd: { sendCommand(cmd, -1, -1); break; } case RomListWidget::kTentativeCodeCmd: { sendCommand(cmd, myShowTentative->getState(), -1); break; } case RomListWidget::kPCAddressesCmd: { sendCommand(cmd, myShowAddresses->getState(), -1); break; } case RomListWidget::kGfxAsBinaryCmd: { sendCommand(cmd, myShowGFXBinary->getState(), -1); break; } case RomListWidget::kAddrRelocationCmd: { sendCommand(cmd, myUseRelocation->getState(), -1); break; } } } stella-5.1.1/src/debugger/gui/RomListSettings.hxx000066400000000000000000000043451324334165500220200ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ROM_LIST_SETTINGS_HXX #define ROM_LIST_SETTINGS_HXX class CheckboxWidget; class EditTextWidget; #include "Command.hxx" #include "Dialog.hxx" /** * A dialog which controls the settings for the RomListWidget. * Currently, all Distella disassembler options are located here as well. */ class RomListSettings : public Dialog, public CommandSender { public: RomListSettings(GuiObject* boss, const GUI::Font& font); virtual ~RomListSettings() = default; /** Show dialog onscreen at the specified coordinates ('data' will be the currently selected line number in RomListWidget) */ void show(uInt32 x, uInt32 y, int data = -1); /** This dialog uses its own positioning, so we override Dialog::center() */ void center() override; private: uInt32 _xorig, _yorig; int _item; // currently selected line number in the disassembly list CheckboxWidget* myShowTentative; CheckboxWidget* myShowAddresses; CheckboxWidget* myShowGFXBinary; CheckboxWidget* myUseRelocation; private: void loadConfig() override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Following constructors and assignment operators not supported RomListSettings() = delete; RomListSettings(const RomListSettings&) = delete; RomListSettings(RomListSettings&&) = delete; RomListSettings& operator=(const RomListSettings&) = delete; RomListSettings& operator=(RomListSettings&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/RomListWidget.cxx000066400000000000000000000421561324334165500214400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Debugger.hxx" #include "DiStella.hxx" #include "PackedBitArray.hxx" #include "Widget.hxx" #include "StellaKeys.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "ScrollBarWidget.hxx" #include "RomListSettings.hxx" #include "RomListWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomListWidget::RomListWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) : EditableWidget(boss, nfont, x, y, 16, 16), _rows(0), _cols(0), _currentPos(0), _selectedItem(-1), _highlightedItem(-1), _editMode(false), _currentKeyDown(KBDK_UNKNOWN), _base(Common::Base::F_DEFAULT), myDisasm(nullptr), myBPState(nullptr) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS; _bgcolor = kWidColor; _bgcolorhi = kWidColor; _textcolor = kTextColor; _textcolorhi = kTextColor; _cols = w / _fontWidth; _rows = h / _fontHeight; // Set real dimensions _w = w - kScrollBarWidth; _h = h + 2; // Create scrollbar and attach to the list myScrollBar = new ScrollBarWidget(boss, lfont, _x + _w, _y, kScrollBarWidth, _h); myScrollBar->setTarget(this); // Add settings menu myMenu = make_unique(this, lfont); // Take advantage of a wide debugger window when possible const int fontWidth = lfont.getMaxCharWidth(), numchars = w / fontWidth; _labelWidth = std::max(14, int(0.45 * (numchars - 8 - 8 - 9 - 2))) * fontWidth - 1; _bytesWidth = 9 * fontWidth; /////////////////////////////////////////////////////// // Add checkboxes int ypos = _y + 2; // rowheight is determined by largest item on a line, // possibly meaning that number of rows will change _fontHeight = std::max(_fontHeight, CheckboxWidget::boxSize()); _rows = h / _fontHeight; // Create a CheckboxWidget for each row in the list CheckboxWidget* t = nullptr; for(int i = 0; i < _rows; ++i) { t = new CheckboxWidget(boss, lfont, _x + 2, ypos, "", CheckboxWidget::kCheckActionCmd); t->setTarget(this); t->setID(i); t->setFill(CheckboxWidget::Circle); t->setTextColor(kTextColorEm); ypos += _fontHeight; myCheckList.push_back(t); } // Add filtering EditableWidget::TextFilter f = [&](char c) { switch(_base) { case Common::Base::F_16: case Common::Base::F_16_1: case Common::Base::F_16_2: case Common::Base::F_16_4: case Common::Base::F_16_8: return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || c == ' '; case Common::Base::F_2: case Common::Base::F_2_8: case Common::Base::F_2_16: return c == '0' || c == '1' || c == ' '; case Common::Base::F_10: return (c >= '0' && c <= '9') || c == ' '; case Common::Base::F_DEFAULT: default: // TODO - properly handle all other cases return false; } }; setTextFilter(f); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::setList(const CartDebug::Disassembly& disasm, const PackedBitArray& state) { myDisasm = &disasm; myBPState = &state; // Enable all checkboxes for(int i = 0; i < _rows; ++i) myCheckList[i]->setFlags(WIDGET_ENABLED); // Then turn off any extras if(int(myDisasm->list.size()) < _rows) for(int i = int(myDisasm->list.size()); i < _rows; ++i) myCheckList[i]->clearFlags(WIDGET_ENABLED); recalc(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::setSelected(int item) { if(item < -1 || item >= int(myDisasm->list.size())) return; if(isEnabled()) { if(_editMode) abortEditMode(); _currentPos = _selectedItem = item; scrollToSelected(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::setHighlighted(int item) { if(item < -1 || item >= int(myDisasm->list.size())) return; if(isEnabled()) { if(_editMode) abortEditMode(); _highlightedItem = item; // Only scroll the list if we're about to pass the page boundary if(_currentPos == 0) _currentPos = _highlightedItem; else if(_highlightedItem == _currentPos + _rows) _currentPos += _rows; scrollToHighlighted(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int RomListWidget::findItem(int x, int y) const { return (y - 1) / _fontHeight + _currentPos; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::recalc() { int size = int(myDisasm->list.size()); if (_currentPos >= size) _currentPos = size - 1; if (_currentPos < 0) _currentPos = 0; if(_selectedItem < 0 || _selectedItem >= size) _selectedItem = 0; _editMode = false; myScrollBar->_numEntries = int(myDisasm->list.size()); myScrollBar->_entriesPerPage = _rows; // Reset to normal data entry abortEditMode(); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::scrollToCurrent(int item) { // Only do something if the current item is not in our view port if (item < _currentPos) { // it's above our view _currentPos = item; } else if (item >= _currentPos + _rows ) { // it's below our view _currentPos = item - _rows + 1; } int size = int(myDisasm->list.size()); if (_currentPos < 0 || _rows > size) _currentPos = 0; else if (_currentPos + _rows > size) _currentPos = size - _rows; myScrollBar->_currentPos = _currentPos; myScrollBar->recalc(); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { if (!isEnabled()) return; // Grab right mouse button for context menu, left for selection/edit mode if(b == MouseButton::RIGHT) { // Set selected and add menu at current x,y mouse location _selectedItem = findItem(x, y); scrollToSelected(); myMenu->show(x + getAbsX(), y + getAbsY(), _selectedItem); } else { // First check whether the selection changed int newSelectedItem; newSelectedItem = findItem(x, y); if (newSelectedItem > int(myDisasm->list.size()) - 1) newSelectedItem = -1; if (_selectedItem != newSelectedItem) { if (_editMode) abortEditMode(); _selectedItem = newSelectedItem; setDirty(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { // If this was a double click and the mouse is still over the selected item, // send the double click command if (clickCount == 2 && (_selectedItem == findItem(x, y))) { // Start edit mode if(isEditable() && !_editMode) startEditMode(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::handleMouseWheel(int x, int y, int direction) { myScrollBar->handleMouseWheel(x, y, direction); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RomListWidget::handleText(char text) { if(_editMode) { // Class EditableWidget handles all text editing related key presses for us return EditableWidget::handleText(text); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RomListWidget::handleKeyDown(StellaKey key, StellaMod mod) { // Ignore all Alt-mod keys if(StellaModTest::isAlt(mod)) return true; bool handled = true; int oldSelectedItem = _selectedItem; if (_editMode) { // Class EditableWidget handles all single-key presses for us handled = EditableWidget::handleKeyDown(key, mod); } else { switch (key) { case KBDK_SPACE: // Snap list back to currently highlighted line if(_highlightedItem >= 0) { _currentPos = _highlightedItem; scrollToHighlighted(); } break; default: handled = false; } } if (_selectedItem != oldSelectedItem) { myScrollBar->draw(); scrollToSelected(); } _currentKeyDown = key; return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RomListWidget::handleKeyUp(StellaKey key, StellaMod mod) { if (key == _currentKeyDown) _currentKeyDown = KBDK_UNKNOWN; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool RomListWidget::handleEvent(Event::Type e) { if(!isEnabled() || _editMode) return false; bool handled = true; int oldSelectedItem = _selectedItem; switch(e) { case Event::UISelect: if (_selectedItem >= 0) { if (isEditable()) startEditMode(); } break; case Event::UIUp: if (_selectedItem > 0) _selectedItem--; break; case Event::UIDown: if (_selectedItem < int(myDisasm->list.size()) - 1) _selectedItem++; break; case Event::UIPgUp: _selectedItem -= _rows - 1; if (_selectedItem < 0) _selectedItem = 0; break; case Event::UIPgDown: _selectedItem += _rows - 1; if (_selectedItem >= int(myDisasm->list.size())) _selectedItem = int(myDisasm->list.size()) - 1; break; case Event::UIHome: _selectedItem = 0; break; case Event::UIEnd: _selectedItem = int(myDisasm->list.size()) - 1; break; default: handled = false; } if (_selectedItem != oldSelectedItem) { myScrollBar->draw(); scrollToSelected(); } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case CheckboxWidget::kCheckActionCmd: // We let the parent class handle this // Pass it as a kRLBreakpointChangedCmd command, since that's the intent sendCommand(RomListWidget::kBPointChangedCmd, _currentPos+id, myCheckList[id]->getState()); break; case GuiObject::kSetPositionCmd: if (_currentPos != data) { _currentPos = data; setDirty(); } break; default: // Let the parent class handle all other commands directly sendCommand(cmd, data, id); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::lostFocusWidget() { _editMode = false; // Reset to normal data entry abortEditMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); const CartDebug::DisassemblyList& dlist = myDisasm->list; int i, pos, xpos, ypos, len = int(dlist.size()); const GUI::Rect& r = getEditRect(); const GUI::Rect& l = getLineRect(); // Draw a thin frame around the list and to separate columns s.hLine(_x, _y, _x + _w - 1, kColor); s.hLine(_x, _y + _h - 1, _x + _w - 1, kShadowColor); s.vLine(_x, _y, _y + _h - 1, kColor); s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor); // Draw the list items int cycleCountW = _fontWidth * 8, noTypeDisasmW = _w - l.x() - _labelWidth, noCodeDisasmW = noTypeDisasmW - r.width(), codeDisasmW = noCodeDisasmW - cycleCountW, actualWidth = myDisasm->fieldwidth * _fontWidth; if(actualWidth < codeDisasmW) codeDisasmW = actualWidth; xpos = _x + CheckboxWidget::boxSize() + 10; ypos = _y + 2; for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++, ypos += _fontHeight) { uInt32 bytesColor = kTextColor; // Draw checkboxes for correct lines (takes scrolling into account) myCheckList[i]->setState(myBPState->isSet(dlist[pos].address)); myCheckList[i]->setDirty(); myCheckList[i]->draw(); // Draw highlighted item in a frame if (_highlightedItem == pos) s.frameRect(_x + l.x() - 3, ypos - 1, _w - l.x(), _fontHeight, kTextColorHi); // Draw the selected item inverted, on a highlighted background. if(_selectedItem == pos && _hasFocus) { if(!_editMode) { s.fillRect(_x + r.x() - 3, ypos - 1, r.width(), _fontHeight, kTextColorHi); bytesColor = kTextColorInv; } else s.frameRect(_x + r.x() - 3, ypos - 1, r.width(), _fontHeight, kTextColorHi); } // Draw labels s.drawString(_font, dlist[pos].label, xpos, ypos, _labelWidth, dlist[pos].hllabel ? kTextColor : kColor); // Bytes are only editable if they represent code, graphics, or accessible data // Otherwise, the disassembly should get all remaining space if(dlist[pos].type & (CartDebug::CODE|CartDebug::GFX|CartDebug::PGFX|CartDebug::DATA)) { if(dlist[pos].type == CartDebug::CODE) { // Draw mnemonic s.drawString(_font, dlist[pos].disasm.substr(0, 7), xpos + _labelWidth, ypos, 7 * _fontWidth, kTextColor); // Draw operand if (dlist[pos].disasm.length() > 8) s.drawString(_font, dlist[pos].disasm.substr(8), xpos + _labelWidth + 7 * _fontWidth, ypos, codeDisasmW - 7 * _fontWidth, kTextColor); // Draw cycle count s.drawString(_font, dlist[pos].ccount, xpos + _labelWidth + codeDisasmW, ypos, cycleCountW, kTextColor); } else { // Draw disassembly only s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos, noCodeDisasmW - 4, kTextColor); } // Draw separator s.vLine(_x + r.x() - 7, ypos, ypos + _fontHeight - 1, kColor); // Draw bytes { if (_selectedItem == pos && _editMode) { adjustOffset(); s.drawString(_font, editString(), _x + r.x(), ypos, r.width(), kTextColor, TextAlign::Left, -_editScrollOffset, false); drawCaret(); } else { s.drawString(_font, dlist[pos].bytes, _x + r.x(), ypos, r.width(), bytesColor); } } } else { // Draw disassembly, giving it all remaining horizontal space s.drawString(_font, dlist[pos].disasm, xpos + _labelWidth, ypos, noTypeDisasmW, kTextColor); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect RomListWidget::getLineRect() const { GUI::Rect r(2, 1, _w, _fontHeight); const int yoffset = (_selectedItem - _currentPos) * _fontHeight, xoffset = CheckboxWidget::boxSize() + 10; r.top += yoffset; r.bottom += yoffset; r.left += xoffset; r.right -= xoffset - 15; return r; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect RomListWidget::getEditRect() const { GUI::Rect r(2, 1, _w, _fontHeight); const int yoffset = (_selectedItem - _currentPos) * _fontHeight; r.top += yoffset; r.bottom += yoffset; r.left += _w - _bytesWidth; r.right = _w; return r; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::startEditMode() { if (isEditable() && !_editMode && _selectedItem >= 0) { // Does this line represent an editable area? if(myDisasm->list[_selectedItem].bytes == "") return; _editMode = true; switch(myDisasm->list[_selectedItem].type) { case CartDebug::GFX: case CartDebug::PGFX: _base = DiStella::settings.gfxFormat; break; default: _base = Common::Base::format(); } // Widget gets raw data while editing EditableWidget::startEditMode(); setText(myDisasm->list[_selectedItem].bytes); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::endEditMode() { if (!_editMode) return; // Send a message that editing finished with a return/enter key press // The parent then calls getText() to get the newly entered data _editMode = false; sendCommand(RomListWidget::kRomChangedCmd, _selectedItem, _base); // Reset to normal data entry EditableWidget::endEditMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomListWidget::abortEditMode() { // Undo any changes made _editMode = false; // Reset to normal data entry EditableWidget::abortEditMode(); } stella-5.1.1/src/debugger/gui/RomListWidget.hxx000066400000000000000000000077521324334165500214500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ROM_LIST_WIDGET_HXX #define ROM_LIST_WIDGET_HXX class ScrollBarWidget; class PackedBitArray; class CheckListWidget; class RomListSettings; #include "Base.hxx" #include "CartDebug.hxx" #include "EditableWidget.hxx" /** RomListWidget */ class RomListWidget : public EditableWidget { public: enum { kBPointChangedCmd = 'RLbp', // 'data' will be disassembly line number, // 'id' will be the checkbox state kRomChangedCmd = 'RLpr', // 'data' will be disassembly line number // 'id' will be the Base::Format of the data kSetPCCmd = 'STpc', // 'data' will be disassembly line number kRuntoPCCmd = 'RTpc', // 'data' will be disassembly line number kDisassembleCmd = 'REds', kTentativeCodeCmd = 'TEcd', // 'data' will be boolean kPCAddressesCmd = 'PCad', // 'data' will be boolean kGfxAsBinaryCmd = 'GFXb', // 'data' will be boolean kAddrRelocationCmd = 'ADre' // 'data' will be boolean }; public: RomListWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h); virtual ~RomListWidget() = default; void setList(const CartDebug::Disassembly& disasm, const PackedBitArray& state); int getSelected() const { return _selectedItem; } int getHighlighted() const { return _highlightedItem; } void setSelected(int item); void setHighlighted(int item); protected: void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; bool handleText(char text) override; bool handleKeyDown(StellaKey key, StellaMod mod) override; bool handleKeyUp(StellaKey key, StellaMod mod) override; bool handleEvent(Event::Type e) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void drawWidget(bool hilite) override; GUI::Rect getLineRect() const; GUI::Rect getEditRect() const override; int findItem(int x, int y) const; void recalc(); void startEditMode() override; void endEditMode() override; void abortEditMode() override; void lostFocusWidget() override; void scrollToSelected() { scrollToCurrent(_selectedItem); } void scrollToHighlighted() { scrollToCurrent(_highlightedItem); } private: void scrollToCurrent(int item); private: unique_ptr myMenu; ScrollBarWidget* myScrollBar; int _labelWidth; int _bytesWidth; int _rows; int _cols; int _currentPos; int _selectedItem; int _highlightedItem; bool _editMode; StellaKey _currentKeyDown; Common::Base::Format _base; // base used during editing const CartDebug::Disassembly* myDisasm; const PackedBitArray* myBPState; vector myCheckList; private: // Following constructors and assignment operators not supported RomListWidget() = delete; RomListWidget(const RomListWidget&) = delete; RomListWidget(RomListWidget&&) = delete; RomListWidget& operator=(const RomListWidget&) = delete; RomListWidget& operator=(RomListWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/RomWidget.cxx000066400000000000000000000165771324334165500206140ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Settings.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "DiStella.hxx" #include "CpuDebug.hxx" #include "GuiObject.hxx" #include "Font.hxx" #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "ContextMenu.hxx" #include "RomListWidget.hxx" #include "RomWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomWidget::RomWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) : Widget(boss, lfont, x, y, w, h), CommandSender(boss), myListIsDirty(true) { int xpos, ypos; StaticTextWidget* t; WidgetArray wid; // Show current bank state xpos = x; ypos = y + 7; t = new StaticTextWidget(boss, lfont, xpos, ypos, lfont.getStringWidth("Bank"), lfont.getFontHeight(), "Bank", TextAlign::Left); xpos += t->getWidth() + 5; myBank = new EditTextWidget(boss, nfont, xpos, ypos-2, _w - 2 - xpos, nfont.getLineHeight()); myBank->setEditable(false); // Create rom listing xpos = x; ypos += myBank->getHeight() + 4; myRomList = new RomListWidget(boss, lfont, nfont, xpos, ypos, _w - 4, _h - ypos - 2); myRomList->setTarget(this); addFocusWidget(myRomList); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::loadConfig() { Debugger& dbg = instance().debugger(); CartDebug& cart = dbg.cartDebug(); const CartState& state = static_cast(cart.getState()); const CartState& oldstate = static_cast(cart.getOldState()); // Fill romlist the current bank of source or disassembly myListIsDirty |= cart.disassemble(myListIsDirty); if(myListIsDirty) { myRomList->setList(cart.disassembly(), dbg.breakPoints()); myListIsDirty = false; } // Update romlist to point to current PC (if it has changed) int pcline = cart.addressToLine(dbg.cpuDebug().pc()); if(pcline >= 0 && pcline != myRomList->getHighlighted()) myRomList->setHighlighted(pcline); // Set current bank state myBank->setText(state.bank, state.bank != oldstate.bank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case RomListWidget::kBPointChangedCmd: // 'data' is the line in the disassemblylist to be accessed // 'id' is the state of the breakpoint at 'data' setBreak(data, id); // Refresh the romlist, since the breakpoint may not have // actually changed myRomList->setDirty(); myRomList->draw(); break; case RomListWidget::kRomChangedCmd: // 'data' is the line in the disassemblylist to be accessed // 'id' is the base to use for the data to be changed patchROM(data, myRomList->getText(), Common::Base::Format(id)); break; case RomListWidget::kSetPCCmd: // 'data' is the line in the disassemblylist to be accessed setPC(data); break; case RomListWidget::kRuntoPCCmd: // 'data' is the line in the disassemblylist to be accessed runtoPC(data); break; case RomListWidget::kDisassembleCmd: invalidate(); break; case RomListWidget::kTentativeCodeCmd: { // 'data' is the boolean value DiStella::settings.resolveCode = data; instance().settings().setValue("dis.resolve", DiStella::settings.resolveCode); invalidate(); break; } case RomListWidget::kPCAddressesCmd: // 'data' is the boolean value DiStella::settings.showAddresses = data; instance().settings().setValue("dis.showaddr", DiStella::settings.showAddresses); invalidate(); break; case RomListWidget::kGfxAsBinaryCmd: // 'data' is the boolean value if(data) { DiStella::settings.gfxFormat = Common::Base::F_2; instance().settings().setValue("dis.gfxformat", "2"); } else { DiStella::settings.gfxFormat = Common::Base::F_16; instance().settings().setValue("dis.gfxformat", "16"); } invalidate(); break; case RomListWidget::kAddrRelocationCmd: // 'data' is the boolean value DiStella::settings.rFlag = data; instance().settings().setValue("dis.relocate", DiStella::settings.rFlag); invalidate(); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::setBreak(int disasm_line, bool state) { const CartDebug::DisassemblyList& list = instance().debugger().cartDebug().disassembly().list; if(disasm_line >= int(list.size())) return; if(list[disasm_line].address != 0 && list[disasm_line].bytes != "") instance().debugger().setBreakPoint(list[disasm_line].address, state); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::setPC(int disasm_line) { const CartDebug::DisassemblyList& list = instance().debugger().cartDebug().disassembly().list; if(disasm_line >= int(list.size())) return; if(list[disasm_line].address != 0) { ostringstream command; command << "pc #" << list[disasm_line].address; instance().debugger().run(command.str()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::runtoPC(int disasm_line) { const CartDebug::DisassemblyList& list = instance().debugger().cartDebug().disassembly().list; if(disasm_line >= int(list.size())) return; if(list[disasm_line].address != 0) { ostringstream command; command << "runtopc #" << list[disasm_line].address; instance().debugger().run(command.str()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::patchROM(int disasm_line, const string& bytes, Common::Base::Format base) { const CartDebug::DisassemblyList& list = instance().debugger().cartDebug().disassembly().list; if(disasm_line >= int(list.size())) return; if(list[disasm_line].address != 0) { ostringstream command; // Temporarily set to correct base, so we don't have to prefix each byte // with the type of data Common::Base::Format oldbase = Common::Base::format(); Common::Base::setFormat(base); command << "rom #" << list[disasm_line].address << " " << bytes; instance().debugger().run(command.str()); // Restore previous base Common::Base::setFormat(oldbase); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomWidget::scrollTo(int line) { myRomList->setSelected(line); } stella-5.1.1/src/debugger/gui/RomWidget.hxx000066400000000000000000000040511324334165500206010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ROM_WIDGET_HXX #define ROM_WIDGET_HXX class GuiObject; class EditTextWidget; class RomListWidget; #include "Base.hxx" #include "Command.hxx" #include "Widget.hxx" class RomWidget : public Widget, public CommandSender { public: // This enum needs to be seen outside the class enum { kInvalidateListing = 'INli' }; public: RomWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h); virtual ~RomWidget() = default; void invalidate(bool forcereload = true) { myListIsDirty = true; if(forcereload) loadConfig(); } void scrollTo(int line); private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void loadConfig() override; void setBreak(int disasm_line, bool state); void setPC(int disasm_line); void runtoPC(int disasm_line); void patchROM(int disasm_line, const string& bytes, Common::Base::Format base); private: RomListWidget* myRomList; EditTextWidget* myBank; bool myListIsDirty; private: // Following constructors and assignment operators not supported RomWidget() = delete; RomWidget(const RomWidget&) = delete; RomWidget(RomWidget&&) = delete; RomWidget& operator=(const RomWidget&) = delete; RomWidget& operator=(RomWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/SaveKeyWidget.cxx000066400000000000000000000026571324334165500214200ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "SaveKey.hxx" #include "SaveKeyWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SaveKeyWidget::SaveKeyWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : FlashWidget(boss, font, x, y, controller) { init(boss, font, x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SaveKeyWidget::eraseCurrent() { SaveKey& skey = static_cast(myController); skey.eraseCurrent(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SaveKeyWidget::isPageUsed(uInt32 page) { SaveKey& skey = static_cast(myController); return skey.isPageUsed(page); } stella-5.1.1/src/debugger/gui/SaveKeyWidget.hxx000066400000000000000000000026131324334165500214150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SAVEKEY_WIDGET_HXX #define SAVEKEY_WIDGET_HXX class Controller; #include "FlashWidget.hxx" class SaveKeyWidget : public FlashWidget { public: SaveKeyWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~SaveKeyWidget() = default; private: void eraseCurrent() override; bool isPageUsed(uInt32 page) override; // Following constructors and assignment operators not supported SaveKeyWidget() = delete; SaveKeyWidget(const SaveKeyWidget&) = delete; SaveKeyWidget(SaveKeyWidget&&) = delete; SaveKeyWidget& operator=(const SaveKeyWidget&) = delete; SaveKeyWidget& operator=(SaveKeyWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/TiaInfoWidget.cxx000066400000000000000000000142151324334165500213730ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Base.hxx" #include "Font.hxx" #include "OSystem.hxx" #include "Debugger.hxx" #include "TIADebug.hxx" #include "Widget.hxx" #include "EditTextWidget.hxx" #include "GuiObject.hxx" #include "TiaInfoWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TiaInfoWidget::TiaInfoWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int max_w) : Widget(boss, lfont, x, y, 16, 16), CommandSender(boss) { bool longstr = 34 * lfont.getMaxCharWidth() <= max_w; x += 5; const int lineHeight = lfont.getLineHeight(); int xpos = x, ypos = y + 10; int lwidth = lfont.getStringWidth(longstr ? "Frame Cycle " : "F. Cycle "); int fwidth = 5 * lfont.getMaxCharWidth() + 4; // Add frame info new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, longstr ? "Frame Count " : "Frame ", TextAlign::Left); xpos += lwidth; myFrameCount = new EditTextWidget(boss, nfont, xpos, ypos-1, fwidth, lineHeight, ""); myFrameCount->setEditable(false, true); xpos = x; ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, longstr ? "Frame Cycle " : "F. Cycle ", TextAlign::Left); xpos += lwidth; myFrameCycles = new EditTextWidget(boss, nfont, xpos, ypos-1, fwidth, lineHeight, ""); myFrameCycles->setEditable(false, true); xpos = x + 20; ypos += lineHeight + 8; myVSync = new CheckboxWidget(boss, lfont, xpos, ypos-3, "VSync", 0); myVSync->setEditable(false); xpos = x + 20; ypos += lineHeight + 5; myVBlank = new CheckboxWidget(boss, lfont, xpos, ypos-3, "VBlank", 0); myVBlank->setEditable(false); xpos = x + lwidth + myFrameCycles->getWidth() + 8; ypos = y + 10; lwidth = lfont.getStringWidth(longstr ? "Color Clock " : "Pixel Pos "); fwidth = 3 * lfont.getMaxCharWidth() + 4; new StaticTextWidget(boss, lfont, xpos, ypos, lfont.getStringWidth(longstr ? "Scanline" : "Scn Ln"), lineHeight, longstr ? "Scanline" : "Scn Ln", TextAlign::Left); myScanlineCountLast = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myScanlineCountLast->setEditable(false, true); myScanlineCount = new EditTextWidget(boss, nfont, xpos+lwidth - myScanlineCountLast->getWidth() - 2, ypos-1, fwidth, lineHeight, ""); myScanlineCount->setEditable(false, true); ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, longstr ? "Scan Cycle " : "Scn Cycle", TextAlign::Left); myScanlineCycles = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myScanlineCycles->setEditable(false, true); ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, "Pixel Pos ", TextAlign::Left); myPixelPosition = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myPixelPosition->setEditable(false, true); ypos += lineHeight + 5; new StaticTextWidget(boss, lfont, xpos, ypos, lwidth, lineHeight, longstr ? "Color Clock " : "Color Clk ", TextAlign::Left); myColorClocks = new EditTextWidget(boss, nfont, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); myColorClocks->setEditable(false, true); // Calculate actual dimensions _w = myColorClocks->getAbsX() + myColorClocks->getWidth() - x; _h = ypos + lineHeight; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaInfoWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { //cerr << "TiaInfoWidget button press: x = " << x << ", y = " << y << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaInfoWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaInfoWidget::loadConfig() { Debugger& dbg = instance().debugger(); TIADebug& tia = dbg.tiaDebug(); const TiaState& oldTia = static_cast(tia.getOldState()); myFrameCount->setText(" " + Common::Base::toString(tia.frameCount(), Common::Base::F_10), tia.frameCount() != oldTia.info[0]); myFrameCycles->setText(" " + Common::Base::toString(tia.frameCycles(), Common::Base::F_10), tia.frameCycles() != oldTia.info[1]); myVSync->setState(tia.vsync(), tia.vsyncAsInt() != oldTia.info[2]); myVBlank->setState(tia.vblank(), tia.vblankAsInt() != oldTia.info[3]); int clk = tia.clocksThisLine(); myScanlineCount->setText(Common::Base::toString(tia.scanlines(), Common::Base::F_10), tia.scanlines() != oldTia.info[4]); myScanlineCountLast->setText( Common::Base::toString(tia.scanlinesLastFrame(), Common::Base::F_10), tia.scanlinesLastFrame() != oldTia.info[5]); myScanlineCycles->setText(Common::Base::toString(clk/3, Common::Base::F_10), clk != oldTia.info[6]); myPixelPosition->setText(Common::Base::toString(clk-68, Common::Base::F_10), clk != oldTia.info[6]); myColorClocks->setText(Common::Base::toString(clk, Common::Base::F_10), clk != oldTia.info[6]); } stella-5.1.1/src/debugger/gui/TiaInfoWidget.hxx000066400000000000000000000036511324334165500214020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_INFO_WIDGET_HXX #define TIA_INFO_WIDGET_HXX class GuiObject; class EditTextWidget; class CheckboxWidget; #include "Widget.hxx" #include "Command.hxx" class TiaInfoWidget : public Widget, public CommandSender { public: TiaInfoWidget(GuiObject *boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int max_w); virtual ~TiaInfoWidget() = default; void loadConfig() override; private: EditTextWidget* myFrameCount; EditTextWidget* myFrameCycles; EditTextWidget* myScanlineCount; EditTextWidget* myScanlineCountLast; EditTextWidget* myScanlineCycles; EditTextWidget* myPixelPosition; EditTextWidget* myColorClocks; CheckboxWidget* myVSync; CheckboxWidget* myVBlank; private: void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Following constructors and assignment operators not supported TiaInfoWidget() = delete; TiaInfoWidget(const TiaInfoWidget&) = delete; TiaInfoWidget(TiaInfoWidget&&) = delete; TiaInfoWidget& operator=(const TiaInfoWidget&) = delete; TiaInfoWidget& operator=(TiaInfoWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/TiaOutputWidget.cxx000066400000000000000000000133501324334165500217770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Widget.hxx" #include "GuiObject.hxx" #include "ContextMenu.hxx" #include "TiaZoomWidget.hxx" #include "Debugger.hxx" #include "DebuggerParser.hxx" #include "PNGLibrary.hxx" #include "TIADebug.hxx" #include "TIASurface.hxx" #include "TIA.hxx" #include "TiaOutputWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TiaOutputWidget::TiaOutputWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : Widget(boss, font, x, y, w, h), CommandSender(boss), myZoom(nullptr), myClickX(0), myClickY(0) { // Create context menu for commands VariantList l; VarList::push_back(l, "Fill to scanline", "scanline"); VarList::push_back(l, "Toggle breakpoint", "bp"); VarList::push_back(l, "Set zoom position", "zoom"); VarList::push_back(l, "Save snapshot", "snap"); myMenu = make_unique(this, font, l); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaOutputWidget::loadConfig() { setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaOutputWidget::saveSnapshot(int execDepth, const string& execPrefix) { if (execDepth > 0) { drawWidget(false); } ostringstream sspath; sspath << instance().snapshotSaveDir() << instance().console().properties().get(Cartridge_Name); sspath << "_dbg_"; if (execDepth > 0 && !execPrefix.empty()) { sspath << execPrefix << "_"; } sspath << std::hex << std::setw(8) << std::setfill('0') << uInt32(instance().getTicks()/1000) << ".png"; const uInt32 width = instance().console().tia().width(), height = instance().console().tia().height(); FBSurface& s = dialog().surface(); GUI::Rect rect(_x, _y, _x + width*2, _y + height); string message = "Snapshot saved"; try { instance().png().saveImage(sspath.str(), s, rect); } catch(const runtime_error& e) { message = e.what(); } if (execDepth == 0) { instance().frameBuffer().showMessage(message); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaOutputWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { // Grab right mouse button for command context menu if(b == MouseButton::RIGHT) { myClickX = x; myClickY = y; // Add menu at current x,y mouse location myMenu->show(x + getAbsX(), y + getAbsY()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaOutputWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { uInt32 ystart = instance().console().tia().ystart(); switch(cmd) { case ContextMenu::kItemSelectedCmd: { const string& rmb = myMenu->getSelectedTag().toString(); if(rmb == "scanline") { ostringstream command; int lines = myClickY + ystart; if(instance().console().tia().isRendering()) lines -= instance().console().tia().scanlines(); if(lines > 0) { command << "scanline #" << lines; string message = instance().debugger().parser().run(command.str()); instance().frameBuffer().showMessage(message); } } else if(rmb == "bp") { ostringstream command; int scanline = myClickY + ystart; command << "breakif _scan==#" << scanline; string message = instance().debugger().parser().run(command.str()); instance().frameBuffer().showMessage(message); } else if(rmb == "zoom") { if(myZoom) myZoom->setPos(myClickX, myClickY); } else if(rmb == "snap") { instance().debugger().parser().run("savesnap"); } break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaOutputWidget::drawWidget(bool hilite) { //cerr << "TiaOutputWidget::drawWidget\n"; const uInt32 width = instance().console().tia().width(), height = instance().console().tia().height(); FBSurface& s = dialog().surface(); s.vLine(_x + _w + 1, _y, height, kColor); s.hLine(_x, _y + height + 1, _x +_w + 1, kColor); // Get current scanline position // This determines where the frame greying should start, and where a // scanline 'pointer' should be drawn uInt32 scanx, scany, scanoffset; bool visible = instance().console().tia().electronBeamPos(scanx, scany); scanoffset = width * scany + scanx; for(uInt32 y = 0, i = 0; y < height; ++y) { uInt32* line_ptr = myLineBuffer; for(uInt32 x = 0; x < width; ++x, ++i) { uInt8 shift = i >= scanoffset ? 1 : 0; uInt32 pixel = instance().frameBuffer().tiaSurface().pixel(i, shift); *line_ptr++ = pixel; *line_ptr++ = pixel; } s.drawPixels(myLineBuffer, _x + 1, _y + 1 + y, width << 1); } // Show electron beam position if(visible && scanx < width && scany+2u < height) s.fillRect(_x + 1 + (scanx<<1), _y + 1 + scany, 3, 3, kColorInfo); } stella-5.1.1/src/debugger/gui/TiaOutputWidget.hxx000066400000000000000000000047641324334165500220150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_OUTPUT_WIDGET_HXX #define TIA_OUTPUT_WIDGET_HXX class GuiObject; class ContextMenu; class TiaZoomWidget; class FBSurface; #include "Widget.hxx" #include "Command.hxx" class TiaOutputWidget : public Widget, public CommandSender { public: TiaOutputWidget(GuiObject *boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~TiaOutputWidget() = default; void loadConfig() override; void setZoomWidget(TiaZoomWidget* w) { myZoom = w; } void saveSnapshot(int execDepth = 0, const string& execPrefix = ""); // Eventually, these methods will enable access to the onscreen TIA image // For example, clicking an area may cause an action // (fill to this scanline, etc). /* void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; bool handleKeyDown(StellaKey key, StellaMod mod) override; bool handleKeyUp(StellaKey key, StellaMod mod) override; */ private: unique_ptr myMenu; TiaZoomWidget* myZoom; int myClickX, myClickY; // Create this buffer once, instead of allocating it each time the // TIA image is redrawn uInt32 myLineBuffer[320]; private: void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void drawWidget(bool hilite) override; bool wantsFocus() const override { return false; } // Following constructors and assignment operators not supported TiaOutputWidget() = delete; TiaOutputWidget(const TiaOutputWidget&) = delete; TiaOutputWidget(TiaOutputWidget&&) = delete; TiaOutputWidget& operator=(const TiaOutputWidget&) = delete; TiaOutputWidget& operator=(TiaOutputWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/TiaWidget.cxx000066400000000000000000001106541324334165500205630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "ColorWidget.hxx" #include "DataGridWidget.hxx" #include "EditTextWidget.hxx" #include "FrameBuffer.hxx" #include "Font.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "Debugger.hxx" #include "CartDebug.hxx" #include "TIA.hxx" #include "TIADebug.hxx" #include "ToggleBitWidget.hxx" #include "TogglePixelWidget.hxx" #include "Widget.hxx" #include "DelayQueueWidget.hxx" #include "TiaWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TiaWidget::TiaWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) : Widget(boss, lfont, x, y, w, h), CommandSender(boss) { const int fontWidth = lfont.getMaxCharWidth(), fontHeight = lfont.getFontHeight(), lineHeight = lfont.getLineHeight(), buttonW = 7 * fontWidth; int xpos = 10, ypos = 10 + lineHeight, buttonX = 0, buttonY = 0; StaticTextWidget* t = nullptr; ButtonWidget* b = nullptr; // Color registers const char* const regNames[] = { "COLUP0", "COLUP1", "COLUPF", "COLUBK" }; for(int row = 0; row < 4; ++row) { new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2, 6*fontWidth, fontHeight, regNames[row], TextAlign::Left); } xpos += 6*fontWidth + 8; myColorRegs = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 2, 8, Common::Base::F_16); myColorRegs->setTarget(this); myColorRegs->setID(kColorRegsID); addFocusWidget(myColorRegs); xpos += myColorRegs->colWidth() + 5; myCOLUP0Color = new ColorWidget(boss, nfont, xpos, ypos+2, uInt32(1.5*lineHeight), lineHeight - 4); myCOLUP0Color->setTarget(this); ypos += lineHeight; myCOLUP1Color = new ColorWidget(boss, nfont, xpos, ypos+2, uInt32(1.5*lineHeight), lineHeight - 4); myCOLUP1Color->setTarget(this); ypos += lineHeight; myCOLUPFColor = new ColorWidget(boss, nfont, xpos, ypos+2, uInt32(1.5*lineHeight), lineHeight - 4); myCOLUPFColor->setTarget(this); ypos += lineHeight; myCOLUBKColor = new ColorWidget(boss, nfont, xpos, ypos+2, uInt32(1.5*lineHeight), lineHeight - 4); myCOLUBKColor->setTarget(this); // Fixed debug colors xpos += myCOLUP0Color->getWidth() + 30; ypos = 10; myFixedEnabled = new CheckboxWidget(boss, lfont, xpos, ypos, "Debug Colors", kDbgClCmd); myFixedEnabled->setTarget(this); addFocusWidget(myFixedEnabled); const char* const dbgLabels[] = { "P0", "P1", "PF", "BK", "M0", "M1", "BL", "HM" }; for(uInt32 row = 0; row <= 3; ++row) { ypos += lineHeight; t = new StaticTextWidget(boss, lfont, xpos, ypos + 2, 2*fontWidth, fontHeight, dbgLabels[row], TextAlign::Left); myFixedColors[row] = new ColorWidget(boss, nfont, xpos + 2 + t->getWidth() + 4, ypos + 2, uInt32(1.5*lineHeight), lineHeight - 4); myFixedColors[row]->setTarget(this); } xpos += t->getWidth() + myFixedColors[0]->getWidth() + 24; ypos = 10; for(uInt32 row = 4; row <= 7; ++row) { ypos += lineHeight; t = new StaticTextWidget(boss, lfont, xpos, ypos + 2, 2*fontWidth, fontHeight, dbgLabels[row], TextAlign::Left); myFixedColors[row] = new ColorWidget(boss, nfont, xpos + 2 + t->getWidth() + 4, ypos + 2, uInt32(1.5*lineHeight), lineHeight - 4); myFixedColors[row]->setTarget(this); } //////////////////////////// // Collision register bits //////////////////////////// xpos += myFixedColors[0]->getWidth() + 2*fontWidth + 60; ypos = 10; // Add all 15 collision bits (with labels) uInt32 cxclrY = 0; xpos -= 2*fontWidth + 5; ypos += lineHeight; const char* const rowLabel[] = { "P0", "P1", "M0", "M1", "BL" }; const char* const colLabel[] = { "PF", "BL", "M1", "M0", "P1" }; uInt32 lwidth = 2*fontWidth, collX = xpos + lwidth + 5, collY = ypos, idx = 0; for(uInt32 row = 0; row < 5; ++row) { // Add vertical label new StaticTextWidget(boss, lfont, xpos, ypos + row*(lineHeight+3), 2*fontWidth, fontHeight, rowLabel[row], TextAlign::Left); for(uInt32 col = 0; col < 5 - row; ++col) { myCollision[idx] = new CheckboxWidget(boss, lfont, collX, collY, "", CheckboxWidget::kCheckActionCmd); myCollision[idx]->setTarget(this); myCollision[idx]->setID(idx); // We need to know where the PF_BL register is, to properly position // the CXCLR button if(idx == kBL_PFID) cxclrY = collY; // Add horizontal label uInt32 labelx = collX; if(lwidth > uInt32(myCollision[idx]->getWidth())) labelx -= (lwidth - myCollision[idx]->getWidth()) / 2; else labelx += (myCollision[idx]->getWidth() - lwidth) / 2; new StaticTextWidget(boss, lfont, labelx, ypos-lineHeight, lwidth, fontHeight, colLabel[col], TextAlign::Left); collX += myCollision[idx]->getWidth() + 10; idx++; } collX = xpos + lwidth + 5; collY += lineHeight+3; } // Clear all collision bits buttonX = collX + 5*(myCollision[0]->getWidth() + 10) - buttonW - 10; buttonY = lineHeight == 15 ? cxclrY : cxclrY - 4; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "CXCLR", kCxclrCmd); b->setTarget(this); addFocusWidget(b); //////////////////////////// // P0 register info //////////////////////////// // grP0 (new) xpos = 10; ypos = collY + 4; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "P0", TextAlign::Left); xpos += 2*fontWidth + 5; myGRP0 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1); myGRP0->setTarget(this); myGRP0->setID(kGRP0ID); myGRP0->setBackgroundColor(-1); addFocusWidget(myGRP0); // posP0 xpos += myGRP0->getWidth() + 12; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "Pos#", TextAlign::Left); xpos += t->getWidth() + 2; myPosP0 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 3, 8, Common::Base::F_10); myPosP0->setTarget(this); myPosP0->setID(kPosP0ID); myPosP0->setRange(0, 160); addFocusWidget(myPosP0); // hmP0 xpos += myPosP0->getWidth() + fontWidth + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "HM", TextAlign::Left); xpos += 2*fontWidth + 5; myHMP0 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 4, Common::Base::F_16_1); myHMP0->setTarget(this); myHMP0->setID(kHMP0ID); addFocusWidget(myHMP0); // P0 reflect xpos += myHMP0->getWidth() + 15; myRefP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reflect", CheckboxWidget::kCheckActionCmd); myRefP0->setTarget(this); myRefP0->setID(kRefP0ID); addFocusWidget(myRefP0); // P0 reset xpos += myRefP0->getWidth() + 12; buttonX = xpos; b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight, "RESP0", kResP0Cmd); b->setTarget(this); addFocusWidget(b); // grP0 (old) xpos = 10 + 2*fontWidth + 5; ypos += myGRP0->getHeight() + 5; myGRP0Old = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1); myGRP0Old->setTarget(this); myGRP0Old->setID(kGRP0OldID); myGRP0Old->setBackgroundColor(-1); addFocusWidget(myGRP0Old); // P0 delay xpos += myGRP0Old->getWidth() + 12; myDelP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "VDel", CheckboxWidget::kCheckActionCmd); myDelP0->setTarget(this); myDelP0->setID(kDelP0ID); addFocusWidget(myDelP0); // NUSIZ0 (player portion) xpos += myDelP0->getWidth() + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 5*fontWidth, fontHeight, "NuSiz", TextAlign::Left); xpos += 5*fontWidth + 5; myNusizP0 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 3, Common::Base::F_16_1); myNusizP0->setTarget(this); myNusizP0->setID(kNusizP0ID); addFocusWidget(myNusizP0); xpos += myNusizP0->getWidth() + 5; myNusizP0Text = new EditTextWidget(boss, nfont, xpos, ypos, 21*fontWidth, lineHeight, ""); myNusizP0Text->setEditable(false, true); //////////////////////////// // P1 register info //////////////////////////// // grP1 (new) xpos = 10; ypos += lineHeight + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "P1", TextAlign::Left); xpos += 2*fontWidth + 5; myGRP1 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1); myGRP1->setTarget(this); myGRP1->setID(kGRP1ID); myGRP1->setBackgroundColor(-1); addFocusWidget(myGRP1); // posP1 xpos += myGRP1->getWidth() + 12; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "Pos#", TextAlign::Left); xpos += t->getWidth() + 2; myPosP1 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 3, 8, Common::Base::F_10); myPosP1->setTarget(this); myPosP1->setID(kPosP1ID); myPosP1->setRange(0, 160); addFocusWidget(myPosP1); // hmP1 xpos += myPosP1->getWidth() + fontWidth + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "HM", TextAlign::Left); xpos += 2*fontWidth + 5; myHMP1 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 4, Common::Base::F_16_1); myHMP1->setTarget(this); myHMP1->setID(kHMP1ID); addFocusWidget(myHMP1); // P1 reflect xpos += myHMP1->getWidth() + 15; myRefP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reflect", CheckboxWidget::kCheckActionCmd); myRefP1->setTarget(this); myRefP1->setID(kRefP1ID); addFocusWidget(myRefP1); // P1 reset xpos += myRefP1->getWidth() + 12; b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight, "RESP1", kResP1Cmd); b->setTarget(this); addFocusWidget(b); // grP1 (old) xpos = 10 + 2*fontWidth + 5; ypos += myGRP1->getHeight() + 5; myGRP1Old = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1); myGRP1Old->setTarget(this); myGRP1Old->setID(kGRP1OldID); myGRP1Old->setBackgroundColor(-1); addFocusWidget(myGRP1Old); // P1 delay xpos += myGRP1Old->getWidth() + 12; myDelP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "VDel", CheckboxWidget::kCheckActionCmd); myDelP1->setTarget(this); myDelP1->setID(kDelP1ID); addFocusWidget(myDelP1); // NUSIZ1 (player portion) xpos += myDelP1->getWidth() + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 5*fontWidth, fontHeight, "NuSiz", TextAlign::Left); xpos += 5*fontWidth + 5; myNusizP1 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 3, Common::Base::F_16_1); myNusizP1->setTarget(this); myNusizP1->setID(kNusizP1ID); addFocusWidget(myNusizP1); xpos += myNusizP1->getWidth() + 5; myNusizP1Text = new EditTextWidget(boss, nfont, xpos, ypos, 21*fontWidth, lineHeight, ""); myNusizP1Text->setEditable(false, true); //////////////////////////// // M0 register info //////////////////////////// // enaM0 xpos = 10; ypos += lineHeight + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "M0", TextAlign::Left); xpos += 2*fontWidth + 5; myEnaM0 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 1, 1); myEnaM0->setTarget(this); myEnaM0->setID(kEnaM0ID); myEnaM0->setBackgroundColor(-1); addFocusWidget(myEnaM0); // posM0 xpos += myEnaM0->getWidth() + 12; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "Pos#", TextAlign::Left); xpos += t->getWidth() + 2; myPosM0 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 3, 8, Common::Base::F_10); myPosM0->setTarget(this); myPosM0->setID(kPosM0ID); myPosM0->setRange(0, 160); addFocusWidget(myPosM0); // hmM0 xpos += myPosM0->getWidth() + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "HM", TextAlign::Left); xpos += 2*fontWidth + 5; myHMM0 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 4, Common::Base::F_16_1); myHMM0->setTarget(this); myHMM0->setID(kHMM0ID); addFocusWidget(myHMM0); // NUSIZ0 (missile portion) xpos += myHMM0->getWidth() + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "Size", TextAlign::Left); xpos += 4*fontWidth + 5; myNusizM0 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 2, Common::Base::F_16_1); myNusizM0->setTarget(this); myNusizM0->setID(kNusizM0ID); addFocusWidget(myNusizM0); // M0 reset to player 0 xpos += myNusizM0->getWidth() + 15; myResMP0 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reset to P0", CheckboxWidget::kCheckActionCmd); myResMP0->setTarget(this); myResMP0->setID(kResMP0ID); addFocusWidget(myResMP0); // M0 reset xpos = buttonX; b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight, "RESM0", kResM0Cmd); b->setTarget(this); addFocusWidget(b); //////////////////////////// // M1 register info //////////////////////////// // enaM1 xpos = 10; ypos += lineHeight + 4; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "M1", TextAlign::Left); xpos += 2*fontWidth + 5; myEnaM1 = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 1, 1); myEnaM1->setTarget(this); myEnaM1->setID(kEnaM1ID); myEnaM1->setBackgroundColor(-1); addFocusWidget(myEnaM1); // posM0 xpos += myEnaM1->getWidth() + 12; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "Pos#", TextAlign::Left); xpos += t->getWidth() + 2; myPosM1 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 3, 8, Common::Base::F_10); myPosM1->setTarget(this); myPosM1->setID(kPosM1ID); myPosM1->setRange(0, 160); addFocusWidget(myPosM1); // hmM0 xpos += myPosM1->getWidth() + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "HM", TextAlign::Left); xpos += 2*fontWidth + 5; myHMM1 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 4, Common::Base::F_16_1); myHMM1->setTarget(this); myHMM1->setID(kHMM1ID); addFocusWidget(myHMM1); // NUSIZ1 (missile portion) xpos += myHMM1->getWidth() + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "Size", TextAlign::Left); xpos += 4*fontWidth + 5; myNusizM1 = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 2, Common::Base::F_16_1); myNusizM1->setTarget(this); myNusizM1->setID(kNusizM1ID); addFocusWidget(myNusizM1); // M1 reset to player 0 xpos += myNusizM1->getWidth() + 15; myResMP1 = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reset to P1", CheckboxWidget::kCheckActionCmd); myResMP1->setTarget(this); myResMP1->setID(kResMP1ID); addFocusWidget(myResMP1); // M1 reset xpos = buttonX; b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight, "RESM1", kResM1Cmd); b->setTarget(this); addFocusWidget(b); //////////////////////////// // BL register info //////////////////////////// // enaBL xpos = 10; ypos += lineHeight + 4; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "BL", TextAlign::Left); xpos += 2*fontWidth + 5; myEnaBL = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 1, 1); myEnaBL->setTarget(this); myEnaBL->setID(kEnaBLID); myEnaBL->setBackgroundColor(-1); addFocusWidget(myEnaBL); // posBL xpos += myEnaBL->getWidth() + 12; t = new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "Pos#", TextAlign::Left); xpos += t->getWidth() + 2; myPosBL = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 3, 8, Common::Base::F_10); myPosBL->setTarget(this); myPosBL->setID(kPosBLID); myPosBL->setRange(0, 160); addFocusWidget(myPosBL); // hmBL xpos += myPosBL->getWidth() + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "HM", TextAlign::Left); xpos += 2*fontWidth + 5; myHMBL = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 4, Common::Base::F_16_1); myHMBL->setTarget(this); myHMBL->setID(kHMBLID); addFocusWidget(myHMBL); // CTRLPF (size portion) xpos += myHMBL->getWidth() + 12; new StaticTextWidget(boss, lfont, xpos, ypos+2, 4*fontWidth, fontHeight, "Size", TextAlign::Left); xpos += 4*fontWidth + 5; mySizeBL = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 1, 2, Common::Base::F_16_1); mySizeBL->setTarget(this); mySizeBL->setID(kSizeBLID); addFocusWidget(mySizeBL); // Reset ball xpos = buttonX; b = new ButtonWidget(boss, lfont, xpos, ypos, buttonW, lineHeight, "RESBL", kResBLCmd); b->setTarget(this); addFocusWidget(b); // Ball (old) xpos = 10 + 2*fontWidth + 5; ypos += myEnaBL->getHeight() + 5; myEnaBLOld = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 1, 1); myEnaBLOld->setTarget(this); myEnaBLOld->setID(kEnaBLOldID); myEnaBLOld->setBackgroundColor(-1); addFocusWidget(myEnaBLOld); // Ball delay xpos += myEnaBLOld->getWidth() + 12; myDelBL = new CheckboxWidget(boss, lfont, xpos, ypos+1, "VDel", CheckboxWidget::kCheckActionCmd); myDelBL->setTarget(this); myDelBL->setID(kDelBLID); addFocusWidget(myDelBL); //////////////////////////// // PF 0/1/2 registers //////////////////////////// const GUI::Font& sf = instance().frameBuffer().smallFont(); const int sfWidth = sf.getMaxCharWidth(), sfHeight = sf.getFontHeight(); const char* const bitNames[] = { "0", "1", "2", "3", "4", "5", "6", "7" }; // PF0 xpos = 10; ypos += lineHeight + sfHeight + 6; new StaticTextWidget(boss, lfont, xpos, ypos+2, 2*fontWidth, fontHeight, "PF", TextAlign::Left); xpos += 2*fontWidth + 5; myPF[0] = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 4, 1); myPF[0]->setTarget(this); myPF[0]->setID(kPF0ID); addFocusWidget(myPF[0]); // PF1 xpos += myPF[0]->getWidth() + 2; myPF[1] = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1); myPF[1]->setTarget(this); myPF[1]->setID(kPF1ID); addFocusWidget(myPF[1]); // PF2 xpos += myPF[1]->getWidth() + 2; myPF[2] = new TogglePixelWidget(boss, nfont, xpos, ypos+1, 8, 1); myPF[2]->setTarget(this); myPF[2]->setID(kPF2ID); addFocusWidget(myPF[2]); // PFx bit labels auto start = [&](int sw) { return (sw - sfWidth) / 2; }; int colw = myPF[0]->getWidth() / 4; xpos = 10 + 2*fontWidth + 5 + start(colw); int _ypos = ypos - sfHeight; for(int i = 4; i <= 7; ++i) { new StaticTextWidget(boss, sf, xpos, _ypos, sfWidth, sfHeight, bitNames[i], TextAlign::Left); xpos += colw; } xpos = 10 + 2*fontWidth + 5 + myPF[0]->getWidth() + 2 + start(colw); for(int i = 7; i >= 0; --i) { new StaticTextWidget(boss, sf, xpos, _ypos, sfWidth, sfHeight, bitNames[i], TextAlign::Left); xpos += colw; } xpos = 10 + 2*fontWidth + 5 + myPF[0]->getWidth() + 2 + myPF[1]->getWidth() + 2 + start(colw); for(int i = 0; i <= 7; ++i) { new StaticTextWidget(boss, sf, xpos, _ypos, sfWidth, sfHeight, bitNames[i], TextAlign::Left); xpos += colw; } // PF reflect, score, priority xpos = 10 + 4*fontWidth; ypos += lineHeight + 6; myRefPF = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Reflect", CheckboxWidget::kCheckActionCmd); myRefPF->setTarget(this); myRefPF->setID(kRefPFID); addFocusWidget(myRefPF); xpos += myRefPF->getWidth() + 15; myScorePF = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Score", CheckboxWidget::kCheckActionCmd); myScorePF->setTarget(this); myScorePF->setID(kScorePFID); addFocusWidget(myScorePF); xpos += myScorePF->getWidth() + 15; myPriorityPF = new CheckboxWidget(boss, lfont, xpos, ypos+1, "Priority", CheckboxWidget::kCheckActionCmd); myPriorityPF->setTarget(this); myPriorityPF->setID(kPriorityPFID); addFocusWidget(myPriorityPF); xpos = 10; ypos += 2 * lineHeight; t = new StaticTextWidget(boss, lfont, xpos, ypos, 13*fontWidth, fontHeight, "Queued Writes", TextAlign::Left); xpos += t->getWidth() + 10; myDelayQueueWidget = new DelayQueueWidget(boss, lfont, xpos, ypos); //////////////////////////// // Strobe buttons //////////////////////////// buttonX = xpos + myDelayQueueWidget->getWidth() + 20; buttonY = ypos; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "WSYNC", kWsyncCmd); b->setTarget(this); addFocusWidget(b); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "RSYNC", kRsyncCmd); b->setTarget(this); addFocusWidget(b); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "HMOVE", kHmoveCmd); b->setTarget(this); addFocusWidget(b); buttonY += lineHeight + 3; b = new ButtonWidget(boss, lfont, buttonX, buttonY, buttonW, lineHeight, "HMCLR", kHmclrCmd); b->setTarget(this); addFocusWidget(b); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { Debugger& dbg = instance().debugger(); TIADebug& tia = dbg.tiaDebug(); switch(cmd) { case kWsyncCmd: tia.strobeWsync(); break; case kRsyncCmd: tia.strobeRsync(); break; case kResP0Cmd: tia.strobeResP0(); break; case kResP1Cmd: tia.strobeResP1(); break; case kResM0Cmd: tia.strobeResM0(); break; case kResM1Cmd: tia.strobeResM1(); break; case kResBLCmd: tia.strobeResBL(); break; case kHmoveCmd: tia.strobeHmove(); break; case kHmclrCmd: tia.strobeHmclr(); break; case kCxclrCmd: tia.strobeCxclr(); break; case kDbgClCmd: myFixedEnabled->setState(tia.tia().toggleFixedColors()); break; case DataGridWidget::kItemDataChangedCmd: switch(id) { case kColorRegsID: changeColorRegs(); break; case kPosP0ID: tia.posP0(myPosP0->getSelectedValue()); break; case kPosP1ID: tia.posP1(myPosP1->getSelectedValue()); break; case kPosM0ID: tia.posM0(myPosM0->getSelectedValue()); break; case kPosM1ID: tia.posM1(myPosM1->getSelectedValue()); break; case kPosBLID: tia.posBL(myPosBL->getSelectedValue()); break; case kHMP0ID: tia.hmP0(myHMP0->getSelectedValue()); break; case kHMP1ID: tia.hmP1(myHMP1->getSelectedValue()); break; case kHMM0ID: tia.hmM0(myHMM0->getSelectedValue()); break; case kHMM1ID: tia.hmM1(myHMM1->getSelectedValue()); break; case kHMBLID: tia.hmBL(myHMBL->getSelectedValue()); break; case kNusizP0ID: tia.nusizP0(myNusizP0->getSelectedValue()); myNusizP0Text->setText(tia.nusizP0String()); break; case kNusizP1ID: tia.nusizP1(myNusizP1->getSelectedValue()); myNusizP1Text->setText(tia.nusizP1String()); break; case kNusizM0ID: tia.nusizM0(myNusizM0->getSelectedValue()); break; case kNusizM1ID: tia.nusizM1(myNusizM1->getSelectedValue()); break; case kSizeBLID: tia.sizeBL(mySizeBL->getSelectedValue()); break; default: cerr << "TiaWidget DG changed\n"; break; } break; case ToggleWidget::kItemDataChangedCmd: switch(id) { case kGRP0ID: tia.grP0(myGRP0->getIntState()); break; case kGRP0OldID: tia.setGRP0Old(myGRP0Old->getIntState()); break; case kGRP1ID: tia.grP1(myGRP1->getIntState()); break; case kGRP1OldID: tia.setGRP1Old(myGRP1Old->getIntState()); break; case kEnaM0ID: tia.enaM0(myEnaM0->getIntState()); break; case kEnaM1ID: tia.enaM1(myEnaM1->getIntState()); break; case kEnaBLID: tia.enaBL(myEnaBL->getIntState()); break; case kEnaBLOldID: tia.setENABLOld(myEnaBLOld->getIntState() != 0); break; case kPF0ID: tia.pf0(myPF[0]->getIntState()); break; case kPF1ID: tia.pf1(myPF[1]->getIntState()); break; case kPF2ID: tia.pf2(myPF[2]->getIntState()); break; } break; case CheckboxWidget::kCheckActionCmd: switch(id) { case kP0_PFID: tia.collision(CollisionBit::P0PF, true); break; case kP0_BLID: tia.collision(CollisionBit::P0BL, true); break; case kP0_M1ID: tia.collision(CollisionBit::M1P0, true); break; case kP0_M0ID: tia.collision(CollisionBit::M0P0, true); break; case kP0_P1ID: tia.collision(CollisionBit::P0P1, true); break; case kP1_PFID: tia.collision(CollisionBit::P1PF, true); break; case kP1_BLID: tia.collision(CollisionBit::P1BL, true); break; case kP1_M1ID: tia.collision(CollisionBit::M1P1, true); break; case kP1_M0ID: tia.collision(CollisionBit::M0P1, true); break; case kM0_PFID: tia.collision(CollisionBit::M0PF, true); break; case kM0_BLID: tia.collision(CollisionBit::M0BL, true); break; case kM0_M1ID: tia.collision(CollisionBit::M0M1, true); break; case kM1_PFID: tia.collision(CollisionBit::M1PF, true); break; case kM1_BLID: tia.collision(CollisionBit::M1BL, true); break; case kBL_PFID: tia.collision(CollisionBit::BLPF, true); break; case kRefP0ID: tia.refP0(myRefP0->getState() ? 1 : 0); break; case kRefP1ID: tia.refP1(myRefP1->getState() ? 1 : 0); break; case kDelP0ID: tia.vdelP0(myDelP0->getState() ? 1 : 0); break; case kDelP1ID: tia.vdelP1(myDelP1->getState() ? 1 : 0); break; case kDelBLID: tia.vdelBL(myDelBL->getState() ? 1 : 0); break; case kResMP0ID: tia.resMP0(myResMP0->getState() ? 1 : 0); break; case kResMP1ID: tia.resMP1(myResMP1->getState() ? 1 : 0); break; case kRefPFID: tia.refPF(myRefPF->getState() ? 1 : 0); break; case kScorePFID: tia.scorePF(myScorePF->getState() ? 1 : 0); break; case kPriorityPFID: tia.priorityPF(myPriorityPF->getState() ? 1 : 0); break; } break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaWidget::loadConfig() { IntArray alist; IntArray vlist; BoolArray blist, changed, grNew, grOld; Debugger& dbg = instance().debugger(); TIADebug& tia = dbg.tiaDebug(); const TiaState& state = static_cast(tia.getState()); const TiaState& oldstate = static_cast(tia.getOldState()); // Color registers alist.clear(); vlist.clear(); changed.clear(); for(uInt32 i = 0; i < 4; i++) { alist.push_back(i); vlist.push_back(state.coluRegs[i]); changed.push_back(state.coluRegs[i] != oldstate.coluRegs[i]); } myColorRegs->setList(alist, vlist, changed); bool fixed = tia.tia().usingFixedColors(); myCOLUP0Color->setColor(state.coluRegs[0]); myCOLUP1Color->setColor(state.coluRegs[1]); myCOLUPFColor->setColor(state.coluRegs[2]); myCOLUBKColor->setColor(state.coluRegs[3]); myCOLUP0Color->setCrossed(fixed); myCOLUP1Color->setCrossed(fixed); myCOLUPFColor->setCrossed(fixed); myCOLUBKColor->setCrossed(fixed); // Fixed debug colors myFixedEnabled->setState(fixed); for(uInt32 c = 0; c < 8; ++c) { myFixedColors[c]->setColor(state.fixedCols[c]); myFixedColors[c]->setCrossed(!fixed); } //////////////////////////// // Collision register bits //////////////////////////// myCollision[kP0_PFID]->setState(tia.collP0_PF(), state.cx[0] != oldstate.cx[0]); myCollision[kP0_BLID]->setState(tia.collP0_BL(), state.cx[1] != oldstate.cx[1]); myCollision[kP0_M1ID]->setState(tia.collM1_P0(), state.cx[2] != oldstate.cx[2]); myCollision[kP0_M0ID]->setState(tia.collM0_P0(), state.cx[3] != oldstate.cx[3]); myCollision[kP0_P1ID]->setState(tia.collP0_P1(), state.cx[4] != oldstate.cx[4]); myCollision[kP1_PFID]->setState(tia.collP1_PF(), state.cx[5] != oldstate.cx[5]); myCollision[kP1_BLID]->setState(tia.collP1_BL(), state.cx[6] != oldstate.cx[6]); myCollision[kP1_M1ID]->setState(tia.collM1_P1(), state.cx[7] != oldstate.cx[7]); myCollision[kP1_M0ID]->setState(tia.collM0_P1(), state.cx[8] != oldstate.cx[8]); myCollision[kM0_PFID]->setState(tia.collM0_PF(), state.cx[9] != oldstate.cx[9]); myCollision[kM0_BLID]->setState(tia.collM0_BL(), state.cx[10] != oldstate.cx[10]); myCollision[kM0_M1ID]->setState(tia.collM0_M1(), state.cx[11] != oldstate.cx[11]); myCollision[kM1_PFID]->setState(tia.collM1_PF(), state.cx[12] != oldstate.cx[12]); myCollision[kM1_BLID]->setState(tia.collM1_BL(), state.cx[13] != oldstate.cx[13]); myCollision[kBL_PFID]->setState(tia.collBL_PF(), state.cx[14] != oldstate.cx[14]); //////////////////////////// // P0 register info //////////////////////////// // grP0 (new and old) if(tia.vdelP0()) { myGRP0->setColor(kBGColorLo); myGRP0Old->setColor(state.coluRegs[0]); myGRP0Old->setCrossed(false); } else { myGRP0->setColor(state.coluRegs[0]); myGRP0Old->setColor(kBGColorLo); myGRP0Old->setCrossed(true); } myGRP0->setIntState(state.gr[P0], false); myGRP0Old->setIntState(state.gr[P0+2], false); // posP0 myPosP0->setList(0, state.pos[P0], state.pos[P0] != oldstate.pos[P0]); // hmP0 myHMP0->setList(0, state.hm[P0], state.hm[P0] != oldstate.hm[P0]); // refP0 & vdelP0 myRefP0->setState(tia.refP0(), state.ref[P0] != oldstate.ref[P0]); myDelP0->setState(tia.vdelP0(), state.vdel[P0] != oldstate.vdel[P0]); // NUSIZ0 (player portion) bool nusiz0changed = state.size[P0] != oldstate.size[P0]; myNusizP0->setList(0, state.size[P0], nusiz0changed); myNusizP0Text->setText(tia.nusizP0String(), nusiz0changed); //////////////////////////// // P1 register info //////////////////////////// // grP1 (new and old) if(tia.vdelP1()) { myGRP1->setColor(kBGColorLo); myGRP1Old->setColor(state.coluRegs[1]); myGRP1Old->setCrossed(false); } else { myGRP1->setColor(state.coluRegs[1]); myGRP1Old->setColor(kBGColorLo); myGRP1Old->setCrossed(true); } myGRP1->setIntState(state.gr[P1], false); myGRP1Old->setIntState(state.gr[P1+2], false); // posP1 myPosP1->setList(0, state.pos[P1], state.pos[P1] != oldstate.pos[P1]); // hmP1 myHMP1->setList(0, state.hm[P1], state.hm[P1] != oldstate.hm[P1]); // refP1 & vdelP1 myRefP1->setState(tia.refP1(), state.ref[P1] != oldstate.ref[P1]); myDelP1->setState(tia.vdelP1(), state.vdel[P1] != oldstate.vdel[P1]); // NUSIZ1 (player portion) bool nusiz1changed = state.size[P1] != oldstate.size[P1]; myNusizP1->setList(0, state.size[P1], nusiz1changed); myNusizP1Text->setText(tia.nusizP1String(), nusiz1changed); //////////////////////////// // M0 register info //////////////////////////// // enaM0 myEnaM0->setColor(state.coluRegs[0]); myEnaM0->setIntState(tia.enaM0() ? 1 : 0, false); // posM0 myPosM0->setList(0, state.pos[M0], state.pos[M0] != oldstate.pos[M0]); // hmM0 myHMM0->setList(0, state.hm[M0], state.hm[M0] != oldstate.hm[M0]); // NUSIZ0 (missile portion) myNusizM0->setList(0, state.size[M0], state.size[M0] != oldstate.size[M0]); // resMP0 myResMP0->setState(tia.resMP0(), state.res[P0] != oldstate.res[P0]); //////////////////////////// // M1 register info //////////////////////////// // enaM1 myEnaM1->setColor(state.coluRegs[1]); myEnaM1->setIntState(tia.enaM1() ? 1 : 0, false); // posM1 myPosM1->setList(0, state.pos[M1], state.pos[M1] != oldstate.pos[M1]); // hmM1 myHMM1->setList(0, state.hm[M1], state.hm[M1] != oldstate.hm[M1]); // NUSIZ1 (missile portion) myNusizM1->setList(0, state.size[M1], state.size[M1] != oldstate.size[M1]); // resMP1 myResMP1->setState(tia.resMP1(),state.res[P1] != oldstate.res[P1]); //////////////////////////// // BL register info //////////////////////////// // enaBL (new and old) if(tia.vdelBL()) { myEnaBL->setColor(kBGColorLo); myEnaBLOld->setColor(state.coluRegs[2]); myEnaBLOld->setCrossed(false); } else { myEnaBL->setColor(state.coluRegs[2]); myEnaBLOld->setColor(kBGColorLo); myEnaBLOld->setCrossed(true); } myEnaBL->setIntState(state.gr[4], false); myEnaBLOld->setIntState(state.gr[5], false); // posBL myPosBL->setList(0, state.pos[BL], state.pos[BL] != oldstate.pos[BL]); // hmBL myHMBL->setList(0, state.hm[BL], state.hm[BL] != oldstate.hm[BL]); // CTRLPF (size portion) mySizeBL->setList(0, state.size[BL], state.size[BL] != oldstate.size[BL]); // vdelBL myDelBL->setState(tia.vdelBL(), state.vdel[2] != oldstate.vdel[2]); //////////////////////////// // PF register info //////////////////////////// // PF0 myPF[0]->setColor(state.coluRegs[2]); myPF[0]->setIntState(state.pf[0], true); // reverse bit order // PF1 myPF[1]->setColor(state.coluRegs[2]); myPF[1]->setIntState(state.pf[1], false); // PF2 myPF[2]->setColor(state.coluRegs[2]); myPF[2]->setIntState(state.pf[2], true); // reverse bit order // Reflect myRefPF->setState(tia.refPF(), state.pf[3] != oldstate.pf[3]); // Score myScorePF->setState(tia.scorePF(), state.pf[4] != oldstate.pf[4]); // Priority myPriorityPF->setState(tia.priorityPF(), state.pf[5] != oldstate.pf[5]); myDelayQueueWidget->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaWidget::changeColorRegs() { int addr = myColorRegs->getSelectedAddr(); int value = myColorRegs->getSelectedValue(); switch(addr) { case kCOLUP0Addr: instance().debugger().tiaDebug().coluP0(value); myCOLUP0Color->setColor(value); break; case kCOLUP1Addr: instance().debugger().tiaDebug().coluP1(value); myCOLUP1Color->setColor(value); break; case kCOLUPFAddr: instance().debugger().tiaDebug().coluPF(value); myCOLUPFColor->setColor(value); break; case kCOLUBKAddr: instance().debugger().tiaDebug().coluBK(value); myCOLUBKColor->setColor(value); break; } } stella-5.1.1/src/debugger/gui/TiaWidget.hxx000066400000000000000000000106671324334165500205730ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_WIDGET_HXX #define TIA_WIDGET_HXX class GuiObject; class ButtonWidget; class DataGridWidget; class StaticTextWidget; class ToggleBitWidget; class TogglePixelWidget; class EditTextWidget; class ColorWidget; class DelayQueueWidget; #include "Widget.hxx" #include "Command.hxx" class TiaWidget : public Widget, public CommandSender { public: TiaWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h); virtual ~TiaWidget() = default; private: DataGridWidget* myColorRegs; ColorWidget* myCOLUP0Color; ColorWidget* myCOLUP1Color; ColorWidget* myCOLUPFColor; ColorWidget* myCOLUBKColor; CheckboxWidget* myFixedEnabled; ColorWidget* myFixedColors[8]; TogglePixelWidget* myGRP0; TogglePixelWidget* myGRP0Old; TogglePixelWidget* myGRP1; TogglePixelWidget* myGRP1Old; DataGridWidget* myPosP0; DataGridWidget* myPosP1; DataGridWidget* myPosM0; DataGridWidget* myPosM1; DataGridWidget* myPosBL; DataGridWidget* myHMP0; DataGridWidget* myHMP1; DataGridWidget* myHMM0; DataGridWidget* myHMM1; DataGridWidget* myHMBL; DataGridWidget* myNusizP0; DataGridWidget* myNusizP1; DataGridWidget* myNusizM0; DataGridWidget* myNusizM1; DataGridWidget* mySizeBL; EditTextWidget* myNusizP0Text; EditTextWidget* myNusizP1Text; CheckboxWidget* myRefP0; CheckboxWidget* myRefP1; CheckboxWidget* myDelP0; CheckboxWidget* myDelP1; CheckboxWidget* myDelBL; TogglePixelWidget* myEnaM0; TogglePixelWidget* myEnaM1; TogglePixelWidget* myEnaBL; TogglePixelWidget* myEnaBLOld; CheckboxWidget* myResMP0; CheckboxWidget* myResMP1; /** Collision register bits */ CheckboxWidget* myCollision[15]; TogglePixelWidget* myPF[3]; CheckboxWidget* myRefPF; CheckboxWidget* myScorePF; CheckboxWidget* myPriorityPF; DelayQueueWidget* myDelayQueueWidget; // ID's for the various widgets // We need ID's, since there are more than one of several types of widgets enum { kP0_PFID, kP0_BLID, kP0_M1ID, kP0_M0ID, kP0_P1ID, kP1_PFID, kP1_BLID, kP1_M1ID, kP1_M0ID, kM0_PFID, kM0_BLID, kM0_M1ID, kM1_PFID, kM1_BLID, kBL_PFID, // Make these first, since we want them to start from 0 kRamID, kColorRegsID, kGRP0ID, kGRP0OldID, kGRP1ID, kGRP1OldID, kPosP0ID, kPosP1ID, kPosM0ID, kPosM1ID, kPosBLID, kHMP0ID, kHMP1ID, kHMM0ID, kHMM1ID, kHMBLID, kRefP0ID, kRefP1ID, kDelP0ID, kDelP1ID, kDelBLID, kNusizP0ID, kNusizP1ID, kNusizM0ID, kNusizM1ID, kSizeBLID, kEnaM0ID, kEnaM1ID, kEnaBLID, kEnaBLOldID, kResMP0ID, kResMP1ID, kPF0ID, kPF1ID, kPF2ID, kRefPFID, kScorePFID, kPriorityPFID }; // Strobe button and misc commands enum { kWsyncCmd = 'Swsy', kRsyncCmd = 'Srsy', kResP0Cmd = 'Srp0', kResP1Cmd = 'Srp1', kResM0Cmd = 'Srm0', kResM1Cmd = 'Srm1', kResBLCmd = 'Srbl', kHmoveCmd = 'Shmv', kHmclrCmd = 'Shmc', kCxChgCmd = 'Sccc', kCxclrCmd = 'Scxl', kDbgClCmd = 'DBGc', }; // Color registers enum { kCOLUP0Addr, kCOLUP1Addr, kCOLUPFAddr, kCOLUBKAddr }; private: void changeColorRegs(); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void loadConfig() override; // Following constructors and assignment operators not supported TiaWidget() = delete; TiaWidget(const TiaWidget&) = delete; TiaWidget(TiaWidget&&) = delete; TiaWidget& operator=(const TiaWidget&) = delete; TiaWidget& operator=(TiaWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/TiaZoomWidget.cxx000066400000000000000000000156651324334165500214360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Console.hxx" #include "TIA.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Widget.hxx" #include "GuiObject.hxx" #include "ContextMenu.hxx" #include "TiaZoomWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TiaZoomWidget::TiaZoomWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : Widget(boss, font, x, y, 16, 16), CommandSender(boss) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_TRACK_MOUSE; _bgcolor = _bgcolorhi = kDlgColor; // Use all available space, up to the maximum bounds of the TIA image _w = std::min(w, 320); _h = std::min(h, 260); addFocusWidget(this); // Initialize positions myZoomLevel = 2; myNumCols = ((_w - 4) >> 1) / myZoomLevel; myNumRows = (_h - 4) / myZoomLevel; myXOff = myYOff = 0; myMouseMoving = false; myXClick = myYClick = 0; // Create context menu for zoom levels VariantList l; VarList::push_back(l, "2x zoom", "2"); VarList::push_back(l, "4x zoom", "4"); VarList::push_back(l, "8x zoom", "8"); myMenu = make_unique(this, font, l); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::loadConfig() { setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::setPos(int x, int y) { // Center on given x,y point myXOff = (x >> 1) - (myNumCols >> 1); myYOff = y - (myNumRows >> 1); recalc(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::zoom(int level) { if(myZoomLevel == level) return; myZoomLevel = level; myNumCols = ((_w - 4) >> 1) / myZoomLevel; myNumRows = (_h - 4) / myZoomLevel; recalc(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::recalc() { const int tw = instance().console().tia().width(), th = instance().console().tia().height(); // Don't go past end of framebuffer myXOff = BSPF::clamp(myXOff, 0, tw - myNumCols); myYOff = BSPF::clamp(myYOff, 0, th - myNumRows); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { // Button 1 is for 'drag'/movement of the image // Button 2 is for context menu if(b == MouseButton::LEFT) { // Indicate mouse drag started/in progress myMouseMoving = true; myXClick = x; myYClick = y; } else if(b == MouseButton::RIGHT) { // Add menu at current x,y mouse location myMenu->show(x + getAbsX(), y + getAbsY()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { myMouseMoving = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::handleMouseWheel(int x, int y, int direction) { if(direction > 0) handleEvent(Event::UIDown); else handleEvent(Event::UIUp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::handleMouseMoved(int x, int y) { // TODO: Not yet working - finish for next release #if 0 if(myMouseMoving) { if(x < 0 || y < 0 || x > _w || y > _h) return; int diffx = ((x - myXClick) >> 1);// / myZoomLevel; int diffy = (y - myYClick);// / myZoomLevel; // myXClick = x; // myYClick = y; //cerr << diffx << " " << diffy << endl; myXOff -= diffx; myYOff -= diffy; recalc(); // cerr << x << ", " << y << endl; } #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::handleMouseLeft() { myMouseMoving = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TiaZoomWidget::handleEvent(Event::Type event) { bool handled = true; switch(event) { case Event::UIUp: myYOff -= 4; break; case Event::UIDown: myYOff += 4; break; case Event::UILeft: myXOff -= 2; break; case Event::UIRight: myXOff += 2; break; case Event::UIPgUp: myYOff = 0; break; case Event::UIPgDown: myYOff = _h; break; case Event::UIHome: myXOff = 0; break; case Event::UIEnd: myXOff = _w; break; default: handled = false; break; } if(handled) recalc(); return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case ContextMenu::kItemSelectedCmd: { int level = myMenu->getSelectedTag().toInt(); if(level > 0) zoom(level); break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TiaZoomWidget::drawWidget(bool hilite) { //cerr << "TiaZoomWidget::drawWidget\n"; FBSurface& s = dialog().surface(); s.fillRect(_x+1, _y+1, _w-2, _h-2, kBGColor); #ifndef FLAT_UI s.box(_x, _y, _w, _h, kColor, kShadowColor); #else s.frameRect(_x, _y, _w, _h, kColor); #endif // Draw the zoomed image // This probably isn't as efficient as it can be, but it's a small area // and I don't have time to make it faster :) const uInt8* currentFrame = instance().console().tia().frameBuffer(); const int width = instance().console().tia().width(), wzoom = myZoomLevel << 1, hzoom = myZoomLevel; // Get current scanline position // This determines where the frame greying should start uInt32 scanx, scany, scanoffset; instance().console().tia().electronBeamPos(scanx, scany); scanoffset = width * scany + scanx; int x, y, col, row; for(y = myYOff, row = 0; y < myNumRows+myYOff; ++y, row += hzoom) { for(x = myXOff, col = 0; x < myNumCols+myXOff; ++x, col += wzoom) { uInt32 idx = y*width + x; uInt32 color = currentFrame[idx] | (idx > scanoffset ? 1 : 0); #ifndef FLAT_UI s.fillRect(_x + col + 2, _y + row + 2, wzoom, hzoom, color); #else s.fillRect(_x + col + 1, _y + row + 1, wzoom, hzoom, color); #endif } } } stella-5.1.1/src/debugger/gui/TiaZoomWidget.hxx000066400000000000000000000042631324334165500214330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_ZOOM_WIDGET_HXX #define TIA_ZOOM_WIDGET_HXX class GuiObject; class ContextMenu; #include "Widget.hxx" #include "Command.hxx" class TiaZoomWidget : public Widget, public CommandSender { public: TiaZoomWidget(GuiObject *boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~TiaZoomWidget() = default; void loadConfig() override; void setPos(int x, int y); private: void zoom(int level); void recalc(); void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; void handleMouseMoved(int x, int y) override; void handleMouseLeft() override; bool handleEvent(Event::Type event) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void drawWidget(bool hilite) override; bool wantsFocus() const override { return true; } private: unique_ptr myMenu; int myZoomLevel; int myNumCols, myNumRows; int myXOff, myYOff; bool myMouseMoving; int myXClick, myYClick; private: // Following constructors and assignment operators not supported TiaZoomWidget() = delete; TiaZoomWidget(const TiaZoomWidget&) = delete; TiaZoomWidget(TiaZoomWidget&&) = delete; TiaZoomWidget& operator=(const TiaZoomWidget&) = delete; TiaZoomWidget& operator=(TiaZoomWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/ToggleBitWidget.cxx000066400000000000000000000101451324334165500217200ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Widget.hxx" #include "Dialog.hxx" #include "Debugger.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "ToggleBitWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ToggleBitWidget::ToggleBitWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows, int colchars) : ToggleWidget(boss, font, x, y, cols, rows, 1) { _rowHeight = font.getLineHeight(); _colWidth = colchars * font.getMaxCharWidth() + 8; // Make sure all lists contain some default values int size = _rows * _cols; while(size--) { _offList.push_back("0"); _onList.push_back("1"); _stateList.push_back(false); _changedList.push_back(false); } // Calculate real dimensions _w = _colWidth * cols + 1; _h = _rowHeight * rows + 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleBitWidget::setList(const StringList& off, const StringList& on) { _offList.clear(); _offList = off; _onList.clear(); _onList = on; assert(int(_offList.size()) == _rows * _cols); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleBitWidget::setState(const BoolArray& state, const BoolArray& changed) { _stateList.clear(); _stateList = state; _changedList.clear(); _changedList = changed; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleBitWidget::drawWidget(bool hilite) { //cerr << "ToggleBitWidget::drawWidget\n"; FBSurface& s = dialog().surface(); int row, col; string buffer; // Draw the internal grid and labels int linewidth = _cols * _colWidth; #ifndef FLAT_UI for (row = 0; row <= _rows; row++) s.hLine(_x, _y + (row * _rowHeight), _x + linewidth, kColor); int lineheight = _rows * _rowHeight; for (col = 0; col <= _cols; col++) s.vLine(_x + (col * _colWidth), _y, _y + lineheight, kColor); #else s.frameRect(_x, _y, _w, _h, kColor); for(row = 1; row <= _rows - 1; row++) s.hLine(_x + 1, _y + (row * _rowHeight), _x + linewidth - 1, kBGColorLo); int lineheight = _rows * _rowHeight; for(col = 1; col <= _cols - 1; col++) s.vLine(_x + (col * _colWidth), _y + 1, _y + lineheight - 1, kBGColorLo); #endif // Draw the list items for (row = 0; row < _rows; row++) { for (col = 0; col < _cols; col++) { uInt32 textColor = kTextColor; int x = _x + 4 + (col * _colWidth); int y = _y + 2 + (row * _rowHeight); int pos = row*_cols + col; // Draw the selected item inverted, on a highlighted background. if(_currentRow == row && _currentCol == col && _hasFocus) { s.fillRect(x - 4, y - 2, _colWidth + 1, _rowHeight + 1, kTextColorHi); textColor = kTextColorInv; } if(_stateList[pos]) buffer = _onList[pos]; else buffer = _offList[pos]; if(isEditable()) { // Highlight changes if(_changedList[pos]) { s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, kDbgChangedColor); s.drawString(_font, buffer, x, y, _colWidth, kDbgChangedTextColor); } else s.drawString(_font, buffer, x, y, _colWidth, textColor); } else { s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, kBGColorHi); s.drawString(_font, buffer, x, y, _colWidth, kTextColor); } } } } stella-5.1.1/src/debugger/gui/ToggleBitWidget.hxx000066400000000000000000000031571324334165500217320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TOGGLE_BIT_WIDGET_HXX #define TOGGLE_BIT_WIDGET_HXX #include "ToggleWidget.hxx" /* ToggleBitWidget */ class ToggleBitWidget : public ToggleWidget { public: ToggleBitWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows, int colchars = 1); virtual ~ToggleBitWidget() = default; void setList(const StringList& off, const StringList& on); void setState(const BoolArray& state, const BoolArray& changed); protected: void drawWidget(bool hilite) override; protected: StringList _offList; StringList _onList; private: // Following constructors and assignment operators not supported ToggleBitWidget() = delete; ToggleBitWidget(const ToggleBitWidget&) = delete; ToggleBitWidget(ToggleBitWidget&&) = delete; ToggleBitWidget& operator=(const ToggleBitWidget&) = delete; ToggleBitWidget& operator=(ToggleBitWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/TogglePixelWidget.cxx000066400000000000000000000115741324334165500222720ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Widget.hxx" #include "Font.hxx" #include "Debugger.hxx" #include "FBSurface.hxx" #include "TogglePixelWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TogglePixelWidget::TogglePixelWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows) : ToggleWidget(boss, font, x, y, cols, rows, 1), _pixelColor(0), _backgroundColor(kDlgColor), _swapBits(false), _crossBits(false) { _rowHeight = _colWidth = font.getLineHeight(); // Calculate real dimensions _w = _colWidth * cols + 1; _h = _rowHeight * rows + 1; // Changed state isn't used, but we still need to fill it while(int(_changedList.size()) < rows * cols) _changedList.push_back(false); // prepare _stateList for change tracking while(int(_stateList.size()) < rows * cols) _stateList.push_back(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TogglePixelWidget::setState(const BoolArray& state) { // track changes automatically for(int row = 0; row < _rows; row++) { for(int col = 0; col < _cols; col++) { int pos = row * _cols + col; _changedList[pos] = _stateList[pos] != state[pos]; } } _stateList.clear(); _stateList = state; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TogglePixelWidget::setIntState(int value, bool swap) { uInt32 size = _rows * _cols; _swapBits = swap; // Create array of required size BoolArray b; while(b.size() < size) b.push_back(false); // Bits in an int increase from right to left, but a BoolArray // is scanned from left to right. // // Swap off means treat the above as normal (ie, contruct the // BoolArray as we read the int from right to left). // // Swap on means reverse of swap off! Sorry if this is // confusing. for(uInt32 i = 0; i < size; ++i) { bool bitIsSet = value & (1 << i); if(_swapBits) b[i] = bitIsSet; else b[size-i-1] = bitIsSet; } setState(b); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TogglePixelWidget::getIntState() { // Construct int based on current state and swap uInt32 value = 0, size = int(_stateList.size()); for(uInt32 i = 0; i < size; ++i) { if(_stateList[i]) { if(_swapBits) value |= 1 << i; else value |= 1 << (size-i-1); } } return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TogglePixelWidget::drawWidget(bool hilite) { //cerr << "TogglePixelWidget::drawWidget\n"; FBSurface& s = dialog().surface(); int row, col; // Draw the internal grid and labels int linewidth = _cols * _colWidth; for (row = 0; row <= _rows; row++) s.hLine(_x, _y + (row * _rowHeight), _x + linewidth, kColor); int lineheight = _rows * _rowHeight; for (col = 0; col <= _cols; col++) s.vLine(_x + (col * _colWidth), _y, _y + lineheight, kColor); // Draw the pixels for (row = 0; row < _rows; row++) { for (col = 0; col < _cols; col++) { int x = _x + 4 + (col * _colWidth); int y = _y + 2 + (row * _rowHeight); int pos = row*_cols + col; // Draw the selected item inverted, on a highlighted background. if (_currentRow == row && _currentCol == col && _hasFocus) s.fillRect(x - 4, y - 2, _colWidth+1, _rowHeight+1, kTextColorHi); // Either draw the pixel in given color, or erase (show background) s.fillRect(x - 3, y - 1, _colWidth-1, _rowHeight-1, _stateList[pos] ? _pixelColor : _backgroundColor); if (_changedList[pos]) s.frameRect(x - 3, y - 1, _colWidth - 1, _rowHeight - 1, kDbgChangedColor); } } // Cross out the bits? if(_crossBits) { #ifndef FLAT_UI for(row = 1; row < 4; ++row) s.hLine(_x, _y + (row * lineheight / 4), _x + linewidth, kColor); #else for(col = 0; col < _cols; ++col) { int x = _x + col * _colWidth; s.line(x + 1, _y + 1, x + _colWidth - 1, _y + lineheight - 1, kColor); s.line(x + _colWidth - 1, _y + 1, x + 1, _y + lineheight - 1, kColor); } #endif } } stella-5.1.1/src/debugger/gui/TogglePixelWidget.hxx000066400000000000000000000036461324334165500223000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TOGGLE_PIXEL_WIDGET_HXX #define TOGGLE_PIXEL_WIDGET_HXX #include "ToggleWidget.hxx" /* TogglePixelWidget */ class TogglePixelWidget : public ToggleWidget { public: TogglePixelWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows); virtual ~TogglePixelWidget() = default; void setColor(int color) { _pixelColor = (color >= 0 && color <= kNumColors) ? color : kDlgColor; } void setBackgroundColor(int color) { _backgroundColor = (color >= 0 && color <= kNumColors) ? color : kDlgColor; } void setState(const BoolArray& state); void setIntState(int value, bool swap); int getIntState(); void setCrossed(bool enable) { _crossBits = enable; } private: int _pixelColor, _backgroundColor; bool _swapBits; bool _crossBits; private: void drawWidget(bool hilite) override; // Following constructors and assignment operators not supported TogglePixelWidget() = delete; TogglePixelWidget(const TogglePixelWidget&) = delete; TogglePixelWidget(TogglePixelWidget&&) = delete; TogglePixelWidget& operator=(const TogglePixelWidget&) = delete; TogglePixelWidget& operator=(TogglePixelWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/ToggleWidget.cxx000066400000000000000000000121441324334165500212620ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "StellaKeys.hxx" #include "Widget.hxx" #include "ToggleWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ToggleWidget::ToggleWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows, int clicksToChange) : Widget(boss, font, x, y, 16, 16), CommandSender(boss), _rows(rows), _cols(cols), _currentRow(0), _currentCol(0), _rowHeight(0), _colWidth(0), _selectedItem(0), _clicksToChange(clicksToChange), _editable(true) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS | WIDGET_WANTS_RAWDATA; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { if (!isEnabled()) return; // First check whether the selection changed int newSelectedItem; newSelectedItem = findItem(x, y); if (newSelectedItem > int(_stateList.size()) - 1) newSelectedItem = -1; if (_selectedItem != newSelectedItem) { _selectedItem = newSelectedItem; _currentRow = _selectedItem / _cols; _currentCol = _selectedItem - (_currentRow * _cols); setDirty(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { if (!isEnabled() || !_editable) return; // If this was a double click and the mouse is still over the selected item, // send the double click command if (clickCount == _clicksToChange && (_selectedItem == findItem(x, y))) { _stateList[_selectedItem] = !_stateList[_selectedItem]; _changedList[_selectedItem] = !_changedList[_selectedItem]; sendCommand(ToggleWidget::kItemDataChangedCmd, _selectedItem, _id); setDirty(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int ToggleWidget::findItem(int x, int y) { int row = (y - 1) / _rowHeight; if(row >= _rows) row = _rows - 1; int col = x / _colWidth; if(col >= _cols) col = _cols - 1; return row * _cols + col; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ToggleWidget::handleKeyDown(StellaKey key, StellaMod mod) { // Ignore all mod keys if(StellaModTest::isControl(mod) || StellaModTest::isAlt(mod)) return true; bool handled = true; bool dirty = false, toggle = false; switch(key) { case KBDK_RETURN: case KBDK_KP_ENTER: if (_currentRow >= 0 && _currentCol >= 0) { dirty = true; toggle = true; } break; case KBDK_UP: if (_currentRow > 0) { _currentRow--; dirty = true; } break; case KBDK_DOWN: if (_currentRow < int(_rows) - 1) { _currentRow++; dirty = true; } break; case KBDK_LEFT: if (_currentCol > 0) { _currentCol--; dirty = true; } break; case KBDK_RIGHT: if (_currentCol < int(_cols) - 1) { _currentCol++; dirty = true; } break; case KBDK_PAGEUP: if (_currentRow > 0) { _currentRow = 0; dirty = true; } break; case KBDK_PAGEDOWN: if (_currentRow < int(_rows) - 1) { _currentRow = _rows - 1; dirty = true; } break; case KBDK_HOME: if (_currentCol > 0) { _currentCol = 0; dirty = true; } break; case KBDK_END: if (_currentCol < int(_cols) - 1) { _currentCol = _cols - 1; dirty = true; } break; default: handled = false; } if (dirty) { _selectedItem = _currentRow*_cols + _currentCol; if(toggle && _editable) { _stateList[_selectedItem] = !_stateList[_selectedItem]; _changedList[_selectedItem] = !_changedList[_selectedItem]; sendCommand(ToggleWidget::kItemDataChangedCmd, _selectedItem, _id); } setDirty(); } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ToggleWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case GuiObject::kSetPositionCmd: if (_selectedItem != data) { _selectedItem = data; setDirty(); } break; } } stella-5.1.1/src/debugger/gui/ToggleWidget.hxx000066400000000000000000000051551324334165500212730ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TOGGLE_WIDGET_HXX #define TOGGLE_WIDGET_HXX #include "Widget.hxx" #include "Command.hxx" /* ToggleWidget */ class ToggleWidget : public Widget, public CommandSender { public: // Commands emitted by this commandsender enum { kItemDataChangedCmd = 'TWch', kSelectionChangedCmd = 'TWsc' }; public: ToggleWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int cols, int rows, int clicksToChange = 2); virtual ~ToggleWidget() = default; const BoolArray& getState() { return _stateList; } bool getSelectedState() const { return _stateList[_selectedItem]; } bool wantsFocus() const override { return true; } int colWidth() const { return _colWidth; } void setEditable(bool editable) { _editable = editable; } bool isEditable() const { return _editable; } protected: protected: int _rows; int _cols; int _currentRow; int _currentCol; int _rowHeight; // explicitly set in child classes int _colWidth; // explicitly set in child classes int _selectedItem; int _clicksToChange; // number of clicks to register a change bool _editable; BoolArray _stateList; BoolArray _changedList; private: void drawWidget(bool hilite) override = 0; int findItem(int x, int y); void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; bool handleKeyDown(StellaKey key, StellaMod mod) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; // Following constructors and assignment operators not supported ToggleWidget() = delete; ToggleWidget(const ToggleWidget&) = delete; ToggleWidget(ToggleWidget&&) = delete; ToggleWidget& operator=(const ToggleWidget&) = delete; ToggleWidget& operator=(ToggleWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/TrakBallWidget.cxx000066400000000000000000000021401324334165500215300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "TrakBallWidget.hxx" TrakBallWidget::TrakBallWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller) : PointingDeviceWidget(boss, font, x, y, controller) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TrakBallWidget::getGrayCodeTable(const int index, const int direction) { return myGrayCodeTable[(index & 0b1) + direction * 2]; } stella-5.1.1/src/debugger/gui/TrakBallWidget.hxx000066400000000000000000000027471324334165500215520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TRAKBALL_WIDGET_HXX #define TRAKBALL_WIDGET_HXX class Controller; #include "PointingDeviceWidget.hxx" class TrakBallWidget : public PointingDeviceWidget { public: TrakBallWidget(GuiObject* boss, const GUI::Font& font, int x, int y, Controller& controller); virtual ~TrakBallWidget() = default; private: uInt8 myGrayCodeTable[4] = { 0b00, 0b10, 0b01, 0b11 }; uInt8 getGrayCodeTable(const int index, const int direction) override; // Following constructors and assignment operators not supported TrakBallWidget() = delete; TrakBallWidget(const TrakBallWidget&) = delete; TrakBallWidget(TrakBallWidget&&) = delete; TrakBallWidget& operator=(const TrakBallWidget&) = delete; TrakBallWidget& operator=(TrakBallWidget&&) = delete; }; #endif stella-5.1.1/src/debugger/gui/module.mk000066400000000000000000000056171324334165500177760ustar00rootroot00000000000000MODULE := src/debugger/gui MODULE_OBJS := \ src/debugger/gui/AmigaMouseWidget.o \ src/debugger/gui/AtariMouseWidget.o \ src/debugger/gui/AtariVoxWidget.o \ src/debugger/gui/AudioWidget.o \ src/debugger/gui/BoosterWidget.o \ src/debugger/gui/Cart0840Widget.o \ src/debugger/gui/Cart2KWidget.o \ src/debugger/gui/Cart3EPlusWidget.o \ src/debugger/gui/Cart3EWidget.o \ src/debugger/gui/Cart3FWidget.o \ src/debugger/gui/Cart4A50Widget.o \ src/debugger/gui/Cart4KSCWidget.o \ src/debugger/gui/Cart4KWidget.o \ src/debugger/gui/CartARWidget.o \ src/debugger/gui/CartBFSCWidget.o \ src/debugger/gui/CartBFWidget.o \ src/debugger/gui/CartBUSWidget.o \ src/debugger/gui/CartCDFWidget.o \ src/debugger/gui/CartCMWidget.o \ src/debugger/gui/CartCTYWidget.o \ src/debugger/gui/CartCVPlusWidget.o \ src/debugger/gui/CartCVWidget.o \ src/debugger/gui/CartDASHWidget.o \ src/debugger/gui/CartDFSCWidget.o \ src/debugger/gui/CartDFWidget.o \ src/debugger/gui/CartDPCPlusWidget.o \ src/debugger/gui/CartDPCWidget.o \ src/debugger/gui/CartE0Widget.o \ src/debugger/gui/CartMNetworkWidget.o \ src/debugger/gui/CartE7Widget.o \ src/debugger/gui/CartE78KWidget.o \ src/debugger/gui/CartEFSCWidget.o \ src/debugger/gui/CartEFWidget.o \ src/debugger/gui/CartF0Widget.o \ src/debugger/gui/CartF4SCWidget.o \ src/debugger/gui/CartF4Widget.o \ src/debugger/gui/CartF6SCWidget.o \ src/debugger/gui/CartF6Widget.o \ src/debugger/gui/CartF8SCWidget.o \ src/debugger/gui/CartF8Widget.o \ src/debugger/gui/CartFA2Widget.o \ src/debugger/gui/CartFAWidget.o \ src/debugger/gui/CartFEWidget.o \ src/debugger/gui/CartMDMWidget.o \ src/debugger/gui/CartRamWidget.o \ src/debugger/gui/CartSBWidget.o \ src/debugger/gui/CartUAWidget.o \ src/debugger/gui/CartWDWidget.o \ src/debugger/gui/CartX07Widget.o \ src/debugger/gui/CartDebugWidget.o \ src/debugger/gui/CpuWidget.o \ src/debugger/gui/DataGridOpsWidget.o \ src/debugger/gui/DataGridWidget.o \ src/debugger/gui/DebuggerDialog.o \ src/debugger/gui/DelayQueueWidget.o \ src/debugger/gui/DrivingWidget.o \ src/debugger/gui/FlashWidget.o \ src/debugger/gui/GenesisWidget.o \ src/debugger/gui/JoystickWidget.o \ src/debugger/gui/KeyboardWidget.o \ src/debugger/gui/PaddleWidget.o \ src/debugger/gui/PointingDeviceWidget.o \ src/debugger/gui/PromptWidget.o \ src/debugger/gui/RamWidget.o \ src/debugger/gui/RiotRamWidget.o \ src/debugger/gui/RiotWidget.o \ src/debugger/gui/RomListSettings.o \ src/debugger/gui/RomListWidget.o \ src/debugger/gui/RomWidget.o \ src/debugger/gui/SaveKeyWidget.o \ src/debugger/gui/TiaInfoWidget.o \ src/debugger/gui/TiaOutputWidget.o \ src/debugger/gui/TiaWidget.o \ src/debugger/gui/TiaZoomWidget.o \ src/debugger/gui/ToggleBitWidget.o \ src/debugger/gui/TogglePixelWidget.o \ src/debugger/gui/ToggleWidget.o \ src/debugger/gui/TrakBallWidget.o MODULE_DIRS += \ src/debugger/gui # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/debugger/module.mk000066400000000000000000000005041324334165500172000ustar00rootroot00000000000000MODULE := src/debugger MODULE_OBJS := \ src/debugger/Debugger.o \ src/debugger/DebuggerParser.o \ src/debugger/CartDebug.o \ src/debugger/CpuDebug.o \ src/debugger/DiStella.o \ src/debugger/RiotDebug.o \ src/debugger/TIADebug.o MODULE_DIRS += \ src/debugger # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/emucore/000077500000000000000000000000001324334165500152365ustar00rootroot00000000000000stella-5.1.1/src/emucore/AmigaMouse.hxx000066400000000000000000000032311324334165500200150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef AMIGAMOUSE_HXX #define AMIGAMOUSE_HXX #include "PointingDevice.hxx" class AmigaMouse : public PointingDevice { public: /** Create a new Amiga Mouse controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ AmigaMouse(Jack jack, const Event& event, const System& system) : PointingDevice(jack, event, system, Controller::AmigaMouse, trackballSensitivity) { } virtual ~AmigaMouse() = default; protected: uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override { static constexpr uInt32 ourTableH[4] = { 0b0000, 0b1000, 0b1010, 0b0010 }; static constexpr uInt32 ourTableV[4] = { 0b0000, 0b0100, 0b0101, 0b0001 }; return ourTableH[countH] | ourTableV[countV]; } static constexpr float trackballSensitivity = 0.8f; }; #endif // AMIGAMOUSE_HXX stella-5.1.1/src/emucore/AtariMouse.hxx000066400000000000000000000032311324334165500200370ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ATARIMOUSE_HXX #define ATARIMOUSE_HXX #include "PointingDevice.hxx" class AtariMouse : public PointingDevice { public: /** Create a new Atari Mouse controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ AtariMouse(Jack jack, const Event& event, const System& system) : PointingDevice(jack, event, system, Controller::AtariMouse, trackballSensitivity) { } virtual ~AtariMouse() = default; protected: uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8, uInt8) override { static constexpr uInt32 ourTableH[4] = { 0b0000, 0b0001, 0b0011, 0b0010 }; static constexpr uInt32 ourTableV[4] = { 0b0000, 0b0100, 0b1100, 0b1000 }; return ourTableH[countH] | ourTableV[countV]; } static constexpr float trackballSensitivity = 0.8f; }; #endif // ATARIMOUSE_HXX stella-5.1.1/src/emucore/AtariVox.cxx000066400000000000000000000072631324334165500175270ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "SerialPort.hxx" #include "System.hxx" #include "AtariVox.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AtariVox::AtariVox(Jack jack, const Event& event, const System& system, const SerialPort& port, const string& portname, const string& eepromfile) : SaveKey(jack, event, system, eepromfile, Controller::AtariVox), mySerialPort(const_cast(port)), myShiftCount(0), myShiftRegister(0), myLastDataWriteCycle(0) { if(mySerialPort.openPort(portname)) myAboutString = " (using serial port \'" + portname + "\')"; else myAboutString = " (invalid serial port \'" + portname + "\')"; myDigitalPinState[Three] = myDigitalPinState[Four] = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool AtariVox::read(DigitalPin pin) { // We need to override the Controller::read() method, since the timing // of the actual read is important for the EEPROM (we can't just read // 60 times per second in the ::update() method) switch(pin) { // Pin 2: SpeakJet READY case Two: // For now, we just assume the device is always ready return myDigitalPinState[Two] = true; default: return SaveKey::read(pin); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariVox::write(DigitalPin pin, bool value) { // Change the pin state based on value switch(pin) { // Pin 1: SpeakJet DATA // output serial data to the speakjet case One: myDigitalPinState[One] = value; clockDataIn(value); break; default: SaveKey::write(pin, value); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariVox::clockDataIn(bool value) { if(value && (myShiftCount == 0)) return; // If this is the first write this frame, or if it's been a long time // since the last write, start a new data byte. uInt64 cycle = mySystem.cycles(); if((cycle < myLastDataWriteCycle) || (cycle > myLastDataWriteCycle + 1000)) { myShiftRegister = 0; myShiftCount = 0; } // If this is the first write this frame, or if it's been 62 cycles // since the last write, shift this bit into the current byte. if((cycle < myLastDataWriteCycle) || (cycle >= myLastDataWriteCycle + 62)) { myShiftRegister >>= 1; myShiftRegister |= (value << 15); if(++myShiftCount == 10) { myShiftCount = 0; myShiftRegister >>= 6; if(!(myShiftRegister & (1<<9))) cerr << "AtariVox: bad start bit" << endl; else if((myShiftRegister & 1)) cerr << "AtariVox: bad stop bit" << endl; else { uInt8 data = ((myShiftRegister >> 1) & 0xff); mySerialPort.writeByte(&data); } myShiftRegister = 0; } } myLastDataWriteCycle = cycle; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AtariVox::reset() { myLastDataWriteCycle = 0; SaveKey::reset(); } stella-5.1.1/src/emucore/AtariVox.hxx000066400000000000000000000075471324334165500175410ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ATARIVOX_HXX #define ATARIVOX_HXX class SerialPort; #include "Control.hxx" #include "SaveKey.hxx" /** Richard Hutchinson's AtariVox "controller": A speech synthesizer and storage device. This code owes a great debt to Alex Herbert's AtariVox documentation and driver code. @author B. Watson */ class AtariVox : public SaveKey { public: /** Create a new AtariVox controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller @param port The serial port object @param portname Name of the port used for reading and writing @param eepromfile The file containing the EEPROM data */ AtariVox(Jack jack, const Event& event, const System& system, const SerialPort& port, const string& portname, const string& eepromfile); virtual ~AtariVox() = default; public: using Controller::read; /** Read the value of the specified digital pin for this controller. @param pin The pin of the controller jack to read @return The state of the pin */ bool read(DigitalPin pin) override; /** Write the given value to the specified digital pin for this controller. Writing is only allowed to the pins associated with the PIA. Therefore you cannot write to pin six. @param pin The pin of the controller jack to write to @param value The value to write to the pin */ void write(DigitalPin pin, bool value) override; /** Update the entire digital and analog pin state according to the events currently set. */ void update() override { } /** Notification method invoked by the system after its reset method has been called. It may be necessary to override this method for controllers that need to know a reset has occurred. */ void reset() override; string about(bool swappedPorts) const override { return Controller::about(swappedPorts) + myAboutString; } private: void clockDataIn(bool value); private: // Instance of an real serial port on the system // Assuming there's a real AtariVox attached, we can send SpeakJet // bytes directly to it SerialPort& mySerialPort; // How many bits have been shifted into the shift register? uInt8 myShiftCount; // Shift register. Data comes in serially: // 1 start bit, always 0 // 8 data bits, LSB first // 1 stop bit, always 1 uInt16 myShiftRegister; // When did the last data write start, in CPU cycles? // The real SpeakJet chip reads data at 19200 bits/sec. Alex's // driver code sends data at 62 CPU cycles per bit, which is // "close enough". uInt64 myLastDataWriteCycle; // Holds information concerning serial port usage string myAboutString; private: // Following constructors and assignment operators not supported AtariVox() = delete; AtariVox(const AtariVox&) = delete; AtariVox(AtariVox&&) = delete; AtariVox& operator=(const AtariVox&) = delete; AtariVox& operator=(AtariVox&&) = delete; }; #endif stella-5.1.1/src/emucore/BSType.hxx000066400000000000000000000114271324334165500171420ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef BSTYPE_HXX #define BSTYPE_HXX #include "bspf.hxx" // Currently supported bankswitch schemes enum class BSType { _AUTO, _0840, _2IN1, _4IN1, _8IN1, _16IN1, _32IN1, _64IN1, _128IN1, _2K, _3E, _3EP, _3F, _4A50, _4K, _4KSC, _AR, _BF, _BFSC, _BUS, _CDF, _CM, _CTY, _CV, _CVP, _DASH, _DF, _DFSC, _DPC, _DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0, _F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA, _FA2, _FE, _MDM, _SB, _UA, _WD, _X07, #ifdef CUSTOM_ARM _CUSTOM, #endif NumSchemes }; // Info about the various bankswitch schemes, useful for displaying // in GUI dropdown boxes, etc struct BSDescription { const char* const name; const char* const desc; }; static BSDescription BSList[int(BSType::NumSchemes)] = { { "AUTO", "Auto-detect" }, { "0840", "0840 (8K ECONObank)" }, { "2IN1", "2IN1 Multicart (4-32K)" }, { "4IN1", "4IN1 Multicart (8-32K)" }, { "8IN1", "8IN1 Multicart (16-64K)" }, { "16IN1", "16IN1 Multicart (32-128K)" }, { "32IN1", "32IN1 Multicart (64/128K)" }, { "64IN1", "64IN1 Multicart (128/256K)" }, { "128IN1", "128IN1 Multicart (256/512K)" }, { "2K", "2K (64-2048 bytes Atari)" }, { "3E", "3E (32K Tigervision)" }, { "3E+", "3E+ (TJ modified DASH)" }, { "3F", "3F (512K Tigervision)" }, { "4A50", "4A50 (64K 4A50 + ram)" }, { "4K", "4K (4K Atari)" }, { "4KSC", "4KSC (CPUWIZ 4K + ram)" }, { "AR", "AR (Supercharger)" }, { "BF", "BF (CPUWIZ 256K)" }, { "BFSC", "BFSC (CPUWIZ 256K + ram)" }, { "BUS", "BUS (Experimental)" }, { "CDF", "CDF (Chris, Darrell, Fred)" }, { "CM", "CM (SpectraVideo CompuMate)" }, { "CTY", "CTY (CDW - Chetiry)" }, { "CV", "CV (Commavid extra ram)" }, { "CV+", "CV+ (Extended Commavid)" }, { "DASH", "DASH (Experimental)" }, { "DF", "DF (CPUWIZ 128K)" }, { "DFSC", "DFSC (CPUWIZ 128K + ram)" }, { "DPC", "DPC (Pitfall II)" }, { "DPC+", "DPC+ (Enhanced DPC)" }, { "E0", "E0 (8K Parker Bros)" }, { "E7", "E7 (16K M-network)" }, { "E78K", "E78K (8K M-network)" }, { "EF", "EF (64K H. Runner)" }, { "EFSC", "EFSC (64K H. Runner + ram)" }, { "F0", "F0 (Dynacom Megaboy)" }, { "F4", "F4 (32K Atari)" }, { "F4SC", "F4SC (32K Atari + ram)" }, { "F6", "F6 (16K Atari)" }, { "F6SC", "F6SC (16K Atari + ram)" }, { "F8", "F8 (8K Atari)" }, { "F8SC", "F8SC (8K Atari + ram)" }, { "FA", "FA (CBS RAM Plus)" }, { "FA2", "FA2 (CBS RAM Plus 24/28K)" }, { "FE", "FE (8K Decathlon)" }, { "MDM", "MDM (Menu Driven Megacart)" }, { "SB", "SB (128-256K SUPERbank)" }, { "UA", "UA (8K UA Ltd.)" }, { "WD", "WD (Experimental)" }, { "X07", "X07 (64K AtariAge)" }, #ifdef CUSTOM_ARM { "CUSTOM", "CUSTOM (ARM)" } #endif }; class Bankswitch { public: // Convert BSType enum to string static string typeToName(BSType type) { return BSList[int(type)].name; } // Convert string to BSType enum static BSType nameToType(const string& name) { for(int i = 0; i < int(BSType::NumSchemes); ++i) if(BSPF::equalsIgnoreCase(BSList[i].name, name)) return BSType(i); return BSType::_AUTO; } private: // Following constructors and assignment operators not supported Bankswitch() = delete; Bankswitch(const Bankswitch&) = delete; Bankswitch(Bankswitch&&) = delete; Bankswitch& operator=(const Bankswitch&) = delete; Bankswitch& operator=(Bankswitch&&) = delete; }; #endif stella-5.1.1/src/emucore/Booster.cxx000066400000000000000000000115711324334165500174040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Event.hxx" #include "Booster.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BoosterGrip::BoosterGrip(Jack jack, const Event& event, const System& system) : Controller(jack, event, system, Controller::BoosterGrip), myControlID(-1) { if(myJack == Left) { myUpEvent = Event::JoystickZeroUp; myDownEvent = Event::JoystickZeroDown; myLeftEvent = Event::JoystickZeroLeft; myRightEvent = Event::JoystickZeroRight; myFireEvent = Event::JoystickZeroFire; myTriggerEvent = Event::JoystickZeroFire5; myBoosterEvent = Event::JoystickZeroFire9; myXAxisValue = Event::SALeftAxis0Value; myYAxisValue = Event::SALeftAxis1Value; } else { myUpEvent = Event::JoystickOneUp; myDownEvent = Event::JoystickOneDown; myLeftEvent = Event::JoystickOneLeft; myRightEvent = Event::JoystickOneRight; myFireEvent = Event::JoystickOneFire; myTriggerEvent = Event::JoystickOneFire5; myBoosterEvent = Event::JoystickOneFire9; myXAxisValue = Event::SARightAxis0Value; myYAxisValue = Event::SARightAxis1Value; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BoosterGrip::update() { // Digital events (from keyboard or joystick hats & buttons) myDigitalPinState[One] = (myEvent.get(myUpEvent) == 0); myDigitalPinState[Two] = (myEvent.get(myDownEvent) == 0); myDigitalPinState[Three] = (myEvent.get(myLeftEvent) == 0); myDigitalPinState[Four] = (myEvent.get(myRightEvent) == 0); myDigitalPinState[Six] = (myEvent.get(myFireEvent) == 0); // The CBS Booster-grip has two more buttons on it. These buttons are // connected to the inputs usually used by paddles. updateAnalogPin( Five, (myEvent.get(myTriggerEvent) != 0) ? minimumResistance : maximumResistance ); updateAnalogPin( Nine, (myEvent.get(myBoosterEvent) != 0) ? minimumResistance : maximumResistance ); // Axis events (usually generated by the Stelladaptor) int xaxis = myEvent.get(myXAxisValue); int yaxis = myEvent.get(myYAxisValue); if(xaxis > 16384-4096) { myDigitalPinState[Four] = false; // Stelladaptor sends "half moved right" for L+R pushed together if(xaxis < 16384+4096) myDigitalPinState[Three] = false; } else if(xaxis < -16384) myDigitalPinState[Three] = false; if(yaxis > 16384-4096) { myDigitalPinState[Two] = false; // Stelladaptor sends "half moved down" for U+D pushed together if(yaxis < 16384+4096) myDigitalPinState[One] = false; } else if(yaxis < -16384) myDigitalPinState[One] = false; // Mouse motion and button events if(myControlID > -1) { // The following code was taken from z26 #define MJ_Threshold 2 int mousex = myEvent.get(Event::MouseAxisXValue), mousey = myEvent.get(Event::MouseAxisYValue); if(mousex || mousey) { if((!(abs(mousey) > abs(mousex) << 1)) && (abs(mousex) >= MJ_Threshold)) { if(mousex < 0) myDigitalPinState[Three] = false; else if (mousex > 0) myDigitalPinState[Four] = false; } if((!(abs(mousex) > abs(mousey) << 1)) && (abs(mousey) >= MJ_Threshold)) { if(mousey < 0) myDigitalPinState[One] = false; else if(mousey > 0) myDigitalPinState[Two] = false; } } // Get mouse button state if(myEvent.get(Event::MouseButtonLeftValue)) myDigitalPinState[Six] = false; if(myEvent.get(Event::MouseButtonRightValue)) updateAnalogPin(Nine, minimumResistance); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool BoosterGrip::setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { // Currently, the booster-grip takes full control of the mouse, using both // axes for its two degrees of movement, and the left/right buttons for // fire and booster, respectively if(xtype == Controller::BoosterGrip && ytype == Controller::BoosterGrip && xid == yid) { myControlID = ((myJack == Left && xid == 0) || (myJack == Right && xid == 1) ) ? xid : -1; } else myControlID = -1; return true; } stella-5.1.1/src/emucore/Booster.hxx000066400000000000000000000060431324334165500174070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef BOOSTERGRIP_HXX #define BOOSTERGRIP_HXX #include "Control.hxx" #include "Event.hxx" /** The standard Atari 2600 joystick controller fitted with the CBS Booster grip. The Booster grip has two more fire buttons on it (a booster and a trigger). @author Bradford W. Mott */ class BoosterGrip : public Controller { public: /** Create a new booster grip joystick plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ BoosterGrip(Jack jack, const Event& event, const System& system); virtual ~BoosterGrip() = default; public: /** Update the entire digital and analog pin state according to the events currently set. */ void update() override; /** Determines how this controller will treat values received from the X/Y axis and left/right buttons of the mouse. Since not all controllers use the mouse the same way (or at all), it's up to the specific class to decide how to use this data. In the current implementation, the left button is tied to the X axis, and the right one tied to the Y axis. @param xtype The controller to use for x-axis data @param xid The controller ID to use for x-axis data (-1 for no id) @param ytype The controller to use for y-axis data @param yid The controller ID to use for y-axis data (-1 for no id) @return Whether the controller supports using the mouse */ bool setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; private: // Pre-compute the events we care about based on given port // This will eliminate test for left or right port in update() Event::Type myUpEvent, myDownEvent, myLeftEvent, myRightEvent, myFireEvent, myBoosterEvent, myTriggerEvent, myXAxisValue, myYAxisValue; // Controller to emulate in normal mouse axis mode int myControlID; private: // Following constructors and assignment operators not supported BoosterGrip() = delete; BoosterGrip(const BoosterGrip&) = delete; BoosterGrip(BoosterGrip&&) = delete; BoosterGrip& operator=(const BoosterGrip&) = delete; BoosterGrip& operator=(BoosterGrip&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart.cxx000066400000000000000000000066151324334165500166630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Settings.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #include "CartDebug.hxx" #endif #include "Cart.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge::Cartridge(const Settings& settings) : mySettings(settings), myStartBank(0), myBankChanged(true), myCodeAccessBase(nullptr), myBankLocked(false) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::setAbout(const string& about, const string& type, const string& id) { myAbout = about; myDetectedType = type; myMultiCartID = id; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::saveROM(ofstream& out) const { uInt32 size = 0; const uInt8* image = getImage(size); if(image == nullptr || size == 0) { cerr << "save not supported" << endl; return false; } out.write(reinterpret_cast(image), size); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::bankChanged() { bool changed = myBankChanged; myBankChanged = false; return changed; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::triggerReadFromWritePort(uInt16 address) { #ifdef DEBUGGER_SUPPORT if(!mySystem->autodetectMode()) Debugger::debugger().cartDebug().triggerReadFromWritePort(address); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::createCodeAccessBase(uInt32 size) { #ifdef DEBUGGER_SUPPORT myCodeAccessBase = make_unique(size); memset(myCodeAccessBase.get(), CartDebug::ROW, size); #else myCodeAccessBase = nullptr; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::initializeRAM(uInt8* arr, uInt32 size, uInt8 val) const { if(randomInitialRAM()) for(uInt32 i = 0; i < size; ++i) arr[i] = mySystem->randGenerator().next(); else memset(arr, val, size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::randomInitialRAM() const { return mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.ramrandom" : "plr.ramrandom"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge::randomizeStartBank() { if(randomStartBank()) myStartBank = mySystem->randGenerator().next() % bankCount(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge::randomStartBank() const { return mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.bankrandom" : "plr.bankrandom"); } stella-5.1.1/src/emucore/Cart.hxx000066400000000000000000000206601324334165500166640ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_HXX #define CARTRIDGE_HXX class Cartridge; class Properties; class CartDebugWidget; class CartRamWidget; class GuiObject; #include "bspf.hxx" #include "Device.hxx" #include "Settings.hxx" #include "Font.hxx" /** A cartridge is a device which contains the machine code for a game and handles any bankswitching performed by the cartridge. A 'bank' is defined as a 4K block that is visible in the 0x1000-0x2000 area (or its mirrors). @author Bradford W. Mott */ class Cartridge : public Device { public: /** Create a new cartridge @param settings A reference to the various settings (read-only) */ Cartridge(const Settings& settings); virtual ~Cartridge() = default; /** Set/query some information about this cartridge. */ void setAbout(const string& about, const string& type, const string& id); const string& about() const { return myAbout; } const string& detectedType() const { return myDetectedType; } const string& multiCartID() const { return myMultiCartID; } /** Save the internal (patched) ROM image. @param out The output file stream to save the image */ bool saveROM(ofstream& out) const; /** Lock/unlock bankswitching capability. The debugger will lock the banks before querying the cart state, otherwise reading values could inadvertantly cause a bankswitch to occur. */ void lockBank() { myBankLocked = true; } void unlockBank() { myBankLocked = false; } bool bankLocked() const { return myBankLocked; } /** Get the default startup bank for a cart. This is the bank where the system will look at address 0xFFFC to determine where to start running code. @return The startup bank */ uInt16 startBank() const { return myStartBank; } /** Answer whether the bank has changed since the last time this method was called. Each cart class is able to override this method to deal with its specific functionality. In those cases, the derived class is still responsible for calling this base function. @return Whether the bank was changed */ virtual bool bankChanged(); public: ////////////////////////////////////////////////////////////////////// // The following methods are cart-specific and will usually be // implemented in derived classes. Carts which don't support // bankswitching (for any reason) do not have to provide an // implementation for bankswitch-related methods. ////////////////////////////////////////////////////////////////////// /** Set the specified bank. This is used only when the bankswitching scheme defines banks in a standard format (ie, 0 for first bank, 1 for second, etc). Carts which will handle their own bankswitching completely or non-bankswitched carts can ignore this method. */ virtual bool bank(uInt16) { return false; } /** Get the current bank. Carts which have only one bank (either real or virtual) always report that bank as zero. */ virtual uInt16 getBank() const { return 0; } /** Query the number of 'banks' supported by the cartridge. Note that this information is cart-specific, where each cart basically defines what a 'bank' is. For the normal Atari-manufactured carts, a standard bank is a 4K block that is directly accessible in the 4K address space. In other cases where ROMs have 2K blocks in some preset area, the bankCount is the number of such blocks. Finally, in some esoteric schemes, the number of ways that the addressing can change (multiple ROM and RAM slices at multiple access points) is so complicated that the cart will report having only one 'virtual' bank. */ virtual uInt16 bankCount() const { return 1; } /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ virtual bool patch(uInt16 address, uInt8 value) = 0; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ virtual const uInt8* getImage(uInt32& size) const = 0; /** Informs the cartridge about the name of the ROM file used when creating this cart. @param name The properties file name of the ROM */ virtual void setRomName(const string& name) { } /** Thumbulator only supports 16-bit ARM code. Some Harmony/Melody drivers, such as BUS and CDF, feature 32-bit ARM code subroutines. This is used to pass values back to the cartridge class to emulate those subroutines. */ virtual uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) { return 0; } /** Get debugger widget responsible for accessing the inner workings of the cart. This will need to be overridden and implemented by each specific cart type, since the bankswitching/inner workings of each cart type can be very different from each other. */ virtual CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) { return nullptr; } protected: /** Indicate that an illegal read from a write port has occurred. @param address The address of the illegal read */ void triggerReadFromWritePort(uInt16 address); /** Create an array that holds code-access information for every byte of the ROM (indicated by 'size'). Note that this is only used by the debugger, and is unavailable otherwise. @param size The size of the code-access array to create */ void createCodeAccessBase(uInt32 size); /** Fill the given RAM array with (possibly random) data. @param arr Pointer to the RAM array @param size The size of the RAM array @param val If provided, the value to store in the RAM array */ void initializeRAM(uInt8* arr, uInt32 size, uInt8 val = 0) const; /** Checks if initial RAM randomization is enabled @return Whether the initial RAM should be randomized */ bool randomInitialRAM() const; /** Defines the startup bank. if 'bank' is negative, a random bank will be selected. */ void randomizeStartBank(); /** Checks if startup bank randomization is enabled @return Whether the startup bank(s) should be randomized */ bool randomStartBank() const; protected: // Settings class for the application const Settings& mySettings; // The startup bank to use (where to look for the reset vector address) uInt16 myStartBank; // Indicates if the bank has changed somehow (a bankswitch has occurred) bool myBankChanged; // The array containing information about every byte of ROM indicating // whether it is used as code. BytePtr myCodeAccessBase; private: // If myBankLocked is true, ignore attempts at bankswitching. This is used // by the debugger, when disassembling/dumping ROM. bool myBankLocked; // Contains various info about this cartridge // This needs to be stored separately from child classes, since // sometimes the information in both do not match // (ie, detected type could be '2in1' while name of cart is '4K') string myAbout, myDetectedType, myMultiCartID; // Following constructors and assignment operators not supported Cartridge() = delete; Cartridge(const Cartridge&) = delete; Cartridge(Cartridge&&) = delete; Cartridge& operator=(const Cartridge&) = delete; Cartridge& operator=(Cartridge&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart0840.cxx000066400000000000000000000133061324334165500171720ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "Cart0840.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge0840::Cartridge0840(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(8192u, size)); createCodeAccessBase(8192); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge0840::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge0840::install(System& system) { mySystem = &system; // Get the page accessing methods for the hot spots since they overlap // areas within the TIA we'll need to forward requests to the TIA myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800); myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900); myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00); myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00); myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00); myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00); myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00); myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00); // Set the page accessing methods for the hot spots System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x0800; addr < 0x0FFF; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Install pages for bank 0 bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge0840::peek(uInt16 address) { address &= 0x1840; // Switch banks if necessary switch(address) { case 0x0800: // Set the current bank to the lower 4k bank bank(0); break; case 0x0840: // Set the current bank to the upper 4k bank bank(1); break; default: break; } // Because of the way we've set up accessing above, we can only // get here when the addresses are from 0x800 - 0xFFF int hotspot = ((address & 0x0F00) >> 8) - 8; return myHotSpotPageAccess[hotspot].device->peek(address); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::poke(uInt16 address, uInt8 value) { address &= 0x1840; // Switch banks if necessary switch(address) { case 0x0800: // Set the current bank to the lower 4k bank bank(0); break; case 0x0840: // Set the current bank to the upper 4k bank bank(1); break; default: break; } // Because of the way accessing is set up, we will may get here by // doing a write to 0x800 - 0xFFF or cart; we ignore the cart write if(!(address & 0x1000)) { int hotspot = ((address & 0x0F00) >> 8) - 8; myHotSpotPageAccess[hotspot].device->poke(address, value); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge0840::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge0840::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0fff)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge0840::getImage(uInt32& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); } catch(...) { cerr << "ERROR: Cartridge0840::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge0840::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); } catch(...) { cerr << "ERROR: Cartridge0840::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset); return true; } stella-5.1.1/src/emucore/Cart0840.hxx000066400000000000000000000113521324334165500171760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE0840_HXX #define CARTRIDGE0840_HXX #include "bspf.hxx" #include "Cart.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart0840Widget.hxx" #endif /** Cartridge class used for 0840 "Econobanking" 8K bankswitched games. There are two 4K banks, which are switched by accessing $0800 (bank 0) and $0840 (bank 1). @author Fred X. Quimby */ class Cartridge0840 : public Cartridge { friend class Cartridge0840Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ Cartridge0840(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~Cartridge0840() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Cartridge0840"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new Cartridge0840Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 8K ROM image of the cartridge uInt8 myImage[8192]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; // Previous Device's page access System::PageAccess myHotSpotPageAccess[8]; private: // Following constructors and assignment operators not supported Cartridge0840() = delete; Cartridge0840(const Cartridge0840&) = delete; Cartridge0840(Cartridge0840&&) = delete; Cartridge0840& operator=(const Cartridge0840&) = delete; Cartridge0840& operator=(Cartridge0840&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart2K.cxx000066400000000000000000000064261324334165500170600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "Cart2K.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge2K::Cartridge2K(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Size can be a maximum of 2K if(size > 2048) size = 2048; // Set image size to closest power-of-two for the given size mySize = 1; while(mySize < size) mySize <<= 1; // We can't use a size smaller than the minimum page size in Stella mySize = std::max(mySize, System::PAGE_SIZE); // Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam myImage = make_unique(mySize); memset(myImage.get(), 0x02, mySize); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), size); createCodeAccessBase(mySize); // Set mask for accessing the image buffer // This is guaranteed to work, as mySize is a power of two myMask = mySize - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge2K::reset() { myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge2K::install(System& system) { mySystem = &system; // Map ROM image into the system // Note that we don't need our own peek/poke methods, since the mapping // takes care of the entire address space System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[addr & myMask]; access.codeAccessBase = &myCodeAccessBase[addr & myMask]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge2K::patch(uInt16 address, uInt8 value) { myImage[address & myMask] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge2K::getImage(uInt32& size) const { size = mySize; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge2K::save(Serializer& out) const { try { out.putString(name()); } catch(...) { cerr << "ERROR: Cartridge2K::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge2K::load(Serializer& in) { try { if(in.getString() != name()) return false; } catch(...) { cerr << "ERROR: Cartridge2K::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/Cart2K.hxx000066400000000000000000000077041324334165500170650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE2K_HXX #define CARTRIDGE2K_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart2KWidget.hxx" #endif /** This is the standard Atari 2K cartridge. These cartridges are not bankswitched, however, the data repeats twice in the 2600's 4K cartridge addressing space. For 'Sub2K' ROMs (ROMs less than 2K in size), the data repeats in intervals based on the size of the ROM (which will always be a power of 2). @author Stephen Anthony */ class Cartridge2K : public Cartridge { friend class Cartridge2KWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image (<= 2048 bytes) @param settings A reference to the various settings (read-only) */ Cartridge2K(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~Cartridge2K() = default; public: /** Reset cartridge to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Cartridge2K"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new Cartridge2KWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif private: // Pointer to a dynamically allocated ROM image of the cartridge BytePtr myImage; // Size of the ROM image uInt32 mySize; // Mask to use for mirroring uInt32 myMask; private: // Following constructors and assignment operators not supported Cartridge2K() = delete; Cartridge2K(const Cartridge2K&) = delete; Cartridge2K(Cartridge2K&&) = delete; Cartridge2K& operator=(const Cartridge2K&) = delete; Cartridge2K& operator=(Cartridge2K&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart3E.cxx000066400000000000000000000166671324334165500170630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "TIA.hxx" #include "Cart3E.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3E::Cartridge3E(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), myCurrentBank(0) { // Allocate array for the ROM image myImage = make_unique(mySize); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), mySize); createCodeAccessBase(mySize + 32768); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3E::reset() { initializeRAM(myRAM, 32768); // We'll map the startup bank into the first segment upon reset bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3E::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READWRITE); // The hotspots ($3E and $3F) are in TIA address space, so we claim it here for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Setup the second segment to always point to the last ROM slice access.type = System::PA_READ; for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank into the first segment bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge3E::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; if(address < 0x0800) { if(myCurrentBank < 256) return myImage[(address & 0x07FF) + (myCurrentBank << 11)]; else { if(address < 0x0400) return myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)]; else { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value; } } } } else { return myImage[(address & 0x07FF) + mySize - 2048]; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3E::poke(uInt16 address, uInt8 value) { address &= 0x0FFF; // Switch banks if necessary. Armin (Kroko) says there are no mirrored // hotspots. if(address == 0x003F) { bank(value); } else if(address == 0x003E) { bank(value + 256); } // Handle TIA space that we claimed above mySystem->tia().poke(address, value); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3E::bank(uInt16 bank) { if(bankLocked()) return false; if(bank < 256) { // Make sure the bank they're asking for is reasonable if((uInt32(bank) << 11) < mySize) { myCurrentBank = bank; } else { // Oops, the bank they're asking for isn't valid so let's wrap it // around to a valid bank number myCurrentBank = bank % (mySize >> 11); } uInt32 offset = myCurrentBank << 11; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } } else { bank -= 256; bank %= 32; myCurrentBank = bank + 256; uInt32 offset = bank << 10; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map read-port RAM image into the system for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[offset + (addr & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } access.directPeekBase = nullptr; access.type = System::PA_WRITE; // Map write-port RAM image into the system for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[offset + (addr & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[mySize + offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge3E::getBank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge3E::bankCount() const { // Because the RAM banks always start at 256 and above, we require the // number of ROM banks to be 256 // If the RAM banks were simply appended to the number of actual // ROM banks, bank numbers would be ambiguous (ie, would bank 128 be // the last bank of ROM, or one of the banks of RAM?) return 256 + 32; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3E::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0800) { if(myCurrentBank < 256) myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value; else myRAM[(address & 0x03FF) + ((myCurrentBank - 256) << 10)] = value; } else myImage[(address & 0x07FF) + mySize - 2048] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge3E::getImage(uInt32& size) const { size = mySize; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3E::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); out.putByteArray(myRAM, 32768); } catch(...) { cerr << "ERROR: Cartridge3E::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3E::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 32768); } catch(...) { cerr << "ERROR: Cartridge3E::load" << endl; return false; } // Now, go to the current bank bank(myCurrentBank); return true; } stella-5.1.1/src/emucore/Cart3E.hxx000066400000000000000000000142321324334165500170520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE3E_HXX #define CARTRIDGE3E_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart3EWidget.hxx" #endif /** This is the cartridge class for Tigervision's bankswitched games with RAM (basically, 3F plus up to 32K of RAM). This code is basically Brad's Cart3F code plus 32K RAM support. In this bankswitching scheme the 2600's 4K cartridge address space is broken into two 2K segments. The last 2K segment always points to the last 2K of the ROM image. The lower 2K of address space maps to either one of the 2K ROM banks (up to 256 of them, though only 240 are supposed to be used for compatibility with the Kroko Cart and Cuttle Cart 2), or else one of the 1K RAM banks (up to 32 of them). Like other carts with RAM, this takes up twice the address space that it should: The lower 1K is the read port, and the upper 1K is the write port (maps to the same memory). To map ROM, the desired bank number of the first 2K segment is selected by storing its value into $3F. To map RAM in the first 2K segment instead, store the RAM bank number into $3E. This implementation of 3E bankswitching numbers the ROM banks 0 to 255, and the RAM banks 256 to 287. This is done because the public bankswitching interface requires us to use one bank number, not one bank number plus the knowledge of whether it's RAM or ROM. All 32K of potential RAM is available to a game using this class, even though real cartridges might not have the full 32K: We have no way to tell how much RAM the game expects. This may change in the future (we may add a stella.pro property for this), but for now it shouldn't cause any problems. (Famous last words...) @author B. Watson */ class Cartridge3E : public Cartridge { friend class Cartridge3EWidget; public: /** Create a new cartridge using the specified image and size @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ Cartridge3E(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~Cartridge3E() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Cartridge3E"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new Cartridge3EWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // Pointer to a dynamically allocated ROM image of the cartridge BytePtr myImage; // RAM contents. For now every ROM gets all 32K of potential RAM uInt8 myRAM[32 * 1024]; // Size of the ROM image uInt32 mySize; // Indicates which bank is currently active for the first segment uInt16 myCurrentBank; private: // Following constructors and assignment operators not supported Cartridge3E() = delete; Cartridge3E(const Cartridge3E&) = delete; Cartridge3E(Cartridge3E&&) = delete; Cartridge3E& operator=(const Cartridge3E&) = delete; Cartridge3E& operator=(Cartridge3E&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart3EPlus.cxx000066400000000000000000000257451324334165500177240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "TIA.hxx" #include "Cart3EPlus.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3EPlus::Cartridge3EPlus(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size) { // Allocate array for the ROM image myImage = make_unique(mySize); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), mySize); createCodeAccessBase(mySize + RAM_TOTAL_SIZE); // Remember startup bank (0 per spec, rather than last per 3E scheme). // Set this to go to 3rd 1K Bank. myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::reset() { initializeRAM(myRAM, RAM_TOTAL_SIZE); // Initialise bank values for all ROM/RAM access // This is used to reverse-lookup from address to bank location for(uInt32 b = 0; b < 8; ++b) bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible! initializeBankState(); // We'll map the startup banks 0 and 3 from the image into the third 1K bank upon reset bankROM((0 << BANK_BITS) | 0); bankROM((3 << BANK_BITS) | 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READWRITE); // The hotspots are in TIA address space, so we claim it here for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Initialise bank values for all ROM/RAM access // This is used to reverse-lookup from address to bank location for(uInt32 b = 0; b < 8; ++b) bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible! initializeBankState(); // Setup the last segment (of 4, each 1K) to point to the first ROM slice // Actually we DO NOT want "always". It's just on bootup, and can be out switched later bankROM((0 << BANK_BITS) | 0); bankROM((3 << BANK_BITS) | 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge3EPlus::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // restrict to 4K address range uInt8 value = 0; uInt32 bank = (address >> (ROM_BANK_TO_POWER - 1)) & 7; // convert to 512 byte bank index (0-7) uInt16 imageBank = bankInUse[bank]; // the ROM/RAM bank that's here if(imageBank == BANK_UNDEFINED) // an uninitialised bank? { // accessing invalid bank, so return should be... random? value = mySystem->randGenerator().next(); } else if(imageBank & BITMASK_ROMRAM) // a RAM bank { // Reading from the write port triggers an unwanted write value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM offset += (address & BITMASK_RAM_BANK); // + byte offset in RAM bank return myRAM[offset] = value; } } return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3EPlus::poke(uInt16 address, uInt8 value) { bool changed = false; // Check for write to the bank switch address. RAM/ROM and bank # are encoded in 'value' // There are NO mirrored hotspots. if(address == BANK_SWITCH_HOTSPOT_RAM) changed = bankRAM(value); else if(address == BANK_SWITCH_HOTSPOT_ROM) changed = bankROM(value); // Handle TIA space that we claimed above mySystem->tia().poke(address, value); return changed; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3EPlus::bankRAM(uInt8 bank) { if(bankLocked()) // debugger can lock RAM return false; //cerr << "bankRAM " << int(bank) << endl; // Each RAM bank uses two slots, separated by 0x200 in memory -- one read, one write. bankRAMSlot(bank | BITMASK_ROMRAM | 0); bankRAMSlot(bank | BITMASK_ROMRAM | BITMASK_LOWERUPPER); return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::bankRAMSlot(uInt16 bank) { uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) to 512 byte block uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range bool upper = bank & BITMASK_LOWERUPPER; // is this the read or write port uInt32 startCurrentBank = currentBank << RAM_BANK_TO_POWER; // Effectively * 512 bytes //cerr << "raw bank=" << std::dec << currentBank << endl // << "startCurrentBank=$" << std::hex << startCurrentBank << endl; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); if(upper) // We're mapping the write port { bankInUse[bankNumber * 2 + 1] = Int16(bank); access.type = System::PA_WRITE; } else // We're mapping the read port { bankInUse[bankNumber * 2] = Int16(bank); access.type = System::PA_READ; } uInt16 start = 0x1000 + (bankNumber << (RAM_BANK_TO_POWER+1)) + (upper ? RAM_WRITE_OFFSET : 0); uInt16 end = start + RAM_BANK_SIZE - 1; //cerr << "bank RAM: " << bankNumber << " -> " << (bankNumber * 2 + (upper ? 1 : 0)) << (upper ? " (W)" : " (R)") << endl // << "start=" << std::hex << start << ", end=" << end << endl << endl; for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) { if(upper) access.directPokeBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; else access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3EPlus::bankROM(uInt8 bank) { if(bankLocked()) // debugger can lock ROM return false; // Map ROM bank image into the system into the correct slot // Memory map is 1K slots at 0x1000, 0x1400, 0x1800, 0x1C00 // Each ROM uses 2 consecutive 512 byte slots bankROMSlot(bank | 0); bankROMSlot(bank | BITMASK_LOWERUPPER); return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::bankROMSlot(uInt16 bank) { uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range bool upper = bank & BITMASK_LOWERUPPER; // is this the lower or upper 512b bankInUse[bankNumber * 2 + (upper ? 1 : 0)] = Int16(bank); // Record which bank switched in (as ROM) uInt32 startCurrentBank = currentBank << ROM_BANK_TO_POWER; // Effectively *1K // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); uInt16 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0); uInt16 end = start + ROM_BANK_SIZE / 2 - 1; for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3EPlus::initializeBankState() { // Switch in each 512b slot for(uInt32 b = 0; b < 8; b++) { if(bankInUse[b] == BANK_UNDEFINED) { // All accesses point to peek/poke above System::PageAccess access(this, System::PA_READ); uInt16 start = 0x1000 + (b << RAM_BANK_TO_POWER); uInt16 end = start + RAM_BANK_SIZE - 1; for(uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); } else if (bankInUse[b] & BITMASK_ROMRAM) bankRAMSlot(bankInUse[b]); else bankROMSlot(bankInUse[b]); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3EPlus::patch(uInt16 address, uInt8 value) { #if 0 // Patch the cartridge ROM (for debugger) myBankChanged = true; uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7) Int16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference if (whichBankIsThere == BANK_UNDEFINED) { // We're trying to access undefined memory (no bank here yet). Fail! myBankChanged = false; } else if (whichBankIsThere & BITMASK_ROMRAM) { // patching RAM (512 byte banks) uInt32 byteOffset = address & BITMASK_RAM_BANK; uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; myRAM[baseAddress] = value; // write to RAM // TODO: Stephen -- should we set 'myBankChanged' true when there's a RAM write? } else { // patching ROM (1K banks) uInt32 byteOffset = address & BITMASK_ROM_BANK; uInt32 baseAddress = (whichBankIsThere << ROM_BANK_TO_POWER) + byteOffset; myImage[baseAddress] = value; // write to the image } return myBankChanged; #else return false; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge3EPlus::getImage(uInt32& size) const { size = mySize; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3EPlus::save(Serializer& out) const { try { out.putString(name()); out.putShortArray(bankInUse, 8); out.putByteArray(myRAM, RAM_TOTAL_SIZE); } catch (...) { cerr << "ERROR: Cartridge3EPlus::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3EPlus::load(Serializer& in) { try { if (in.getString() != name()) return false; in.getShortArray(bankInUse, 8); in.getByteArray(myRAM, RAM_TOTAL_SIZE); } catch (...) { cerr << "ERROR: Cartridge3EPlus::load" << endl; return false; } initializeBankState(); return true; } stella-5.1.1/src/emucore/Cart3EPlus.hxx000066400000000000000000000152141324334165500177170ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_3EPLUS_HXX #define CARTRIDGE_3EPLUS_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT class Cartridge3EPlusWidget; #include "Cart3EPlusWidget.hxx" #endif /** Cartridge class from Thomas Jentzsch, mostly based on the 'DASH' scheme with the following changes: RAM areas: - read $x000, write $x200 - read $x400, write $x600 - read $x800, write $xa00 - read $xc00, write $xe00 @author Thomas Jentzsch and Stephen Anthony */ class Cartridge3EPlus: public Cartridge { friend class Cartridge3EPlusWidget; public: /** Create a new cartridge using the specified image and size @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ Cartridge3EPlus(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~Cartridge3EPlus() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Cartridge3E+"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new Cartridge3EPlusWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: bool bankRAM(uInt8 bank); // switch a RAM bank bool bankROM(uInt8 bank); // switch a ROM bank void bankRAMSlot(uInt16 bank); // switch in a 512b RAM slot (lower or upper 1/2 bank) void bankROMSlot(uInt16 bank); // switch in a 512b RAM slot (read or write port) void initializeBankState(); // set all banks according to current bankInUse state // We have an array that indicates for each of the 8 512 byte areas of the address space, which ROM/RAM // bank is used in that area. ROM switches 1K so occupies 2 successive entries for each switch. RAM occupies // two as well, one 512 byte for read and one for write. The RAM locations are +0x800 apart, and the ROM // are consecutive. This allows us to determine on a read/write exactly where the data is. static constexpr uInt16 BANK_UNDEFINED = 0x8000; // bank is undefined and inaccessible uInt16 bankInUse[8]; // bank being used for ROM/RAM (eight 512 byte areas) static constexpr uInt16 BANK_SWITCH_HOTSPOT_RAM = 0x3E; // writes to this address cause bankswitching static constexpr uInt16 BANK_SWITCH_HOTSPOT_ROM = 0x3F; // writes to this address cause bankswitching static constexpr uInt8 BANK_BITS = 6; // # bits for bank static constexpr uInt8 BIT_BANK_MASK = (1 << BANK_BITS) - 1; // mask for those bits static constexpr uInt16 BITMASK_LOWERUPPER = 0x100; // flags lower or upper section of bank (1==upper) static constexpr uInt16 BITMASK_ROMRAM = 0x200; // flags ROM or RAM bank switching (1==RAM) static constexpr uInt16 MAXIMUM_BANK_COUNT = (1 << BANK_BITS); static constexpr uInt16 RAM_BANK_TO_POWER = 9; // 2^n = 512 static constexpr uInt16 RAM_BANK_SIZE = (1 << RAM_BANK_TO_POWER); static constexpr uInt16 BITMASK_RAM_BANK = (RAM_BANK_SIZE - 1); static constexpr uInt32 RAM_TOTAL_SIZE = MAXIMUM_BANK_COUNT * RAM_BANK_SIZE; static constexpr uInt16 ROM_BANK_TO_POWER = 10; // 2^n = 1024 static constexpr uInt16 ROM_BANK_SIZE = (1 << ROM_BANK_TO_POWER); static constexpr uInt16 BITMASK_ROM_BANK = (ROM_BANK_SIZE - 1); static constexpr uInt16 ROM_BANK_COUNT = 64; static constexpr uInt16 RAM_WRITE_OFFSET = 0x200; BytePtr myImage; // Pointer to a dynamically allocated ROM image of the cartridge uInt32 mySize; // Size of the ROM image uInt8 myRAM[RAM_TOTAL_SIZE]; private: // Following constructors and assignment operators not supported Cartridge3EPlus() = delete; Cartridge3EPlus(const Cartridge3EPlus&) = delete; Cartridge3EPlus(Cartridge3EPlus&&) = delete; Cartridge3EPlus& operator=(const Cartridge3EPlus&) = delete; Cartridge3EPlus& operator=(Cartridge3EPlus&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart3F.cxx000066400000000000000000000132331324334165500170460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "TIA.hxx" #include "Cart3F.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge3F::Cartridge3F(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), myCurrentBank(0) { // Allocate array for the ROM image myImage = make_unique(mySize); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), mySize); createCodeAccessBase(mySize); // Remember startup bank myStartBank = bankCount() - 1; // last bank } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3F::reset() { // define random startup banks // Note: This works for all Tigervision ROMs except for one version of Polaris // (md5: 203049f4d8290bb4521cc4402415e737) which requires 3 as startup bank // (or non-randomized RAM). All other ROMs take care of other startup banks. // The problematic version is most likely an incorrect dump with wrong // startup vectors. randomizeStartBank(); // We'll map the startup bank into the first segment upon reset bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge3F::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READWRITE); // The hotspot ($3F) is in TIA address space, so we claim it here for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Setup the second segment to always point to the last ROM slice access.type = System::PA_READ; for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[(mySize - 2048) + (addr & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[(mySize - 2048) + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } // Install pages for startup bank into the first segment bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge3F::peek(uInt16 address) { address &= 0x0FFF; if(address < 0x0800) return myImage[(address & 0x07FF) + (myCurrentBank << 11)]; else return myImage[(address & 0x07FF) + mySize - 2048]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3F::poke(uInt16 address, uInt8 value) { address &= 0x0FFF; // Switch banks if necessary if(address <= 0x003F) bank(value); // Handle TIA space that we claimed above mySystem->tia().poke(address, value); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3F::bank(uInt16 bank) { if(bankLocked()) return false; // Make sure the bank they're asking for is reasonable if((uInt32(bank) << 11) < mySize) { myCurrentBank = bank; } else { // Oops, the bank they're asking for isn't valid so let's wrap it // around to a valid bank number myCurrentBank = bank % (mySize >> 11); } uInt32 offset = myCurrentBank << 11; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge3F::getBank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Cartridge3F::bankCount() const { return mySize >> 11; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3F::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0800) myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value; else myImage[(address & 0x07FF) + mySize - 2048] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge3F::getImage(uInt32& size) const { size = mySize; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3F::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: Cartridge3F::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge3F::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: Cartridge3F::load" << endl; return false; } // Now, go to the current bank bank(myCurrentBank); return true; } stella-5.1.1/src/emucore/Cart3F.hxx000066400000000000000000000120101324334165500170430ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE3F_HXX #define CARTRIDGE3F_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart3FWidget.hxx" #endif /** This is the cartridge class for Tigervision's bankswitched games. In this bankswitching scheme the 2600's 4K cartridge address space is broken into two 2K segments. The last 2K segment always points to the last 2K of the ROM image. The desired bank number of the first 2K segment is selected by storing its value into $3F. Actually, any write to location $00 to $3F will change banks. Although, the Tigervision games only used 8K this bankswitching scheme supports up to 512K. @author Bradford W. Mott */ class Cartridge3F : public Cartridge { friend class Cartridge3FWidget; public: /** Create a new cartridge using the specified image and size @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ Cartridge3F(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~Cartridge3F() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Cartridge3F"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new Cartridge3FWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // Pointer to a dynamically allocated ROM image of the cartridge BytePtr myImage; // Size of the ROM image uInt32 mySize; // Indicates which bank is currently active for the first segment uInt16 myCurrentBank; private: // Following constructors and assignment operators not supported Cartridge3F() = delete; Cartridge3F(const Cartridge3F&) = delete; Cartridge3F(Cartridge3F&&) = delete; Cartridge3F& operator=(const Cartridge3F&) = delete; Cartridge3F& operator=(Cartridge3F&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart4A50.cxx000066400000000000000000000332741324334165500172160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "M6532.hxx" #include "TIA.hxx" #include "Cart4A50.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4A50::Cartridge4A50(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), mySliceLow(0), mySliceMiddle(0), mySliceHigh(0), myIsRomLow(true), myIsRomMiddle(true), myIsRomHigh(true), myLastAddress(0), myLastData(0) { // Copy the ROM image into my buffer // Supported file sizes are 32/64/128K, which are duplicated if necessary if(size < 65536) size = 32768; else if(size < 131072) size = 65536; else size = 131072; for(uInt32 slice = 0; slice < 131072 / size; ++slice) memcpy(myImage + (slice*size), image.get(), size); // We use System::PageAccess.codeAccessBase, but don't allow its use // through a pointer, since the address space of 4A50 carts can change // at the instruction level, and PageAccess is normally defined at an // interval of 64 bytes // // Instead, access will be through the getAccessFlags and setAccessFlags // methods below createCodeAccessBase(131072 + 32768); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50::reset() { initializeRAM(myRAM, 32768); mySliceLow = mySliceMiddle = mySliceHigh = 0; myIsRomLow = myIsRomMiddle = myIsRomHigh = true; myLastData = 0xff; myLastAddress = 0xffff; myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50::install(System& system) { mySystem = &system; // Map all of the accesses to call peek and poke (We don't yet indicate RAM areas) System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Mirror all access in TIA and RIOT; by doing so we're taking responsibility // for that address space in peek and poke below. mySystem->tia().installDelegate(system, *this); mySystem->m6532().installDelegate(system, *this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge4A50::peek(uInt16 address) { uInt8 value = 0; if(!(address & 0x1000)) // Hotspots below 0x1000 { // Check for RAM or TIA mirroring uInt16 lowAddress = address & 0x3ff; if(lowAddress & 0x80) value = mySystem->m6532().peek(address); else if(!(lowAddress & 0x200)) value = mySystem->tia().peek(address); checkBankSwitch(address, value); } else { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { value = myIsRomLow ? myImage[(address & 0x7ff) + mySliceLow] : myRAM[(address & 0x7ff) + mySliceLow]; } else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff ((address & 0x1fff) <= 0x1dff)) { value = myIsRomMiddle ? myImage[(address & 0x7ff) + mySliceMiddle + 0x10000] : myRAM[(address & 0x7ff) + mySliceMiddle]; } else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff { value = myIsRomHigh ? myImage[(address & 0xff) + mySliceHigh + 0x10000] : myRAM[(address & 0xff) + mySliceHigh]; } else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff { value = myImage[(address & 0xff) + 0x1ff00]; if(!bankLocked() && ((myLastData & 0xe0) == 0x60) && ((myLastAddress >= 0x1000) || (myLastAddress < 0x200))) mySliceHigh = (mySliceHigh & 0xf0ff) | ((address & 0x8) << 8) | ((address & 0x70) << 4); } } myLastData = value; myLastAddress = address & 0x1fff; return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4A50::poke(uInt16 address, uInt8 value) { if(!(address & 0x1000)) // Hotspots below 0x1000 { // Check for RAM or TIA mirroring uInt16 lowAddress = address & 0x3ff; if(lowAddress & 0x80) mySystem->m6532().poke(address, value); else if(!(lowAddress & 0x200)) mySystem->tia().poke(address, value); checkBankSwitch(address, value); } else { if((address & 0x1800) == 0x1000) // 2K region at 0x1000 - 0x17ff { if(!myIsRomLow) { myRAM[(address & 0x7ff) + mySliceLow] = value; myBankChanged = true; } } else if(((address & 0x1fff) >= 0x1800) && // 1.5K region at 0x1800 - 0x1dff ((address & 0x1fff) <= 0x1dff)) { if(!myIsRomMiddle) { myRAM[(address & 0x7ff) + mySliceMiddle] = value; myBankChanged = true; } } else if((address & 0x1f00) == 0x1e00) // 256B region at 0x1e00 - 0x1eff { if(!myIsRomHigh) { myRAM[(address & 0xff) + mySliceHigh] = value; myBankChanged = true; } } else if((address & 0x1f00) == 0x1f00) // 256B region at 0x1f00 - 0x1fff { if(!bankLocked() && ((myLastData & 0xe0) == 0x60) && ((myLastAddress >= 0x1000) || (myLastAddress < 0x200))) { mySliceHigh = (mySliceHigh & 0xf0ff) | ((address & 0x8) << 8) | ((address & 0x70) << 4); myBankChanged = true; } } } myLastData = value; myLastAddress = address & 0x1fff; return myBankChanged; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge4A50::getAccessFlags(uInt16 address) const { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { if(myIsRomLow) return myCodeAccessBase[(address & 0x7ff) + mySliceLow]; else return myCodeAccessBase[131072 + (address & 0x7ff) + mySliceLow]; } else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff ((address & 0x1fff) <= 0x1dff)) { if(myIsRomMiddle) return myCodeAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000]; else return myCodeAccessBase[131072 + (address & 0x7ff) + mySliceMiddle]; } else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff { if(myIsRomHigh) return myCodeAccessBase[(address & 0xff) + mySliceHigh + 0x10000]; else return myCodeAccessBase[131072 + (address & 0xff) + mySliceHigh]; } else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff { return myCodeAccessBase[(address & 0xff) + 0x1ff00]; } return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50::setAccessFlags(uInt16 address, uInt8 flags) { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { if(myIsRomLow) myCodeAccessBase[(address & 0x7ff) + mySliceLow] |= flags; else myCodeAccessBase[131072 + (address & 0x7ff) + mySliceLow] |= flags; } else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff ((address & 0x1fff) <= 0x1dff)) { if(myIsRomMiddle) myCodeAccessBase[(address & 0x7ff) + mySliceMiddle + 0x10000] |= flags; else myCodeAccessBase[131072 + (address & 0x7ff) + mySliceMiddle] |= flags; } else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff { if(myIsRomHigh) myCodeAccessBase[(address & 0xff) + mySliceHigh + 0x10000] |= flags; else myCodeAccessBase[131072 + (address & 0xff) + mySliceHigh] |= flags; } else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff { myCodeAccessBase[(address & 0xff) + 0x1ff00] |= flags; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4A50::checkBankSwitch(uInt16 address, uInt8 value) { if(bankLocked()) return; // This scheme contains so many hotspots that it's easier to just check // all of them if(((myLastData & 0xe0) == 0x60) && // Switch lower/middle/upper bank ((myLastAddress >= 0x1000) || (myLastAddress < 0x200))) { if((address & 0x0f00) == 0x0c00) // Enable 256B of ROM at 0x1e00 - 0x1eff bankROMHigh(address & 0xff); else if((address & 0x0f00) == 0x0d00) // Enable 256B of RAM at 0x1e00 - 0x1eff bankRAMHigh(address & 0x7f); else if((address & 0x0f40) == 0x0e00) // Enable 2K of ROM at 0x1000 - 0x17ff bankROMLower(address & 0x1f); else if((address & 0x0f40) == 0x0e40) // Enable 2K of RAM at 0x1000 - 0x17ff bankRAMLower(address & 0xf); else if((address & 0x0f40) == 0x0f00) // Enable 1.5K of ROM at 0x1800 - 0x1dff bankROMMiddle(address & 0x1f); else if((address & 0x0f50) == 0x0f40) // Enable 1.5K of RAM at 0x1800 - 0x1dff bankRAMMiddle(address & 0xf); // Stella helper functions else if((address & 0x0f00) == 0x0400) // Toggle bit A11 of lower block address { mySliceLow = mySliceLow ^ 0x800; myBankChanged = true; } else if((address & 0x0f00) == 0x0500) // Toggle bit A12 of lower block address { mySliceLow = mySliceLow ^ 0x1000; myBankChanged = true; } else if((address & 0x0f00) == 0x0800) // Toggle bit A11 of middle block address { mySliceMiddle = mySliceMiddle ^ 0x800; myBankChanged = true; } else if((address & 0x0f00) == 0x0900) // Toggle bit A12 of middle block address { mySliceMiddle = mySliceMiddle ^ 0x1000; myBankChanged = true; } } // Zero-page hotspots for upper page // 0xf4, 0xf6, 0xfc, 0xfe for ROM // 0xf5, 0xf7, 0xfd, 0xff for RAM // 0x74 - 0x7f (0x80 bytes lower) if((address & 0xf75) == 0x74) // Enable 256B of ROM at 0x1e00 - 0x1eff bankROMHigh(value); else if((address & 0xf75) == 0x75) // Enable 256B of RAM at 0x1e00 - 0x1eff bankRAMHigh(value & 0x7f); // Zero-page hotspots for lower and middle blocks // 0xf8, 0xf9, 0xfa, 0xfb // 0x78, 0x79, 0x7a, 0x7b (0x80 bytes lower) else if((address & 0xf7c) == 0x78) { if((value & 0xf0) == 0) // Enable 2K of ROM at 0x1000 - 0x17ff bankROMLower(value & 0xf); else if((value & 0xf0) == 0x40) // Enable 2K of RAM at 0x1000 - 0x17ff bankRAMLower(value & 0xf); else if((value & 0xf0) == 0x90) // Enable 1.5K of ROM at 0x1800 - 0x1dff bankROMMiddle((value & 0xf) | 0x10); else if((value & 0xf0) == 0xc0) // Enable 1.5K of RAM at 0x1800 - 0x1dff bankRAMMiddle(value & 0xf); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4A50::patch(uInt16 address, uInt8 value) { if((address & 0x1800) == 0x1000) // 2K region from 0x1000 - 0x17ff { if(myIsRomLow) myImage[(address & 0x7ff) + mySliceLow] = value; else myRAM[(address & 0x7ff) + mySliceLow] = value; } else if(((address & 0x1fff) >= 0x1800) && // 1.5K region from 0x1800 - 0x1dff ((address & 0x1fff) <= 0x1dff)) { if(myIsRomMiddle) myImage[(address & 0x7ff) + mySliceMiddle + 0x10000] = value; else myRAM[(address & 0x7ff) + mySliceMiddle] = value; } else if((address & 0x1f00) == 0x1e00) // 256B region from 0x1e00 - 0x1eff { if(myIsRomHigh) myImage[(address & 0xff) + mySliceHigh + 0x10000] = value; else myRAM[(address & 0xff) + mySliceHigh] = value; } else if((address & 0x1f00) == 0x1f00) // 256B region from 0x1f00 - 0x1fff { myImage[(address & 0xff) + 0x1ff00] = value; } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge4A50::getImage(uInt32& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4A50::save(Serializer& out) const { try { out.putString(name()); // The 32K bytes of RAM out.putByteArray(myRAM, 32768); // Index pointers out.putShort(mySliceLow); out.putShort(mySliceMiddle); out.putShort(mySliceHigh); // Whether index pointers are for ROM or RAM out.putBool(myIsRomLow); out.putBool(myIsRomMiddle); out.putBool(myIsRomHigh); // Last address and data values out.putByte(myLastData); out.putShort(myLastAddress); } catch(...) { cerr << "ERROR: Cartridge4A40::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4A50::load(Serializer& in) { try { if(in.getString() != name()) return false; in.getByteArray(myRAM, 32768); // Index pointers mySliceLow = in.getShort(); mySliceMiddle = in.getShort(); mySliceHigh = in.getShort(); // Whether index pointers are for ROM or RAM myIsRomLow = in.getBool(); myIsRomMiddle = in.getBool(); myIsRomHigh = in.getBool(); // Last address and data values myLastData = in.getByte(); myLastAddress = in.getShort(); } catch(...) { cerr << "ERROR: Cartridge4A50::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/Cart4A50.hxx000066400000000000000000000167421324334165500172240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE4A50_HXX #define CARTRIDGE4A50_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart4A50Widget.hxx" #endif /** Bankswitching method as defined/created by John Payson (aka Supercat), documented at https://stella-emu.github.io/4A50.html. In this bankswitching scheme the 2600's 4K cartridge address space is broken into four segments. The first 2K segment accesses any 2K region of RAM, or of the first 32K of ROM. The second 1.5K segment accesses the first 1.5K of any 2K region of RAM, or of the last 32K of ROM. The 3rd 256 byte segment points to any 256 byte page of RAM or ROM. The last 256 byte segment always points to the last 256 bytes of ROM. Because of the complexity of this scheme, the cart reports having only one actual bank, in which pieces of it can be swapped out in many different ways. It contains so many hotspots and possibilities for the ROM address space to change that we just consider the bank to have changed on every poke operation (for any RAM) or an actual bankswitch. NOTE: This scheme hasn't been fully implemented, and may never be (there is only one test ROM, and it hasn't been extended any further). In particular, the following functionality is missing: - hires helper functions - 1E00 page wrap @author Eckhard Stolberg & Stephen Anthony */ class Cartridge4A50 : public Cartridge { friend class Cartridge4A50Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ Cartridge4A50(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~Cartridge4A50() = default; public: /** Reset cartridge to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Cartridge4A50"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new Cartridge4A50Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Query the given address type for the associated disassembly flags. @param address The address to query */ uInt8 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ void setAccessFlags(uInt16 address, uInt8 flags) override; /** Check all possible hotspots */ void checkBankSwitch(uInt16 address, uInt8 value); /** Methods to perform all the ways that banks can be switched */ inline void bankROMLower(uInt16 value) { myIsRomLow = true; mySliceLow = value << 11; myBankChanged = true; } inline void bankRAMLower(uInt16 value) { myIsRomLow = false; mySliceLow = value << 11; myBankChanged = true; } inline void bankROMMiddle(uInt16 value) { myIsRomMiddle = true; mySliceMiddle = value << 11; myBankChanged = true; } inline void bankRAMMiddle(uInt16 value) { myIsRomMiddle = false; mySliceMiddle = value << 11; myBankChanged = true; } inline void bankROMHigh(uInt16 value) { myIsRomHigh = true; mySliceHigh = value << 8; myBankChanged = true; } inline void bankRAMHigh(uInt16 value) { myIsRomHigh = false; mySliceHigh = value << 8; myBankChanged = true; } private: // The 128K ROM image of the cartridge uInt8 myImage[131072]; // The 32K of RAM on the cartridge uInt8 myRAM[32768]; // (Actual) Size of the ROM image uInt32 mySize; // Indicates the slice mapped into each of the three segments uInt16 mySliceLow; /* index pointer for $1000-$17ff slice */ uInt16 mySliceMiddle; /* index pointer for $1800-$1dff slice */ uInt16 mySliceHigh; /* index pointer for $1e00-$1eff slice */ // Indicates whether the given slice is mapped to ROM or RAM bool myIsRomLow; /* true = ROM -- false = RAM at $1000-$17ff */ bool myIsRomMiddle; /* true = ROM -- false = RAM at $1800-$1dff */ bool myIsRomHigh; /* true = ROM -- false = RAM at $1e00-$1eFF */ // The previous address and data values (from peek and poke) uInt16 myLastAddress; uInt8 myLastData; private: // Following constructors and assignment operators not supported Cartridge4A50() = delete; Cartridge4A50(const Cartridge4A50&) = delete; Cartridge4A50(Cartridge4A50&&) = delete; Cartridge4A50& operator=(const Cartridge4A50&) = delete; Cartridge4A50& operator=(Cartridge4A50&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart4K.cxx000066400000000000000000000053001324334165500170500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "Cart4K.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4K::Cartridge4K(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(4096u, size)); createCodeAccessBase(4096); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4K::reset() { myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4K::install(System& system) { mySystem = &system; // Map ROM image into the system // Note that we don't need our own peek/poke methods, since the mapping // takes care of the entire address space System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[addr & 0x0FFF]; access.codeAccessBase = &myCodeAccessBase[addr & 0x0FFF]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4K::patch(uInt16 address, uInt8 value) { myImage[address & 0x0FFF] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge4K::getImage(uInt32& size) const { size = 4096; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4K::save(Serializer& out) const { try { out.putString(name()); } catch(...) { cerr << "ERROR: Cartridge4K::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4K::load(Serializer& in) { try { if(in.getString() != name()) return false; } catch(...) { cerr << "ERROR: Cartridge4K::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/Cart4K.hxx000066400000000000000000000071261324334165500170650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE4K_HXX #define CARTRIDGE4K_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart4KWidget.hxx" #endif /** This is the standard Atari 4K cartridge. These cartridges are not bankswitched. @author Bradford W. Mott */ class Cartridge4K : public Cartridge { friend class Cartridge4KWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ Cartridge4K(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~Cartridge4K() = default; public: /** Reset cartridge to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Cartridge4K"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new Cartridge4KWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif private: // The 4K ROM image for the cartridge uInt8 myImage[4096]; private: // Following constructors and assignment operators not supported Cartridge4K() = delete; Cartridge4K(const Cartridge4K&) = delete; Cartridge4K(Cartridge4K&&) = delete; Cartridge4K& operator=(const Cartridge4K&) = delete; Cartridge4K& operator=(Cartridge4K&&) = delete; }; #endif stella-5.1.1/src/emucore/Cart4KSC.cxx000066400000000000000000000101451324334165500173010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "Cart4KSC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cartridge4KSC::Cartridge4KSC(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(4096u, size)); createCodeAccessBase(4096); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4KSC::reset() { initializeRAM(myRAM, 128); myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Cartridge4KSC::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } // Map ROM image into the system for(uInt16 addr = 0x1100; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[addr & 0x0FFF]; access.codeAccessBase = &myCodeAccessBase[addr & 0x0FFF]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Cartridge4KSC::peek(uInt16 address) { // The only way we can get to this method is if we attempt to read from // the write port (0xF000 - 0xF080, 128 bytes), in which case an // unwanted write is triggered uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(address); return myRAM[address & 0x0FFF] = value; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4KSC::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0100) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x007F] = value; } else myImage[address & 0xFFF] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* Cartridge4KSC::getImage(uInt32& size) const { size = 4096; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4KSC::save(Serializer& out) const { try { out.putString(name()); out.putByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: Cartridge4KSC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Cartridge4KSC::load(Serializer& in) { try { if(in.getString() != name()) return false; in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: Cartridge4KSC::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/Cart4KSC.hxx000066400000000000000000000075231324334165500173140ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE4KSC_HXX #define CARTRIDGE4KSC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "Cart4KSCWidget.hxx" #endif /** Cartridge class used for 4K games with 128 bytes of RAM. RAM read port is $1080 - $10FF, write port is $1000 - $107F. */ class Cartridge4KSC : public Cartridge { friend class Cartridge4KSCWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ Cartridge4KSC(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~Cartridge4KSC() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Cartridge4KSC"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new Cartridge4KSCWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; private: // The 4K ROM image of the cartridge uInt8 myImage[4096]; // The 128 bytes of RAM uInt8 myRAM[128]; private: // Following constructors and assignment operators not supported Cartridge4KSC() = delete; Cartridge4KSC(const Cartridge4KSC&) = delete; Cartridge4KSC(Cartridge4KSC&&) = delete; Cartridge4KSC& operator=(const Cartridge4KSC&) = delete; Cartridge4KSC& operator=(Cartridge4KSC&&) = delete; }; #endif stella-5.1.1/src/emucore/CartAR.cxx000066400000000000000000000460561324334165500171110ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "M6502.hxx" #include "System.hxx" #include "CartAR.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeAR::CartridgeAR(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(std::max(size, 8448u)), myWriteEnabled(false), myPower(true), myDataHoldRegister(0), myNumberOfDistinctAccesses(0), myWritePending(false), myCurrentBank(0) { // Create a load image buffer and copy the given image myLoadImages = make_unique(mySize); myNumberOfLoadImages = mySize / 8448; memcpy(myLoadImages.get(), image.get(), size); // Add header if image doesn't include it if(size < 8448) memcpy(myLoadImages.get()+8192, ourDefaultHeader, 256); // We use System::PageAccess.codeAccessBase, but don't allow its use // through a pointer, since the AR scheme doesn't support bankswitching // in the normal sense // // Instead, access will be through the getAccessFlags and setAccessFlags // methods below createCodeAccessBase(mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::reset() { // Initialize RAM #if 0 // TODO - figure out actual behaviour of the real cart initializeRAM(myImage, 6*1024); #endif memset(myImage, 0, 6 * 1024); // Initialize SC BIOS ROM initializeROM(); myWriteEnabled = false; myPower = true; myDataHoldRegister = 0; myNumberOfDistinctAccesses = 0; myWritePending = false; // Set bank configuration upon reset so ROM is selected and powered up bankConfiguration(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::install(System& system) { mySystem = &system; // Map all of the accesses to call peek and poke (we don't yet indicate RAM areas) System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); bankConfiguration(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeAR::peek(uInt16 addr) { // In debugger/bank-locked mode, we ignore all hotspots and in general // anything that can change the internal state of the cart if(bankLocked()) return myImage[(addr & 0x07FF) + myImageOffset[(addr & 0x0800) ? 1 : 0]]; // Is the "dummy" SC BIOS hotspot for reading a load being accessed? if(((addr & 0x1FFF) == 0x1850) && (myImageOffset[1] == (3 << 11))) { // Get load that's being accessed (BIOS places load number at 0x80) uInt8 load = mySystem->peek(0x0080); // Read the specified load into RAM loadIntoRAM(load); return myImage[(addr & 0x07FF) + myImageOffset[1]]; } // Cancel any pending write if more than 5 distinct accesses have occurred // TODO: Modify to handle when the distinct counter wraps around... if(myWritePending && (mySystem->m6502().distinctAccesses() > myNumberOfDistinctAccesses + 5)) { myWritePending = false; } // Is the data hold register being set? if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending)) { myDataHoldRegister = addr; myNumberOfDistinctAccesses = mySystem->m6502().distinctAccesses(); myWritePending = true; } // Is the bank configuration hotspot being accessed? else if((addr & 0x1FFF) == 0x1FF8) { // Yes, so handle bank configuration myWritePending = false; bankConfiguration(myDataHoldRegister); } // Handle poke if writing enabled else if(myWriteEnabled && myWritePending && (mySystem->m6502().distinctAccesses() == (myNumberOfDistinctAccesses + 5))) { if((addr & 0x0800) == 0) { myImage[(addr & 0x07FF) + myImageOffset[0]] = myDataHoldRegister; mySystem->setDirtyPage(addr); } else if(myImageOffset[1] != (3 << 11)) // Can't poke to ROM :-) { myImage[(addr & 0x07FF) + myImageOffset[1]] = myDataHoldRegister; mySystem->setDirtyPage(addr); } myWritePending = false; } return myImage[(addr & 0x07FF) + myImageOffset[(addr & 0x0800) ? 1 : 0]]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeAR::poke(uInt16 addr, uInt8) { bool modified = false; // Cancel any pending write if more than 5 distinct accesses have occurred // TODO: Modify to handle when the distinct counter wraps around... if(myWritePending && (mySystem->m6502().distinctAccesses() > myNumberOfDistinctAccesses + 5)) { myWritePending = false; } // Is the data hold register being set? if(!(addr & 0x0F00) && (!myWriteEnabled || !myWritePending)) { myDataHoldRegister = addr; myNumberOfDistinctAccesses = mySystem->m6502().distinctAccesses(); myWritePending = true; } // Is the bank configuration hotspot being accessed? else if((addr & 0x1FFF) == 0x1FF8) { // Yes, so handle bank configuration myWritePending = false; bankConfiguration(myDataHoldRegister); } // Handle poke if writing enabled else if(myWriteEnabled && myWritePending && (mySystem->m6502().distinctAccesses() == (myNumberOfDistinctAccesses + 5))) { if((addr & 0x0800) == 0) { myImage[(addr & 0x07FF) + myImageOffset[0]] = myDataHoldRegister; modified = true; } else if(myImageOffset[1] != (3 << 11)) // Can't poke to ROM :-) { myImage[(addr & 0x07FF) + myImageOffset[1]] = myDataHoldRegister; modified = true; } myWritePending = false; } return modified; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeAR::getAccessFlags(uInt16 address) const { return myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::setAccessFlags(uInt16 address, uInt8 flags) { myCodeAccessBase[(address & 0x07FF) + myImageOffset[(address & 0x0800) ? 1 : 0]] |= flags; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeAR::bankConfiguration(uInt8 configuration) { // D7-D5 of this byte: Write Pulse Delay (n/a for emulator) // // D4-D0: RAM/ROM configuration: // $F000-F7FF $F800-FFFF Address range that banks map into // 000wp 2 ROM // 001wp 0 ROM // 010wp 2 0 as used in Commie Mutants and many others // 011wp 0 2 as used in Suicide Mission // 100wp 2 ROM // 101wp 1 ROM // 110wp 2 1 as used in Killer Satellites // 111wp 1 2 as we use for 2k/4k ROM cloning // // w = Write Enable (1 = enabled; accesses to $F000-$F0FF cause writes // to happen. 0 = disabled, and the cart acts like ROM.) // p = ROM Power (0 = enabled, 1 = off.) Only power the ROM if you're // wanting to access the ROM for multiloads. Otherwise set to 1. myCurrentBank = configuration & 0x1F; // remember for the bank() method // Handle ROM power configuration myPower = !(configuration & 0x01); myWriteEnabled = configuration & 0x02; switch((configuration >> 2) & 0x07) { case 0: { myImageOffset[0] = 2 << 11; myImageOffset[1] = 3 << 11; break; } case 1: { myImageOffset[0] = 0 ; myImageOffset[1] = 3 << 11; break; } case 2: { myImageOffset[0] = 2 << 11; myImageOffset[1] = 0 ; break; } case 3: { myImageOffset[0] = 0 ; myImageOffset[1] = 2 << 11; break; } case 4: { myImageOffset[0] = 2 << 11; myImageOffset[1] = 3 << 11; break; } case 5: { myImageOffset[0] = 1 << 11; myImageOffset[1] = 3 << 11; break; } case 6: { myImageOffset[0] = 2 << 11; myImageOffset[1] = 1 << 11; break; } case 7: { myImageOffset[0] = 1 << 11; myImageOffset[1] = 2 << 11; break; } } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::initializeROM() { // Note that the following offsets depend on the 'scrom.asm' file // in src/emucore/misc. If that file is ever recompiled (and its // contents placed in the ourDummyROMCode array), the offsets will // almost definitely change // The scrom.asm code checks a value at offset 109 as follows: // 0xFF -> do a complete jump over the SC BIOS progress bars code // 0x00 -> show SC BIOS progress bars as normal ourDummyROMCode[109] = mySettings.getBool("fastscbios") ? 0xFF : 0x00; // The accumulator should contain a random value after exiting the // SC BIOS code - a value placed in offset 281 will be stored in A ourDummyROMCode[281] = mySystem->randGenerator().next(); // Initialize ROM with illegal 6502 opcode that causes a real 6502 to jam memset(myImage + (3<<11), 0x02, 2048); // Copy the "dummy" Supercharger BIOS code into the ROM area memcpy(myImage + (3<<11), ourDummyROMCode, sizeof(ourDummyROMCode)); // Finally set 6502 vectors to point to initial load code at 0xF80A of BIOS myImage[(3<<11) + 2044] = 0x0A; myImage[(3<<11) + 2045] = 0xF8; myImage[(3<<11) + 2046] = 0x0A; myImage[(3<<11) + 2047] = 0xF8; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeAR::checksum(uInt8* s, uInt16 length) { uInt8 sum = 0; for(uInt32 i = 0; i < length; ++i) sum += s[i]; return sum; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeAR::loadIntoRAM(uInt8 load) { uInt16 image; // Scan through all of the loads to see if we find the one we're looking for for(image = 0; image < myNumberOfLoadImages; ++image) { // Is this the correct load? if(myLoadImages[(image * 8448) + 8192 + 5] == load) { // Copy the load's header memcpy(myHeader, myLoadImages.get() + (image * 8448) + 8192, 256); // Verify the load's header if(checksum(myHeader, 8) != 0x55) { cerr << "WARNING: The Supercharger header checksum is invalid...\n"; } // Load all of the pages from the load bool invalidPageChecksumSeen = false; for(uInt32 j = 0; j < myHeader[3]; ++j) { uInt32 bank = myHeader[16 + j] & 0x03; uInt32 page = (myHeader[16 + j] >> 2) & 0x07; uInt8* src = myLoadImages.get() + (image * 8448) + (j * 256); uInt8 sum = checksum(src, 256) + myHeader[16 + j] + myHeader[64 + j]; if(!invalidPageChecksumSeen && (sum != 0x55)) { cerr << "WARNING: Some Supercharger page checksums are invalid...\n"; invalidPageChecksumSeen = true; } // Copy page to Supercharger RAM (don't allow a copy into ROM area) if(bank < 3) { memcpy(myImage + (bank * 2048) + (page * 256), src, 256); } } // Copy the bank switching byte and starting address into the 2600's // RAM for the "dummy" SC BIOS to access it mySystem->poke(0xfe, myHeader[0]); mySystem->poke(0xff, myHeader[1]); mySystem->poke(0x80, myHeader[2]); myBankChanged = true; return; } } // TODO: Should probably switch to an internal ROM routine to display // this message to the user... cerr << "ERROR: Supercharger load is missing from ROM image...\n"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeAR::bank(uInt16 bank) { if(!bankLocked()) return bankConfiguration(bank); else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeAR::getBank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeAR::bankCount() const { return 32; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeAR::patch(uInt16 address, uInt8 value) { // TODO - add support for debugger return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeAR::getImage(uInt32& size) const { size = mySize; return myLoadImages.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeAR::save(Serializer& out) const { try { out.putString(name()); // Indicates the offest within the image for the corresponding bank out.putIntArray(myImageOffset, 2); // The 6K of RAM and 2K of ROM contained in the Supercharger out.putByteArray(myImage, 8192); // The 256 byte header for the current 8448 byte load out.putByteArray(myHeader, 256); // All of the 8448 byte loads associated with the game // Note that the size of this array is myNumberOfLoadImages * 8448 out.putByteArray(myLoadImages.get(), myNumberOfLoadImages * 8448); // Indicates how many 8448 loads there are out.putByte(myNumberOfLoadImages); // Indicates if the RAM is write enabled out.putBool(myWriteEnabled); // Indicates if the ROM's power is on or off out.putBool(myPower); // Data hold register used for writing out.putByte(myDataHoldRegister); // Indicates number of distinct accesses when data hold register was set out.putInt(myNumberOfDistinctAccesses); // Indicates if a write is pending or not out.putBool(myWritePending); } catch(...) { cerr << "ERROR: CartridgeAR::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeAR::load(Serializer& in) { try { if(in.getString() != name()) return false; // Indicates the offest within the image for the corresponding bank in.getIntArray(myImageOffset, 2); // The 6K of RAM and 2K of ROM contained in the Supercharger in.getByteArray(myImage, 8192); // The 256 byte header for the current 8448 byte load in.getByteArray(myHeader, 256); // All of the 8448 byte loads associated with the game // Note that the size of this array is myNumberOfLoadImages * 8448 in.getByteArray(myLoadImages.get(), myNumberOfLoadImages * 8448); // Indicates how many 8448 loads there are myNumberOfLoadImages = in.getByte(); // Indicates if the RAM is write enabled myWriteEnabled = in.getBool(); // Indicates if the ROM's power is on or off myPower = in.getBool(); // Data hold register used for writing myDataHoldRegister = in.getByte(); // Indicates number of distinct accesses when data hold register was set myNumberOfDistinctAccesses = in.getInt(); // Indicates if a write is pending or not myWritePending = in.getBool(); } catch(...) { cerr << "ERROR: CartridgeAR::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeAR::ourDummyROMCode[] = { 0xa5, 0xfa, 0x85, 0x80, 0x4c, 0x18, 0xf8, 0xff, 0xff, 0xff, 0x78, 0xd8, 0xa0, 0x00, 0xa2, 0x00, 0x94, 0x00, 0xe8, 0xd0, 0xfb, 0x4c, 0x50, 0xf8, 0xa2, 0x00, 0xbd, 0x06, 0xf0, 0xad, 0xf8, 0xff, 0xa2, 0x00, 0xad, 0x00, 0xf0, 0xea, 0xbd, 0x00, 0xf7, 0xca, 0xd0, 0xf6, 0x4c, 0x50, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa2, 0x03, 0xbc, 0x22, 0xf9, 0x94, 0xfa, 0xca, 0x10, 0xf8, 0xa0, 0x00, 0xa2, 0x28, 0x94, 0x04, 0xca, 0x10, 0xfb, 0xa2, 0x1c, 0x94, 0x81, 0xca, 0x10, 0xfb, 0xa9, 0xff, 0xc9, 0x00, 0xd0, 0x03, 0x4c, 0x13, 0xf9, 0xa9, 0x00, 0x85, 0x1b, 0x85, 0x1c, 0x85, 0x1d, 0x85, 0x1e, 0x85, 0x1f, 0x85, 0x19, 0x85, 0x1a, 0x85, 0x08, 0x85, 0x01, 0xa9, 0x10, 0x85, 0x21, 0x85, 0x02, 0xa2, 0x07, 0xca, 0xca, 0xd0, 0xfd, 0xa9, 0x00, 0x85, 0x20, 0x85, 0x10, 0x85, 0x11, 0x85, 0x02, 0x85, 0x2a, 0xa9, 0x05, 0x85, 0x0a, 0xa9, 0xff, 0x85, 0x0d, 0x85, 0x0e, 0x85, 0x0f, 0x85, 0x84, 0x85, 0x85, 0xa9, 0xf0, 0x85, 0x83, 0xa9, 0x74, 0x85, 0x09, 0xa9, 0x0c, 0x85, 0x15, 0xa9, 0x1f, 0x85, 0x17, 0x85, 0x82, 0xa9, 0x07, 0x85, 0x19, 0xa2, 0x08, 0xa0, 0x00, 0x85, 0x02, 0x88, 0xd0, 0xfb, 0x85, 0x02, 0x85, 0x02, 0xa9, 0x02, 0x85, 0x02, 0x85, 0x00, 0x85, 0x02, 0x85, 0x02, 0x85, 0x02, 0xa9, 0x00, 0x85, 0x00, 0xca, 0x10, 0xe4, 0x06, 0x83, 0x66, 0x84, 0x26, 0x85, 0xa5, 0x83, 0x85, 0x0d, 0xa5, 0x84, 0x85, 0x0e, 0xa5, 0x85, 0x85, 0x0f, 0xa6, 0x82, 0xca, 0x86, 0x82, 0x86, 0x17, 0xe0, 0x0a, 0xd0, 0xc3, 0xa9, 0x02, 0x85, 0x01, 0xa2, 0x1c, 0xa0, 0x00, 0x84, 0x19, 0x84, 0x09, 0x94, 0x81, 0xca, 0x10, 0xfb, 0xa6, 0x80, 0xdd, 0x00, 0xf0, 0xa9, 0x9a, 0xa2, 0xff, 0xa0, 0x00, 0x9a, 0x4c, 0xfa, 0x00, 0xcd, 0xf8, 0xff, 0x4c }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8 CartridgeAR::ourDefaultHeader[256] = { 0xac, 0xfa, 0x0f, 0x18, 0x62, 0x00, 0x24, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c, 0x01, 0x05, 0x09, 0x0d, 0x11, 0x15, 0x19, 0x1d, 0x02, 0x06, 0x0a, 0x0e, 0x12, 0x16, 0x1a, 0x1e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; stella-5.1.1/src/emucore/CartAR.hxx000066400000000000000000000153651324334165500171150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEAR_HXX #define CARTRIDGEAR_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartARWidget.hxx" #endif /** FIXME: This scheme needs to be be described in more detail. This is the cartridge class for Arcadia (aka Starpath) Supercharger games. Christopher Salomon provided most of the technical details used in creating this class. A good description of the Supercharger is provided in the Cuttle Cart's manual. The Supercharger has four 2K banks. There are three banks of RAM and one bank of ROM. All 6K of the RAM can be read and written. @author Bradford W. Mott */ class CartridgeAR : public Cartridge { friend class CartridgeARWidget; public: /** Create a new cartridge using the specified image and size @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeAR(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeAR() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeAR"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeARWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Query the given address type for the associated disassembly flags. @param address The address to query */ uInt8 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ void setAccessFlags(uInt16 address, uInt8 flags) override; // Handle a change to the bank configuration bool bankConfiguration(uInt8 configuration); // Compute the sum of the array of bytes uInt8 checksum(uInt8* s, uInt16 length); // Load the specified load into SC RAM void loadIntoRAM(uInt8 load); // Sets up a "dummy" BIOS ROM in the ROM bank of the cartridge void initializeROM(); private: // Indicates the offset within the image for the corresponding bank uInt32 myImageOffset[2]; // The 6K of RAM and 2K of ROM contained in the Supercharger uInt8 myImage[8192]; // The 256 byte header for the current 8448 byte load uInt8 myHeader[256]; // Size of the ROM image uInt32 mySize; // All of the 8448 byte loads associated with the game BytePtr myLoadImages; // Indicates how many 8448 loads there are uInt8 myNumberOfLoadImages; // Indicates if the RAM is write enabled bool myWriteEnabled; // Indicates if the ROM's power is on or off bool myPower; // Data hold register used for writing uInt8 myDataHoldRegister; // Indicates number of distinct accesses when data hold register was set uInt32 myNumberOfDistinctAccesses; // Indicates if a write is pending or not bool myWritePending; // Indicates which bank is currently active uInt16 myCurrentBank; // Fake SC-BIOS code to simulate the Supercharger load bars static uInt8 ourDummyROMCode[294]; // Default 256-byte header to use if one isn't included in the ROM // This data comes from z26 static const uInt8 ourDefaultHeader[256]; private: // Following constructors and assignment operators not supported CartridgeAR() = delete; CartridgeAR(const CartridgeAR&) = delete; CartridgeAR(CartridgeAR&&) = delete; CartridgeAR& operator=(const CartridgeAR&) = delete; CartridgeAR& operator=(CartridgeAR&&) = delete; }; #endif stella-5.1.1/src/emucore/CartBF.cxx000066400000000000000000000111131324334165500170600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartBF.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBF::CartridgeBF(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(262144u, size)); createCodeAccessBase(262144); // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBF::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBF::install(System& system) { mySystem = &system; // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBF::peek(uInt16 address) { // Due to the way addressing is set up, we will only get here if the // address is in the hotspot range ($1F80 - $1FFF) address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0F80) && (address <= 0x0FBF)) bank(address - 0x0F80); return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::poke(uInt16 address, uInt8) { // Due to the way addressing is set up, we will only get here if the // address is in the hotspot range ($1F80 - $1FFF) address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0F80) && (address <= 0x0FBF)) bank(address - 0x0F80); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1000; addr < (0x1F80U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBF::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBF::bankCount() const { return 64; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeBF::getImage(uInt32& size) const { size = 64 * 4096; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::save(Serializer& out) const { try { out.putString(name()); out.putInt(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeBF::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBF::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getInt(); } catch(...) { cerr << "ERROR: CartridgeBF::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartBF.hxx000066400000000000000000000111561324334165500170740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEBF_HXX #define CARTRIDGEBF_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartBFWidget.hxx" #endif /** Update of EF cartridge class used for Homestar Runner by Paul Slocum. There are 64 4K banks (total of 256K ROM). Accessing $1F80 - $1FBF switches to each bank. @author Mike Saarna */ class CartridgeBF : public Cartridge { friend class CartridgeBFWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeBF(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeBF() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeBF"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeBFWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 256K ROM image of the cartridge uInt8 myImage[64 * 4096]; // Indicates the offset into the ROM image (aligns to current bank) uInt32 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeBF() = delete; CartridgeBF(const CartridgeBF&) = delete; CartridgeBF(CartridgeBF&&) = delete; CartridgeBF& operator=(const CartridgeBF&) = delete; CartridgeBF& operator=(CartridgeBF&&) = delete; }; #endif stella-5.1.1/src/emucore/CartBFSC.cxx000066400000000000000000000137261324334165500173220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartBFSC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBFSC::CartridgeBFSC(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(262144u, size)); createCodeAccessBase(262144); // Remember startup bank myStartBank = 15; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSC::reset() { initializeRAM(myRAM, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBFSC::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBFSC::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0F80) && (address <= 0x0FBF)) bank(address - 0x0F80); if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } else return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBFSC::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0F80) && (address <= 0x0FBF)) bank(address - 0x0F80); // NOTE: This does not handle accessing RAM, however, this method // should never be called for RAM because of the way page accessing // has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBFSC::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1F80 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1100; addr < (0x1F80U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBFSC::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBFSC::bankCount() const { return 64; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBFSC::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0100) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x007F] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeBFSC::getImage(uInt32& size) const { size = 64 * 4096; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBFSC::save(Serializer& out) const { try { out.putString(name()); out.putInt(myBankOffset); out.putByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeBFSC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBFSC::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getInt(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeBFSC::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartBFSC.hxx000066400000000000000000000113261324334165500173210ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEBFSC_HXX #define CARTRIDGEBFSC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartBFSCWidget.hxx" #endif /** There are 64 4K banks (total of 256K ROM) with 128 bytes of RAM. Accessing $1F80 - $1FBF switches to each bank. RAM read port is $1080 - $10FF, write port is $1000 - $107F. @author Stephen Anthony */ class CartridgeBFSC : public Cartridge { friend class CartridgeBFSCWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeBFSC(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeBFSC() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeBFSC"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeBFSCWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 256K ROM image of the cartridge uInt8 myImage[64 * 4096]; // The 128 bytes of RAM uInt8 myRAM[128]; // Indicates the offset into the ROM image (aligns to current bank) uInt32 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeBFSC() = delete; CartridgeBFSC(const CartridgeBFSC&) = delete; CartridgeBFSC(CartridgeBFSC&&) = delete; CartridgeBFSC& operator=(const CartridgeBFSC&) = delete; CartridgeBFSC& operator=(CartridgeBFSC&&) = delete; }; #endif stella-5.1.1/src/emucore/CartBUS.cxx000066400000000000000000000507251324334165500172360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #include "System.hxx" #include "M6532.hxx" #include "TIA.hxx" #include "Thumbulator.hxx" #include "CartBUS.hxx" // Location of data within the RAM copy of the BUS Driver. #define DSxPTR 0x06D8 #define DSxINC 0x0720 #define DSMAPS 0x0760 #define WAVEFORM 0x07F4 #define DSRAM 0x0800 #define COMMSTREAM 0x10 #define JUMPSTREAM 0x11 #define BUS_STUFF_ON ((myMode & 0x0F) == 0) #define DIGITAL_AUDIO_ON ((myMode & 0xF0) == 0) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeBUS::CartridgeBUS(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myAudioCycles(0), myARMCycles(0), myFractionalClocks(0.0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(32768u, size)); // even though the ROM is 32K, only 28K is accessible to the 6507 createCodeAccessBase(4096 * 7); // Pointer to the program ROM (28K @ 0 byte offset) // which starts after the 2K BUS Driver and 2K C Code myProgramImage = myImage + 4096; // Pointer to BUS driver in RAM myBusDriverImage = myBUSRAM; // Pointer to the display RAM myDisplayImage = myBUSRAM + DSRAM; // Create Thumbulator ARM emulator myThumbEmulator = make_unique( reinterpret_cast(myImage), reinterpret_cast(myBUSRAM), settings.getBool("thumb.trapfatal"), Thumbulator::ConfigureFor::BUS, this ); setInitialState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::reset() { initializeRAM(myBUSRAM+2048, 8192-2048); // Update cycles to the current system cycles myAudioCycles = myARMCycles = 0; myFractionalClocks = 0.0; setInitialState(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::setInitialState() { // Copy initial BUS driver to Harmony RAM memcpy(myBusDriverImage, myImage, 0x0800); for (int i=0; i < 3; ++i) myMusicWaveformSize[i] = 27; // BUS always starts in bank 6 myStartBank = 6; // Assuming mode starts out with Fast Fetch off and 3-Voice music, // need to confirm with Chris myMode = 0xFF; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::consoleChanged(ConsoleTiming timing) { myThumbEmulator->setConsoleTiming(timing); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::install(System& system) { mySystem = &system; // Map all of the accesses to call peek and poke System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Mirror all access in TIA and RIOT; by doing so we're taking responsibility // for that address space in peek and poke below. mySystem->tia().installDelegate(system, *this); mySystem->m6532().installDelegate(system, *this); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeBUS::updateMusicModeDataFetchers() { // Calculate the number of cycles since the last update uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles); myAudioCycles = mySystem->cycles(); // Calculate the number of BUS OSC clocks since the last update double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); // Let's update counters and flags of the music mode data fetchers if(wholeClocks > 0) for(int x = 0; x <= 2; ++x) myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeBUS::callFunction(uInt8 value) { switch (value) { // Call user written ARM code (will most likely be C compiled for ARM) case 254: // call with IRQ driven audio, no special handling needed at this // time for Stella as ARM code "runs in zero 6507 cycles". case 255: // call without IRQ driven audio try { Int32 cycles = Int32(mySystem->cycles() - myARMCycles); myARMCycles = mySystem->cycles(); myThumbEmulator->run(cycles); } catch(const runtime_error& e) { if(!mySystem->autodetectMode()) { #ifdef DEBUGGER_SUPPORT Debugger::debugger().startWithFatalError(e.what()); #else cout << e.what() << endl; #endif } } break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBUS::peek(uInt16 address) { if(!(address & 0x1000)) // Hotspots below 0x1000 { // Check for RAM or TIA mirroring uInt16 lowAddress = address & 0x3ff; if(lowAddress & 0x80) return mySystem->m6532().peek(address); else if(!(lowAddress & 0x200)) return mySystem->tia().peek(address); } else { address &= 0x0FFF; uInt8 peekvalue = myProgramImage[myBankOffset + address]; // In debugger/bank-locked mode, we ignore all hotspots and in general // anything that can change the internal state of the cart if(bankLocked()) return peekvalue; // implement JMP FASTJMP which fetches the destination address from stream 17 if (myFastJumpActive && myJMPoperandAddress == address) { uInt32 pointer; uInt8 value; myFastJumpActive--; myJMPoperandAddress++; pointer = getDatastreamPointer(JUMPSTREAM); value = myDisplayImage[ pointer >> 20 ]; pointer += 0x100000; // always increment by 1 setDatastreamPointer(JUMPSTREAM, pointer); return value; } // test for JMP FASTJUMP where FASTJUMP = $0000 if (BUS_STUFF_ON && peekvalue == 0x4C && myProgramImage[myBankOffset + address+1] == 0 && myProgramImage[myBankOffset + address+2] == 0) { myFastJumpActive = 2; // return next two peeks from datastream 17 myJMPoperandAddress = address + 1; return peekvalue; } myJMPoperandAddress = 0; // save the STY's zero page address if (BUS_STUFF_ON && mySTYZeroPageAddress == address) myBusOverdriveAddress = peekvalue; mySTYZeroPageAddress = 0; switch(address) { case 0xFEE: // AMPLITUDE // Update the music data fetchers (counter & flag) updateMusicModeDataFetchers(); if DIGITAL_AUDIO_ON { // retrieve packed sample (max size is 2K, or 4K of unpacked data) uInt32 sampleaddress = getSample() + (myMusicCounters[0] >> 21); // get sample value from ROM or RAM if (sampleaddress < 0x8000) peekvalue = myImage[sampleaddress]; else if (sampleaddress >= 0x40000000 && sampleaddress < 0x40002000) // check for RAM peekvalue = myBUSRAM[sampleaddress - 0x40000000]; else peekvalue = 0; // make sure current volume value is in the lower nybble if ((myMusicCounters[0] & (1<<20)) == 0) peekvalue >>= 4; peekvalue &= 0x0f; } else { // using myDisplayImage[] instead of myProgramImage[] because waveforms // can be modified during runtime. uInt32 i = myDisplayImage[(getWaveform(0) ) + (myMusicCounters[0] >> myMusicWaveformSize[0])] + myDisplayImage[(getWaveform(1) ) + (myMusicCounters[1] >> myMusicWaveformSize[1])] + myDisplayImage[(getWaveform(2) ) + (myMusicCounters[2] >> myMusicWaveformSize[2])]; peekvalue = uInt8(i); } break; case 0xFEF: // DSREAD peekvalue = readFromDatastream(COMMSTREAM); break; case 0xFF0: // DSWRITE case 0xFF1: // DSPTR case 0xFF2: // SETMODE case 0xFF3: // CALLFN // these are write-only break; case 0xFF5: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF6: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF7: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF8: // Set the current bank to the fourth 4k bank bank(3); break; case 0x0FF9: // Set the current bank to the fifth 4k bank bank(4); break; case 0x0FFA: // Set the current bank to the sixth 4k bank bank(5); break; case 0x0FFB: // Set the current bank to the last 4k bank bank(6); break; default: break; } // this might not work right for STY $84 if (BUS_STUFF_ON && peekvalue == 0x84) mySTYZeroPageAddress = address + 1; return peekvalue; } return 0; // make compiler happy } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBUS::poke(uInt16 address, uInt8 value) { if (!(address & 0x1000)) { value &= busOverdrive(address); // Check for RAM or TIA mirroring uInt16 lowAddress = address & 0x3ff; if(lowAddress & 0x80) mySystem->m6532().poke(address, value); else if(!(lowAddress & 0x200)) mySystem->tia().poke(address, value); } else { uInt32 pointer; address &= 0x0FFF; switch(address) { case 0xFEE: // AMPLITUDE case 0xFEF: // DSREAD // these are read-only break; case 0xFF0: // DSWRITE pointer = getDatastreamPointer(COMMSTREAM); myDisplayImage[ pointer >> 20 ] = value; pointer += 0x100000; // always increment by 1 when writing setDatastreamPointer(COMMSTREAM, pointer); break; case 0xFF1: // DSPTR pointer = getDatastreamPointer(COMMSTREAM); pointer <<=8; pointer &= 0xf0000000; pointer |= (value << 20); setDatastreamPointer(COMMSTREAM, pointer); break; case 0xFF2: // SETMODE myMode = value; break; case 0xFF3: // CALLFN callFunction(value); break; case 0xFF5: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF6: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF7: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF8: // Set the current bank to the fourth 4k bank bank(3); break; case 0x0FF9: // Set the current bank to the fifth 4k bank bank(4); break; case 0x0FFA: // Set the current bank to the sixth 4k bank bank(5); break; case 0x0FFB: // Set the current bank to the last 4k bank bank(6); break; default: break; } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBUS::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map Program ROM image into the system for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBUS::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeBUS::bankCount() const { return 7; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBUS::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; // For now, we ignore attempts to patch the BUS address space if(address >= 0x0040) { myProgramImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeBUS::getImage(uInt32& size) const { size = 32768; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBUS::busOverdrive(uInt16 address) { uInt8 overdrive = 0xff; // only overdrive if the address matches if (address == myBusOverdriveAddress) { uInt8 map = address & 0x7f; if (map <= 0x24) // map TIA registers VSYNC thru HMBL inclusive { uInt32 alldatastreams = getAddressMap(map); uInt8 datastream = alldatastreams & 0x0f; // lowest nybble has the current datastream to use overdrive = readFromDatastream(datastream); // rotate map nybbles for next time alldatastreams >>= 4; alldatastreams |= (datastream << 28); setAddressMap(map, alldatastreams); } } myBusOverdriveAddress = 0xff; // turns off overdrive for next poke event return overdrive; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) { switch (function) { case 0: // _SetNote - set the note/frequency myMusicFrequencies[value1] = value2; break; // _ResetWave - reset counter, // used to make sure digital samples start from the beginning case 1: myMusicCounters[value1] = 0; break; // _GetWavePtr - return the counter case 2: return myMusicCounters[value1]; // _SetWaveSize - set size of waveform buffer case 3: myMusicWaveformSize[value1] = value2; break; } return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBUS::save(Serializer& out) const { try { out.putString(name()); // Indicates which bank is currently active out.putShort(myBankOffset); // Harmony RAM out.putByteArray(myBUSRAM, 8192); // Addresses for bus override logic out.putShort(myBusOverdriveAddress); out.putShort(mySTYZeroPageAddress); out.putShort(myJMPoperandAddress); // Save cycles and clocks out.putLong(myAudioCycles); out.putDouble(myFractionalClocks); out.putLong(myARMCycles); // Audio info out.putIntArray(myMusicCounters, 3); out.putIntArray(myMusicFrequencies, 3); out.putByteArray(myMusicWaveformSize, 3); // Indicates current mode out.putByte(myMode); // Indicates if in the middle of a fast jump out.putByte(myFastJumpActive); } catch(...) { cerr << "ERROR: CartridgeBUS::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeBUS::load(Serializer& in) { try { if(in.getString() != name()) return false; // Indicates which bank is currently active myBankOffset = in.getShort(); // Harmony RAM in.getByteArray(myBUSRAM, 8192); // Addresses for bus override logic myBusOverdriveAddress = in.getShort(); mySTYZeroPageAddress = in.getShort(); myJMPoperandAddress = in.getShort(); // Get system cycles and fractional clocks myAudioCycles = in.getLong(); myFractionalClocks = in.getDouble(); myARMCycles = in.getLong(); // Audio info in.getIntArray(myMusicCounters, 3); in.getIntArray(myMusicFrequencies, 3); in.getByteArray(myMusicWaveformSize, 3); // Indicates current mode myMode = in.getByte(); // Indicates if in the middle of a fast jump myFastJumpActive = in.getByte(); } catch(...) { cerr << "ERROR: CartridgeBUS::load" << endl; return false; } // Now, go to the current bank bank(myBankOffset >> 12); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::getDatastreamPointer(uInt8 index) const { // index &= 0x0f; return myBUSRAM[DSxPTR + index*4 + 0] + // low byte (myBUSRAM[DSxPTR + index*4 + 1] << 8) + (myBUSRAM[DSxPTR + index*4 + 2] << 16) + (myBUSRAM[DSxPTR + index*4 + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::setDatastreamPointer(uInt8 index, uInt32 value) { // index &= 0x0f; myBUSRAM[DSxPTR + index*4 + 0] = value & 0xff; // low byte myBUSRAM[DSxPTR + index*4 + 1] = (value >> 8) & 0xff; myBUSRAM[DSxPTR + index*4 + 2] = (value >> 16) & 0xff; myBUSRAM[DSxPTR + index*4 + 3] = (value >> 24) & 0xff; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::getDatastreamIncrement(uInt8 index) const { // index &= 0x0f; return myBUSRAM[DSxINC + index*4 + 0] + // low byte (myBUSRAM[DSxINC + index*4 + 1] << 8) + (myBUSRAM[DSxINC + index*4 + 2] << 16) + (myBUSRAM[DSxINC + index*4 + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::getAddressMap(uInt8 index) const { // index &= 0x0f; return myBUSRAM[DSMAPS + index*4 + 0] + // low byte (myBUSRAM[DSMAPS + index*4 + 1] << 8) + (myBUSRAM[DSMAPS + index*4 + 2] << 16) + (myBUSRAM[DSMAPS + index*4 + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::getWaveform(uInt8 index) const { // instead of 0, 1, 2, etc. this returned // 0x40000800 for 0 // 0x40000820 for 1 // 0x40000840 for 2 // ... // return myBUSRAM[WAVEFORM + index*4 + 0] + // low byte // (myBUSRAM[WAVEFORM + index*4 + 1] << 8) + // (myBUSRAM[WAVEFORM + index*4 + 2] << 16) + // (myBUSRAM[WAVEFORM + index*4 + 3] << 24) - // high byte // 0x40000800; uInt32 result; result = myBUSRAM[WAVEFORM + index*4 + 0] + // low byte (myBUSRAM[WAVEFORM + index*4 + 1] << 8) + (myBUSRAM[WAVEFORM + index*4 + 2] << 16) + (myBUSRAM[WAVEFORM + index*4 + 3] << 24); // high byte result -= 0x40000800; if (result >= 4096) result = 0; return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::getSample() { uInt32 result; result = myBUSRAM[WAVEFORM + 0] + // low byte (myBUSRAM[WAVEFORM + 1] << 8) + (myBUSRAM[WAVEFORM + 2] << 16) + (myBUSRAM[WAVEFORM + 3] << 24); // high byte return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeBUS::getWaveformSize(uInt8 index) const { return myMusicWaveformSize[index]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeBUS::setAddressMap(uInt8 index, uInt32 value) { // index &= 0x0f; myBUSRAM[DSMAPS + index*4 + 0] = value & 0xff; // low byte myBUSRAM[DSMAPS + index*4 + 1] = (value >> 8) & 0xff; myBUSRAM[DSMAPS + index*4 + 2] = (value >> 16) & 0xff; myBUSRAM[DSMAPS + index*4 + 3] = (value >> 24) & 0xff; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeBUS::readFromDatastream(uInt8 index) { // Pointers are stored as: // PPPFF--- // // Increments are stored as // ----IIFF // // P = Pointer // I = Increment // F = Fractional uInt32 pointer = getDatastreamPointer(index); uInt16 increment = getDatastreamIncrement(index); uInt8 value = myDisplayImage[ pointer >> 20 ]; pointer += (increment << 12); setDatastreamPointer(index, pointer); return value; } stella-5.1.1/src/emucore/CartBUS.hxx000066400000000000000000000173361324334165500172440ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_BUS_HXX #define CARTRIDGE_BUS_HXX class System; class Thumbulator; #ifdef DEBUGGER_SUPPORT #include "CartBUSWidget.hxx" #endif #include "bspf.hxx" #include "Cart.hxx" /** Cartridge class used for BUS. THIS BANKSWITCHING SCHEME IS EXPERIMENTAL, AND MAY BE REMOVED IN A FUTURE RELEASE. There are seven 4K program banks, a 4K Display Data RAM, 1K C Varaible and Stack, and the BUS chip. BUS chip access is mapped to $1000 - $103F. @authors: Darrell Spice Jr, Chris Walton, Fred Quimby, Stephen Anthony, Bradford W. Mott */ class CartridgeBUS : public Cartridge { friend class CartridgeBUSWidget; friend class CartridgeRamBUSWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeBUS(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeBUS() = default; public: /** Reset device to its power-on state */ void reset() override; /** Notification method invoked by the system when the console type has changed. We need this to inform the Thumbulator that the timing has changed. @param timing Enum representing the new console type */ void consoleChanged(ConsoleTiming timing) override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeBUS"; } uInt8 busOverdrive(uInt16 address); /** Used for Thumbulator to pass values back to the cartridge */ uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) override; #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeBUSWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Sets the initial state of the DPC pointers and RAM */ void setInitialState(); /** Updates any data fetchers in music mode based on the number of CPU cycles which have passed since the last update. */ void updateMusicModeDataFetchers(); /** Call Special Functions */ void callFunction(uInt8 value); uInt32 getDatastreamPointer(uInt8 index) const; void setDatastreamPointer(uInt8 index, uInt32 value); uInt32 getDatastreamIncrement(uInt8 index) const; void setDatastreamIncrement(uInt8 index, uInt32 value); uInt32 getAddressMap(uInt8 index) const; void setAddressMap(uInt8 index, uInt32 value); uInt8 readFromDatastream(uInt8 index); uInt32 getWaveform(uInt8 index) const; uInt32 getWaveformSize(uInt8 index) const; uInt32 getSample(); private: // The 32K ROM image of the cartridge uInt8 myImage[32768]; // Pointer to the 28K program ROM image of the cartridge uInt8* myProgramImage; // Pointer to the 4K display ROM image of the cartridge uInt8* myDisplayImage; // Pointer to the 2K BUS driver image in RAM uInt8* myBusDriverImage; // The BUS 8k RAM image, used as: // $0000 - 2K BUS driver // $0800 - 4K Display Data // $1800 - 2K C Variable & Stack uInt8 myBUSRAM[8192]; // Pointer to the Thumb ARM emulator object unique_ptr myThumbEmulator; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; // Address to override the bus for uInt16 myBusOverdriveAddress; // set to address of ZP if last byte peeked was $84 (STY ZP) uInt16 mySTYZeroPageAddress; // set to address of the JMP operand if last byte peeked was 4C // *and* the next two bytes in ROM are 00 00 uInt16 myJMPoperandAddress; // System cycle count from when the last update to music data fetchers occurred uInt64 myAudioCycles; // ARM cycle count from when the last callFunction() occurred uInt64 myARMCycles; // The music mode counters uInt32 myMusicCounters[3]; // The music frequency uInt32 myMusicFrequencies[3]; // The music waveform sizes uInt8 myMusicWaveformSize[3]; // Fractional DPC music OSC clocks unused during the last update double myFractionalClocks; // Controls mode, lower nybble sets Fast Fetch, upper nybble sets audio // -0 = Bus Stuffing ON // -F = Bus Stuffing OFF // 0- = Packed Digital Sample // F- = 3 Voice Music uInt8 myMode; uInt8 myFastJumpActive; private: // Following constructors and assignment operators not supported CartridgeBUS() = delete; CartridgeBUS(const CartridgeBUS&) = delete; CartridgeBUS(CartridgeBUS&&) = delete; CartridgeBUS& operator=(const CartridgeBUS&) = delete; CartridgeBUS& operator=(CartridgeBUS&&) = delete; }; #endif stella-5.1.1/src/emucore/CartCDF.cxx000066400000000000000000000430551324334165500171770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #include "System.hxx" #include "Thumbulator.hxx" #include "CartCDF.hxx" #include "TIA.hxx" // Location of data within the RAM copy of the CDF Driver. // Version 0 1 const uInt16 DSxPTR[] = {0x06E0, 0x00A0}; const uInt16 DSxINC[] = {0x0768, 0x0128}; const uInt16 WAVEFORM[] = {0x07F0, 0x01B0}; #define DSRAM 0x0800 #define COMMSTREAM 0x20 #define JUMPSTREAM 0x21 #define AMPLITUDE 0x22 #define FAST_FETCH_ON ((myMode & 0x0F) == 0) #define DIGITAL_AUDIO_ON ((myMode & 0xF0) == 0) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCDF::CartridgeCDF(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myAudioCycles(0), myARMCycles(0), myFractionalClocks(0.0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(32768u, size)); // even though the ROM is 32K, only 28K is accessible to the 6507 createCodeAccessBase(4096 * 7); // Pointer to the program ROM (28K @ 0 byte offset) // which starts after the 2K CDF Driver and 2K C Code myProgramImage = myImage + 4096; // Pointer to CDF driver in RAM myBusDriverImage = myCDFRAM; // Pointer to the display RAM myDisplayImage = myCDFRAM + DSRAM; setVersion(); // Create Thumbulator ARM emulator myThumbEmulator = make_unique( reinterpret_cast(myImage), reinterpret_cast(myCDFRAM), settings.getBool("thumb.trapfatal"), myVersion ? Thumbulator::ConfigureFor::CDF1 : Thumbulator::ConfigureFor::CDF, this); setInitialState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::reset() { initializeRAM(myCDFRAM+2048, 8192-2048); myAudioCycles = myARMCycles = 0; myFractionalClocks = 0.0; setInitialState(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::setInitialState() { // Copy initial CDF driver to Harmony RAM memcpy(myBusDriverImage, myImage, 0x0800); for (int i=0; i < 3; ++i) myMusicWaveformSize[i] = 27; // CDF always starts in bank 6 myStartBank = 6; // Assuming mode starts out with Fast Fetch off and 3-Voice music, // need to confirm with Chris myMode = 0xFF; myFastJumpActive = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::consoleChanged(ConsoleTiming timing) { myThumbEmulator->setConsoleTiming(timing); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::install(System& system) { mySystem = &system; // Map all of the accesses to call peek and poke System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeCDF::updateMusicModeDataFetchers() { // Calculate the number of cycles since the last update uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles); myAudioCycles = mySystem->cycles(); // Calculate the number of CDF OSC clocks since the last update double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); // Let's update counters and flags of the music mode data fetchers if(wholeClocks > 0) for(int x = 0; x <= 2; ++x) myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeCDF::callFunction(uInt8 value) { switch (value) { // Call user written ARM code (will most likely be C compiled for ARM) case 254: // call with IRQ driven audio, no special handling needed at this // time for Stella as ARM code "runs in zero 6507 cycles". case 255: // call without IRQ driven audio try { Int32 cycles = Int32(mySystem->cycles() - myARMCycles); myARMCycles = mySystem->cycles(); myThumbEmulator->run(cycles); } catch(const runtime_error& e) { if(!mySystem->autodetectMode()) { #ifdef DEBUGGER_SUPPORT Debugger::debugger().startWithFatalError(e.what()); #else cout << e.what() << endl; #endif } } break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCDF::peek(uInt16 address) { address &= 0x0FFF; uInt8 peekvalue = myProgramImage[myBankOffset + address]; // In debugger/bank-locked mode, we ignore all hotspots and in general // anything that can change the internal state of the cart if(bankLocked()) return peekvalue; // implement JMP FASTJMP which fetches the destination address from stream 33 if (myFastJumpActive && myJMPoperandAddress == address) { uInt32 pointer; uInt8 value; myFastJumpActive--; myJMPoperandAddress++; pointer = getDatastreamPointer(JUMPSTREAM); value = myDisplayImage[ pointer >> 20 ]; pointer += 0x100000; // always increment by 1 setDatastreamPointer(JUMPSTREAM, pointer); return value; } // test for JMP FASTJUMP where FASTJUMP = $0000 if (FAST_FETCH_ON && peekvalue == 0x4C && myProgramImage[myBankOffset + address+1] == 0 && myProgramImage[myBankOffset + address+2] == 0) { myFastJumpActive = 2; // return next two peeks from datastream 31 myJMPoperandAddress = address + 1; return peekvalue; } myJMPoperandAddress = 0; // Do a FAST FETCH LDA# if: // 1) in Fast Fetch mode // 2) peeking the operand of an LDA # instruction // 3) peek value is 0-34 if(FAST_FETCH_ON && myLDAimmediateOperandAddress == address && peekvalue <= AMPLITUDE) { myLDAimmediateOperandAddress = 0; if (peekvalue == AMPLITUDE) { updateMusicModeDataFetchers(); if DIGITAL_AUDIO_ON { // retrieve packed sample (max size is 2K, or 4K of unpacked data) uInt32 sampleaddress = getSample() + (myMusicCounters[0] >> 21); // get sample value from ROM or RAM if (sampleaddress < 0x8000) peekvalue = myImage[sampleaddress]; else if (sampleaddress >= 0x40000000 && sampleaddress < 0x40002000) // check for RAM peekvalue = myCDFRAM[sampleaddress - 0x40000000]; else peekvalue = 0; // make sure current volume value is in the lower nybble if ((myMusicCounters[0] & (1<<20)) == 0) peekvalue >>= 4; peekvalue &= 0x0f; } else { peekvalue = myDisplayImage[getWaveform(0) + (myMusicCounters[0] >> myMusicWaveformSize[0])] + myDisplayImage[getWaveform(1) + (myMusicCounters[1] >> myMusicWaveformSize[1])] + myDisplayImage[getWaveform(2) + (myMusicCounters[2] >> myMusicWaveformSize[2])]; } return peekvalue; } else { return readFromDatastream(peekvalue); } } myLDAimmediateOperandAddress = 0; // Switch banks if necessary switch(address) { case 0xFF5: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF6: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF7: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF8: // Set the current bank to the fourth 4k bank bank(3); break; case 0x0FF9: // Set the current bank to the fifth 4k bank bank(4); break; case 0x0FFA: // Set the current bank to the sixth 4k bank bank(5); break; case 0x0FFB: // Set the current bank to the last 4k bank bank(6); break; default: break; } if(FAST_FETCH_ON && peekvalue == 0xA9) myLDAimmediateOperandAddress = address + 1; return peekvalue; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCDF::poke(uInt16 address, uInt8 value) { uInt32 pointer; address &= 0x0FFF; switch(address) { case 0xFF0: // DSWRITE pointer = getDatastreamPointer(COMMSTREAM); myDisplayImage[ pointer >> 20 ] = value; pointer += 0x100000; // always increment by 1 when writing setDatastreamPointer(COMMSTREAM, pointer); break; case 0xFF1: // DSPTR pointer = getDatastreamPointer(COMMSTREAM); pointer <<=8; pointer &= 0xf0000000; pointer |= (value << 20); setDatastreamPointer(COMMSTREAM, pointer); break; case 0xFF2: // SETMODE myMode = value; break; case 0xFF3: // CALLFN callFunction(value); break; case 0xFF5: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF6: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF7: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF8: // Set the current bank to the fourth 4k bank bank(3); break; case 0x0FF9: // Set the current bank to the fifth 4k bank bank(4); break; case 0x0FFA: // Set the current bank to the sixth 4k bank bank(5); break; case 0x0FFB: // Set the current bank to the last 4k bank bank(6); break; default: break; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCDF::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map Program ROM image into the system for(uInt16 addr = 0x1040; addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCDF::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCDF::bankCount() const { return 7; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCDF::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; // For now, we ignore attempts to patch the CDF address space if(address >= 0x0040) { myProgramImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeCDF::getImage(uInt32& size) const { size = 32768; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDF::thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) { switch (function) { case 0: // _SetNote - set the note/frequency myMusicFrequencies[value1] = value2; break; // _ResetWave - reset counter, // used to make sure digital samples start from the beginning case 1: myMusicCounters[value1] = 0; break; // _GetWavePtr - return the counter case 2: return myMusicCounters[value1]; // _SetWaveSize - set size of waveform buffer case 3: myMusicWaveformSize[value1] = value2; break; } return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCDF::save(Serializer& out) const { try { out.putString(name()); // Indicates which bank is currently active out.putShort(myBankOffset); // Indicates current mode out.putByte(myMode); // State of FastJump out.putByte(myFastJumpActive); // operand addresses out.putShort(myLDAimmediateOperandAddress); out.putShort(myJMPoperandAddress); // Harmony RAM out.putByteArray(myCDFRAM, 8192); // Audio info out.putIntArray(myMusicCounters, 3); out.putIntArray(myMusicFrequencies, 3); out.putByteArray(myMusicWaveformSize, 3); // Save cycles and clocks out.putLong(myAudioCycles); out.putDouble(myFractionalClocks); out.putLong(myARMCycles); } catch(...) { cerr << "ERROR: CartridgeCDF::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCDF::load(Serializer& in) { try { if(in.getString() != name()) return false; // Indicates which bank is currently active myBankOffset = in.getShort(); // Indicates current mode myMode = in.getByte(); // State of FastJump myFastJumpActive = in.getByte(); // Address of LDA # operand myLDAimmediateOperandAddress = in.getShort(); myJMPoperandAddress = in.getShort(); // Harmony RAM in.getByteArray(myCDFRAM, 8192); // Audio info in.getIntArray(myMusicCounters, 3); in.getIntArray(myMusicFrequencies, 3); in.getByteArray(myMusicWaveformSize, 3); // Get cycles and clocks myAudioCycles = in.getLong(); myFractionalClocks = in.getDouble(); myARMCycles = in.getLong(); } catch(...) { cerr << "ERROR: CartridgeCDF::load" << endl; return false; } // Now, go to the current bank bank(myBankOffset >> 12); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDF::getDatastreamPointer(uInt8 index) const { uInt16 address = DSxPTR[myVersion] + index * 4; return myCDFRAM[address + 0] + // low byte (myCDFRAM[address + 1] << 8) + (myCDFRAM[address + 2] << 16) + (myCDFRAM[address + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::setDatastreamPointer(uInt8 index, uInt32 value) { uInt16 address = DSxPTR[myVersion] + index * 4; myCDFRAM[address + 0] = value & 0xff; // low byte myCDFRAM[address + 1] = (value >> 8) & 0xff; myCDFRAM[address + 2] = (value >> 16) & 0xff; myCDFRAM[address + 3] = (value >> 24) & 0xff; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDF::getDatastreamIncrement(uInt8 index) const { uInt16 address = DSxINC[myVersion] + index * 4; return myCDFRAM[address + 0] + // low byte (myCDFRAM[address + 1] << 8) + (myCDFRAM[address + 2] << 16) + (myCDFRAM[address + 3] << 24) ; // high byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDF::getWaveform(uInt8 index) const { uInt32 result; uInt16 address = WAVEFORM[myVersion] + index * 4; result = myCDFRAM[address + 0] + // low byte (myCDFRAM[address + 1] << 8) + (myCDFRAM[address + 2] << 16) + (myCDFRAM[address + 3] << 24); // high byte result -= (0x40000000 + DSRAM); if (result >= 4096) result &= 4095; return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDF::getSample() { uInt32 result; uInt16 address = WAVEFORM[myVersion]; result = myCDFRAM[address + 0] + // low byte (myCDFRAM[address + 1] << 8) + (myCDFRAM[address + 2] << 16) + (myCDFRAM[address + 3] << 24); // high byte return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeCDF::getWaveformSize(uInt8 index) const { return myMusicWaveformSize[index]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCDF::readFromDatastream(uInt8 index) { // Pointers are stored as: // PPPFF--- // // Increments are stored as // ----IIFF // // P = Pointer // I = Increment // F = Fractional uInt32 pointer = getDatastreamPointer(index); uInt16 increment = getDatastreamIncrement(index); uInt8 value = myDisplayImage[ pointer >> 20 ]; pointer += (increment << 12); setDatastreamPointer(index, pointer); return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCDF::setVersion() { myVersion = 0; for(uInt32 i = 0; i < 2048; i += 4) { // CDF signature occurs 3 times in a row, i+3 (+7 or +11) is version if ( myImage[i+0] == 0x43 && myImage[i + 4] == 0x43 && myImage[i + 8] == 0x43) // C if ( myImage[i+1] == 0x44 && myImage[i + 5] == 0x44 && myImage[i + 9] == 0x44) // D if (myImage[i+2] == 0x46 && myImage[i + 6] == 0x46 && myImage[i +10] == 0x46) // F { myVersion = myImage[i+3]; break; } } } stella-5.1.1/src/emucore/CartCDF.hxx000066400000000000000000000207151324334165500172020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_CDF_HXX #define CARTRIDGE_CDF_HXX class System; class Thumbulator; #ifdef DEBUGGER_SUPPORT #include "CartCDFWidget.hxx" #endif #include "bspf.hxx" #include "Cart.hxx" /** Cartridge class used for CDF. There are seven 4K program banks, a 4K Display Data RAM, 1K C Variable and Stack, and the CDF chip. CDF chip access is mapped to $1000 - $103F (both read and write). Program banks are accessible by read/write to $1FF5 - $1FFB. FIXME: THIS NEEDS TO BE UPDATED @authors: Darrell Spice Jr, Chris Walton, Fred Quimby, Stephen Anthony, Bradford W. Mott */ class CartridgeCDF : public Cartridge { friend class CartridgeCDFWidget; friend class CartridgeRamCDFWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeCDF(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeCDF() = default; public: /** Reset device to its power-on state */ void reset() override; /** Notification method invoked by the system when the console type has changed. We need this to inform the Thumbulator that the timing has changed. @param timing Enum representing the new console type */ void consoleChanged(ConsoleTiming timing) override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeCDF"; } /** Used for Thumbulator to pass values back to the cartridge */ uInt32 thumbCallback(uInt8 function, uInt32 value1, uInt32 value2) override; #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeCDFWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Sets the initial state of the DPC pointers and RAM */ void setInitialState(); /** Updates any data fetchers in music mode based on the number of CPU cycles which have passed since the last update. */ void updateMusicModeDataFetchers(); /** Call Special Functions */ void callFunction(uInt8 value); uInt32 getDatastreamPointer(uInt8 index) const; void setDatastreamPointer(uInt8 index, uInt32 value); uInt32 getDatastreamIncrement(uInt8 index) const; void setDatastreamIncrement(uInt8 index, uInt32 value); uInt8 readFromDatastream(uInt8 index); uInt32 getWaveform(uInt8 index) const; uInt32 getWaveformSize(uInt8 index) const; uInt32 getSample(); void setVersion(); private: // The 32K ROM image of the cartridge uInt8 myImage[32768]; // Pointer to the 28K program ROM image of the cartridge uInt8* myProgramImage; // Pointer to the 4K display ROM image of the cartridge uInt8* myDisplayImage; // Pointer to the 2K CDF driver image in RAM uInt8* myBusDriverImage; // The CDF 8k RAM image, used as: // $0000 - 2K CDF driver // $0800 - 4K Display Data // $1800 - 2K C Variable & Stack uInt8 myCDFRAM[8192]; // Pointer to the Thumb ARM emulator object unique_ptr myThumbEmulator; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; // System cycle count from when the last update to music data fetchers occurred uInt64 myAudioCycles; // ARM cycle count from when the last callFunction() occurred uInt64 myARMCycles; // The audio routines in the driver run in 32-bit mode and take advantage // of the FIQ Shadow Registers which are not accessible to 16-bit thumb // code. As such, Thumbulator does not support them. The driver supplies a // few 16-bit subroutines used to pass values from 16-bit to 32-bit. The // Thumbulator will trap these calls and pass the appropriate information to // the Cartridge Class via callFunction() so it can emulate the 32 bit audio routines. /* Register usage for audio: r8 = channel0 accumulator r9 = channel1 accumulator r10 = channel2 accumulator r11 = channel0 frequency r12 = channel1 frequency r13 = channel2 frequency r14 = timer base */ // The music counters, ARM FIQ shadow registers r8, r9, r10 uInt32 myMusicCounters[3]; // The music frequency, ARM FIQ shadow registers r11, r12, r13 uInt32 myMusicFrequencies[3]; // The music waveform sizes uInt8 myMusicWaveformSize[3]; // Fractional CDF music, OSC clocks unused during the last update double myFractionalClocks; // Controls mode, lower nybble sets Fast Fetch, upper nybble sets audio // -0 = Fast Fetch ON // -F = Fast Fetch OFF // 0- = Packed Digital Sample // F- = 3 Voice Music uInt8 myMode; // set to address of #value if last byte peeked was A9 (LDA #) uInt16 myLDAimmediateOperandAddress; // set to address of the JMP operand if last byte peeked was 4C // *and* the next two bytes in ROM are 00 00 uInt16 myJMPoperandAddress; TIA* myTIA; uInt8 myFastJumpActive; // version of CDF uInt16 myVersion; private: // Following constructors and assignment operators not supported CartridgeCDF() = delete; CartridgeCDF(const CartridgeCDF&) = delete; CartridgeCDF(CartridgeCDF&&) = delete; CartridgeCDF& operator=(const CartridgeCDF&) = delete; CartridgeCDF& operator=(CartridgeCDF&&) = delete; }; #endif stella-5.1.1/src/emucore/CartCM.cxx000066400000000000000000000147101324334165500170760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "CompuMate.hxx" #include "System.hxx" #include "M6532.hxx" #include "CartCM.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCM::CartridgeCM(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySWCHA(0xFF), // portA is all 1's myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(16384u, size)); createCodeAccessBase(16384); // On powerup, the last bank of ROM is enabled and RAM is disabled myStartBank = mySWCHA & 0x3; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCM::reset() { initializeRAM(myRAM, 2048); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCM::install(System& system) { mySystem = &system; // Mirror all access in RIOT; by doing so we're taking responsibility // for that address space in peek and poke below. mySystem->m6532().installDelegate(system, *this); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCM::peek(uInt16 address) { // NOTE: This does not handle accessing cart ROM/RAM, however, this method // should never be called for ROM/RAM because of the way page accessing // has been setup (it will only ever be called for RIOT reads) return mySystem->m6532().peek(address); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCM::poke(uInt16 address, uInt8 value) { // NOTE: This could be called for RIOT writes or cart ROM writes // In the latter case, the write is ignored if(!(address & 0x1000)) { // RIOT mirroring, check bankswitch if(address == 0x280) { mySWCHA = value; bank(mySWCHA & 0x3); if(myCompuMate) { uInt8& column = myCompuMate->column(); if(value & 0x20) column = 0; if(value & 0x40) column = (column + 1) % 10; } } mySystem->m6532().poke(address, value); } return myBankChanged; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCM::column() const { return myCompuMate->column(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCM::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; // Although this scheme contains four 4K ROM banks and one 2K RAM bank, // it's easier to think of things in terms of 2K slices, as follows: // // The lower 2K of cart address space always points to the lower 2K of the // current ROM bank // The upper 2K of cart address space can point to either the 2K of RAM or // the upper 2K of the current ROM bank System::PageAccess access(this, System::PA_READ); // Lower 2K (always ROM) for(uInt16 addr = 0x1000; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Upper 2K (RAM or ROM) for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.type = System::PA_READWRITE; if(mySWCHA & 0x10) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; } else { access.directPeekBase = &myRAM[addr & 0x7FF]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x07FF)]; } if((mySWCHA & 0x30) == 0x20) access.directPokeBase = &myRAM[addr & 0x7FF]; else access.directPokeBase = nullptr; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCM::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCM::bankCount() const { // We report 4 banks (of ROM), even though RAM can overlap the upper 2K // of cart address space at some times // However, this RAM isn't enabled in the normal way that bankswitching // works, so it is ignored here return 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCM::patch(uInt16 address, uInt8 value) { if((mySWCHA & 0x30) == 0x20) myRAM[address & 0x7FF] = value; else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeCM::getImage(uInt32& size) const { size = 16384; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCM::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); out.putByte(mySWCHA); out.putByte(myCompuMate->column()); out.putByteArray(myRAM, 2048); } catch(...) { cerr << "ERROR: CartridgeCM::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCM::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); mySWCHA = in.getByte(); myCompuMate->column() = in.getByte(); in.getByteArray(myRAM, 2048); } catch(...) { cerr << "ERROR: CartridgeCM::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartCM.hxx000066400000000000000000000211631324334165500171030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECM_HXX #define CARTRIDGECM_HXX class CompuMate; class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartCMWidget.hxx" #endif /** FIXME: This scheme is not yet fully implemented. In particular, loading from and saving to the cassette is completely missing. Cartridge class used for SpectraVideo CompuMate bankswitched games. This is more than just a cartridge mapper - it's also a "computer" add-on. There's two 8K EPROMs soldered on top of each other. There's two short wires with DB-9's on them which you plug into the two controller ports. A 42 or so key membrane keyboard with audio in and audio out, and 2K of RAM. There are 4 4K banks selectable at $1000 - $1FFF, and 2K RAM at $1800 - $1FFF (R/W 'line' is available at SWCHA D5, so there's no separate read and write ports). Bankswitching is done though the controller ports SWCHA: D7 = Audio input from tape player D6 = Audio out to tape player and 4017 CLK 1 -> increase key column (0 to 9) D5 = 4017 RST, and RAM direction. (high = write, low = read) 1 -> reset key column to 0 (if D4 = 0) 0 -> enable RAM writing (if D4 = 1) D4 = RAM enable: 1 = disable RAM, 0 = enable RAM D3 = keyboard row 3 input (0 = key pressed) D2 = keyboard row 1 input (0 = key pressed) D1 = bank select high bit D0 = bank select low bit INPT0: D7 = FUNC key input (0 on startup / 1 = key pressed) INPT1: D7 = always HIGH input (pulled high thru 20K resistor) INPT2: D7 = always HIGH input (pulled high thru 20K resistor) INPT3: D7 = SHIFT key input (0 on startup / 1 = key pressed) INPT4: D7 = keyboard row 0 input (0 = key pressed) INPT5: D7 = keyboard row 2 input (0 = key pressed) The keyboard's composed of a 4017 1 of 10 counter, driving the 10 columns of the keyboard. It has 4 rows. The 4 row outputs are buffered by inverters. Bit 5 of portA controls the reset line on the 4017. Pulling it high will reset scanning to column 0. Pulling it low will allow the counter to be clocked. Bit 6 of portA clocks the 4017. Each rising edge advances the column one count. There's 10 columns labelled 0-9, and 4 rows, labelled 0-3. Column 0 1 2 3 4 5 6 7 8 9 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ | 7 | | 6 | | 8 | | 2 | | 3 | | 0 | | 9 | | 5 | | 1 | | 4 | 0 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ | U | | Y | | I | | W | | E | | P | | O | | T | | Q | | R | 1 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ Row +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ | J | | H | | K | | S | | D | |ent| | L | | G | | A | | F | 2 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ | M | | N | | < | | X | | C | |spc| | > | | B | | Z | | V | 3 +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ +---+ Function and Shift are separate keys that are read by 2 of the paddle inputs. These two buttons pull the specific paddle input low when pressed. Because the inputs are inverted, a low indicates a pressed button, and a high is an unpressed one. The audio input/output are designed to drive a tape player. The audio output is buffered through an inverter and 2 resistors and a capacitor to reduce the level to feed it into the tape player. The audio input is passed through a .1uf capacitor and is pulled to 1/2 supply by two 20K resistors, then it goes through a hex inverting schmitt trigger to square it up. This then runs into bit 7 of portA. This code was heavily borrowed from z26. @author Stephen Anthony & z26 team */ class CartridgeCM : public Cartridge { friend class CartridgeCMWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeCM(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeCM() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeCM"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeCMWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; /** Inform the cartridge about the parent CompuMate controller */ void setCompuMate(shared_ptr& cmate) { myCompuMate = cmate; } /** Get the current keyboard column @return The column referenced by SWCHA D6 and D5 */ uInt8 column() const; private: // The CompuMate device which interacts with this cartridge shared_ptr myCompuMate; // The 16K ROM image of the cartridge uInt8 myImage[16384]; // The 2K of RAM uInt8 myRAM[2048]; // Current copy of SWCHA (controls ROM/RAM accesses) uInt8 mySWCHA; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeCM() = delete; CartridgeCM(const CartridgeCM&) = delete; CartridgeCM(CartridgeCM&&) = delete; CartridgeCM& operator=(const CartridgeCM&) = delete; CartridgeCM& operator=(CartridgeCM&&) = delete; }; #endif stella-5.1.1/src/emucore/CartCTY.cxx000066400000000000000000000335671324334165500172510ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Serializer.hxx" #include "System.hxx" #include "CartCTYTunes.hxx" #include "CartCTY.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCTY::CartridgeCTY(const BytePtr& image, uInt32 size, const OSystem& osystem) : Cartridge(osystem.settings()), myOSystem(osystem), myOperationType(0), myCounter(0), myLDAimmediate(false), myRandomNumber(0x2B435044), myRamAccessTimeout(0), myAudioCycles(0), myFractionalClocks(0.0), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(32768u, size)); createCodeAccessBase(32768); // Point to the first tune myFrequencyImage = CartCTYTunes; // Remember startup bank (not bank 0, since that's ARM code) myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::reset() { initializeRAM(myRAM, 64); myRAM[0] = myRAM[1] = myRAM[2] = myRAM[3] = 0xFF; myAudioCycles = 0; myFractionalClocks = 0.0; // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::install(System& system) { mySystem = &system; // Map all RAM accesses to call peek and poke System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCTY::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; uInt8 peekValue = myImage[myBankOffset + address]; // In debugger/bank-locked mode, we ignore all hotspots and in general // anything that can change the internal state of the cart if(bankLocked()) return peekValue; // Check for aliasing to 'LDA #$F2' if(myLDAimmediate && peekValue == 0xF2) { myLDAimmediate = false; // Update the music data fetchers (counter & flag) updateMusicModeDataFetchers(); #if 0 // using myDisplayImage[] instead of myProgramImage[] because waveforms // can be modified during runtime. uInt32 i = myDisplayImage[(myMusicWaveforms[0] << 5) + (myMusicCounters[0] >> 27)] + myDisplayImage[(myMusicWaveforms[1] << 5) + (myMusicCounters[1] >> 27)] + myDisplayImage[(myMusicWaveforms[2] << 5) + (myMusicCounters[2] >> 27)]; return = (uInt8)i; #endif return 0xF2; // FIXME - return frequency value here } else myLDAimmediate = false; if(address < 0x0040) // Write port is at $1000 - $103F (64 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } else if(address < 0x0080) // Read port is at $1040 - $107F (64 bytes) { address -= 0x40; switch(address) { case 0x00: // Error code after operation return myRAM[0]; case 0x01: // Get next Random Number (8-bit LFSR) myRandomNumber = ((myRandomNumber & (1<<10)) ? 0x10adab1e: 0x00) ^ ((myRandomNumber >> 11) | (myRandomNumber << 21)); return myRandomNumber & 0xFF; case 0x02: // Get Tune position (low byte) return myCounter & 0xFF; case 0x03: // Get Tune position (high byte) return (myCounter >> 8) & 0xFF; default: return myRAM[address]; } } else // Check hotspots { switch(address) { case 0x0FF4: // Bank 0 is ARM code and not actually accessed return ramReadWrite(); case 0x0FF5: case 0x0FF6: case 0x0FF7: case 0x0FF8: case 0x0FF9: case 0x0FFA: case 0x0FFB: // Banks 1 through 7 bank(address - 0x0FF4); break; default: break; } // Is this instruction an immediate mode LDA? myLDAimmediate = (peekValue == 0xA9); return peekValue; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCTY::poke(uInt16 address, uInt8 value) { address &= 0x0FFF; //cerr << "POKE: address=" << HEX4 << address << ", value=" << HEX2 << value << endl; if(address < 0x0040) // Write port is at $1000 - $103F (64 bytes) { switch(address) // FIXME for functionality { case 0x00: // Operation type for $1FF4 myOperationType = value; break; case 0x01: // Set Random seed value (reset) myRandomNumber = 0x2B435044; break; case 0x02: // Reset fetcher to beginning of tune myCounter = 0; break; case 0x03: // Advance fetcher to next tune position myCounter = (myCounter + 3) & 0x0fff; break; default: myRAM[address] = value; break; } } else // Check hotspots { switch(address) { case 0x0FF4: // Bank 0 is ARM code and not actually accessed ramReadWrite(); break; case 0x0FF5: case 0x0FF6: case 0x0FF7: case 0x0FF8: case 0x0FF9: case 0x0FFA: case 0x0FFB: // Banks 1 through 7 bank(address - 0x0FF4); break; default: break; } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCTY::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1080; addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCTY::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCTY::bankCount() const { return 8; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCTY::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0080) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x003F] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeCTY::getImage(uInt32& size) const { size = 32768; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCTY::save(Serializer& out) const { try { out.putString(name()); out.putShort(getBank()); out.putByteArray(myRAM, 64); out.putByte(myOperationType); out.putShort(myCounter); out.putBool(myLDAimmediate); out.putInt(myRandomNumber); out.putLong(myAudioCycles); out.putDouble(myFractionalClocks); } catch(...) { cerr << "ERROR: CartridgeCTY::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCTY::load(Serializer& in) { try { if(in.getString() != name()) return false; // Remember what bank we were in bank(in.getShort()); in.getByteArray(myRAM, 64); myOperationType = in.getByte(); myCounter = in.getShort(); myLDAimmediate = in.getBool(); myRandomNumber = in.getInt(); myAudioCycles = in.getLong(); myFractionalClocks = in.getDouble(); } catch(...) { cerr << "ERROR: CartridgeCTY::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::setRomName(const string& name) { myEEPROMFile = myOSystem.nvramDir() + name + "_eeprom.dat"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCTY::ramReadWrite() { /* The following algorithm implements accessing Harmony cart EEPROM 1. Wait for an access to hotspot location $1FF4 (return 1 in bit 6 while busy). 2. Determine operation from myOperationType. 3. Save or load relevant EEPROM memory to/from a file. 4. Set byte 0 of RAM+ memory to zero to indicate success (will always happen in emulation). 5. Return 0 (in bit 6) on the next access to $1FF4, if enough time has passed to complete the operation on a real system (0.5 s for read, 1 s for write). */ if(bankLocked()) return 0xff; // First access sets the timer if(myRamAccessTimeout == 0) { // Opcode and value in form of XXXXYYYY (from myOperationType), where: // XXXX = index and YYYY = operation uInt8 index = myOperationType >> 4; switch(myOperationType & 0xf) { case 1: // Load tune (index = tune) if(index < 7) { // Add 0.5 s delay for read myRamAccessTimeout = myOSystem.getTicks() + 500000; loadTune(index); } break; case 2: // Load score table (index = table) if(index < 4) { // Add 0.5 s delay for read myRamAccessTimeout = myOSystem.getTicks() + 500000; loadScore(index); } break; case 3: // Save score table (index = table) if(index < 4) { // Add 1 s delay for write myRamAccessTimeout = myOSystem.getTicks() + 1000000; saveScore(index); } break; case 4: // Wipe all score tables // Add 1 s delay for write myRamAccessTimeout = myOSystem.getTicks() + 1000000; wipeAllScores(); break; } // Bit 6 is 1, busy return myImage[myBankOffset + 0xFF4] | 0x40; } else { // Have we reached the timeout value yet? if(myOSystem.getTicks() >= myRamAccessTimeout) { myRamAccessTimeout = 0; // Turn off timer myRAM[0] = 0; // Successful operation // Bit 6 is 0, ready/success return myImage[myBankOffset + 0xFF4] & ~0x40; } else // Bit 6 is 1, busy return myImage[myBankOffset + 0xFF4] | 0x40; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::loadTune(uInt8 index) { // Each tune is offset by 4096 bytes // Instead of copying non-modifiable data around (as would happen on the // Harmony), we simply point to the appropriate tune myFrequencyImage = CartCTYTunes + (index << 12); // Reset to beginning of tune myCounter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::loadScore(uInt8 index) { Serializer serializer(myEEPROMFile, true); if(serializer) { uInt8 scoreRAM[256]; try { serializer.getByteArray(scoreRAM, 256); } catch(...) { memset(scoreRAM, 0, 256); } // Grab 60B slice @ given index (first 4 bytes are ignored) memcpy(myRAM+4, scoreRAM + (index << 6) + 4, 60); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::saveScore(uInt8 index) { Serializer serializer(myEEPROMFile); if(serializer) { // Load score RAM uInt8 scoreRAM[256]; try { serializer.getByteArray(scoreRAM, 256); } catch(...) { memset(scoreRAM, 0, 256); } // Add 60B RAM to score table @ given index (first 4 bytes are ignored) memcpy(scoreRAM + (index << 6) + 4, myRAM+4, 60); // Save score RAM serializer.rewind(); try { serializer.putByteArray(scoreRAM, 256); } catch(...) { // Maybe add logging here that save failed? cerr << name() << ": ERROR saving score table " << int(index) << endl; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCTY::wipeAllScores() { Serializer serializer(myEEPROMFile); if(serializer) { // Erase score RAM uInt8 scoreRAM[256]; memset(scoreRAM, 0, 256); try { serializer.putByteArray(scoreRAM, 256); } catch(...) { // Maybe add logging here that save failed? cerr << name() << ": ERROR wiping score tables" << endl; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeCTY::updateMusicModeDataFetchers() { // Calculate the number of cycles since the last update uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles); myAudioCycles = mySystem->cycles(); // Calculate the number of CTY OSC clocks since the last update double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); // Let's update counters and flags of the music mode data fetchers if(wholeClocks > 0) for(int x = 0; x <= 2; ++x) ; //myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks; } stella-5.1.1/src/emucore/CartCTY.hxx000066400000000000000000000244141324334165500172450ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECHETIRY_HXX #define CARTRIDGECHETIRY_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartCTYWidget.hxx" #endif /** FIXME: This scheme is not yet fully implemented. The 'Chetiry' bankswitch scheme was developed by Chris D. Walton for a Tetris clone game by the same name. It makes use of a Harmony cart, whereby ARM code in bank 0 is executed to implement the bankswitch scheme. The implementation here does not execute this ARM code, and instead implements the bankswitching directly. Its functionality is similar to several other schemes, as follows: F4SC: The scheme contains 8 4K banks, with the first bank being inaccessible (due to containing ARM code). The remaining banks (1 - 7) are accessed at hotspots $FF5 - $FFB, exactly the same as F4SC. There is 64 bytes of RAM (vs. 128 bytes in F4SC) at $1000 - $107F ($1000 - $103F is write port, $1040 - $107F is read port). FA2: The first four bytes of RAM are actually a kind of hotspot, with the following functionality. Data is accessed from Harmony EEPROM in the same fashion as the FA2 scheme. Write Addresses: $1000 = Operation Type (see discussion of hotspot $1FF4 below) $1001 = Set Random Seed Value $1002 = Reset Fetcher To Beginning Of Tune $1003 = Advance Fetcher To Next Tune Position Read Addresses: $1040 = Error Code after operation $1041 = Get Next Random Number (8-bit LFSR) $1042 = Get Tune Position (Low Byte) $1043 = Get Tune Position (High Byte) RAM Load And Save Operations: Address $1FF4 is used as a special hotspot to trigger loading and saving of the RAM, similar to FA2 bankswitching. The operation to perform is given using the first byte of the extra RAM. The format of this byte is XXXXYYYY, where XXXX is an index and YYYY is the operation to perform. There are 4 different operation types: 1 = Load Tune (index = tune) 2 = Load Score Table (index = table) 3 = Save Score Table (index = table) 4 = Wipe All Score Tables (set all 256 bytes of EEPROM to $00) The score table functionality is based on 256 bytes from Harmony EEPROM, of which there are 4 64-byte 'tables'. The 'index' for operations 2 and 3 can therefore be in the range 0 - 3, indicating which table to use. For this implementation, the 256 byte EEPROM is serialized to a file. The tune table functionality is also based on Harmony EEPROM, where 7 4K tunes are stored (28K total). The 'index' for operation 1 can therefore be in the range 0 - 6, indicating which tune to load. For this implementation, the 28K tune data is in the 'CartCTYTunes' header file. DPC+: The music functionality is quite similar to the DPC+ scheme. Fast Fetcher The music frequency value is fetched using a fast fetcher operation. This operation is aliased to the instruction "LDA #$F2". Whenever this instruction is executed, the $F2 value is replaced with the frequency value calculated from the tune data. The pointer to the tune data does not advance until address $1003 is written. When a new tune is loaded, the pointer is reset to the beginning of the tune. This also happens when the end of the tune is reached or when address $1002 is written to. The calculation of the frequency value is essentially the same as DPC. There are 3 different channels that are combined together, and only a square waveform is used. The data is formatted so that the three notes for each position appear consecutively (note0, note1, note2). Moving to the next tune position means incrementing by 3 bytes. The end of the tune is marked by a note value of 1. A note value of 0 means that the current value should not be updated, i.e continue with the previous non-zero value. @author Stephen Anthony and Chris D. Walton */ class CartridgeCTY : public Cartridge { friend class CartridgeCTYWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param osystem A reference to the OSystem currently in use */ CartridgeCTY(const BytePtr& image, uInt32 size, const OSystem& osystem); virtual ~CartridgeCTY() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeCTY"; } /** Informs the cartridge about the name of the ROM file used when creating this cart. @param name The properties file name of the ROM */ void setRomName(const string& name) override; #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeCTYWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Either load or save internal RAM to Harmony EEPROM (represented by a file in emulation). @return The value at $FF4 with bit 6 set or cleared (depending on whether the RAM access was busy or successful) */ uInt8 ramReadWrite(); /** Actions initiated by accessing $FF4 hotspot. */ void loadTune(uInt8 index); void loadScore(uInt8 index); void saveScore(uInt8 index); void wipeAllScores(); /** Updates any data fetchers in music mode based on the number of CPU cycles which have passed since the last update. */ void updateMusicModeDataFetchers(); private: // OSsytem currently in use const OSystem& myOSystem; // The 32K ROM image of the cartridge uInt8 myImage[32768]; // The 64 bytes of RAM accessible at $1000 - $1080 uInt8 myRAM[64]; // Operation type (written to $1000, used by hotspot $1FF4) uInt8 myOperationType; // Pointer to the 28K frequency table (points to the start of one // of seven 4K tunes in CartCTYTunes) const uInt8* myFrequencyImage; // The counter register for the data fetcher uInt16 myCounter; // Flags that last byte peeked was A9 (LDA #) bool myLDAimmediate; // The random number generator register uInt32 myRandomNumber; // The time after which the first request of a load/save operation // will actually be completed // Due to Harmony EEPROM constraints, a read/write isn't instantaneous, // so we need to emulate the delay as well uInt64 myRamAccessTimeout; // Full pathname of the file to use when emulating load/save // of internal RAM to Harmony cart EEPROM string myEEPROMFile; // System cycle count from when the last update to music data fetchers occurred uInt64 myAudioCycles; // Fractional DPC music OSC clocks unused during the last update double myFractionalClocks; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeCTY() = delete; CartridgeCTY(const CartridgeCTY&) = delete; CartridgeCTY(CartridgeCTY&&) = delete; CartridgeCTY& operator=(const CartridgeCTY&) = delete; CartridgeCTY& operator=(CartridgeCTY&&) = delete; }; #endif stella-5.1.1/src/emucore/CartCTYTunes.hxx000066400000000000000000005317751324334165500203010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECHETIRY_TUNES_HXX #define CARTRIDGECHETIRY_TUNES_HXX /** The following is the contents of the 'tunes.bin' file, which is used by the Chetiry bankswitch scheme for tunes data. There are 7 4K chunks. */ #define CHETIRY_TUNES_SIZE 7 * 4096 static constexpr uInt8 CartCTYTunes[CHETIRY_TUNES_SIZE] = { /////////////////////////// // Tune 1 /////////////////////////// 0x25, 0x20, 0x02, 0x00, 0x00, 0x00, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x25, 0x20, 0x00, 0x00, 0x00, 0x00, 0x23, 0x25, 0x00, 0x00, 0x00, 0x00, 0x22, 0x27, 0x00, 0x00, 0x00, 0x00, 0x20, 0x29, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /////////////////////////// // Tune 2 /////////////////////////// 0x2e, 0x29, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x29, 0x26, 0x0a, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x0a, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x16, 0x2c, 0x00, 0x00, 0x2a, 0x27, 0x0a, 0x00, 0x00, 0x00, 0x29, 0x25, 0x16, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x2a, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x0f, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x1b, 0x00, 0x00, 0x00, 0x29, 0x26, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0d, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x19, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2e, 0x2a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x02, 0x14, 0x00, 0x00, 0x00, 0x2c, 0x23, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x27, 0x14, 0x00, 0x00, 0x00, 0x33, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x14, 0x00, 0x2a, 0x00, 0x31, 0x29, 0x14, 0x00, 0x00, 0x00, 0x2f, 0x27, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2a, 0x22, 0x12, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x12, 0x00, 0x00, 0x00, 0x00, 0x27, 0x0d, 0x00, 0x25, 0x00, 0x2c, 0x23, 0x02, 0x00, 0x00, 0x00, 0x2a, 0x22, 0x0d, 0x00, 0x00, 0x00, 0x29, 0x26, 0x11, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1d, 0x00, 0x00, 0x00, 0x29, 0x26, 0x02, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x1d, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x02, 0x00, 0x00, 0x00, 0x00, 0x25, 0x16, 0x00, 0x00, 0x00, 0x2e, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1a, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x22, 0x16, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x29, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x29, 0x26, 0x0a, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x0a, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x16, 0x2c, 0x00, 0x00, 0x2a, 0x27, 0x0a, 0x00, 0x00, 0x00, 0x29, 0x25, 0x16, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x2a, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x0f, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x1b, 0x00, 0x00, 0x00, 0x29, 0x26, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x26, 0x0d, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x19, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2e, 0x2a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, 0x02, 0x14, 0x00, 0x00, 0x00, 0x2c, 0x23, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2f, 0x27, 0x14, 0x00, 0x00, 0x00, 0x33, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x14, 0x00, 0x2a, 0x00, 0x31, 0x29, 0x14, 0x00, 0x00, 0x00, 0x2f, 0x27, 0x0b, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2a, 0x22, 0x12, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x12, 0x00, 0x00, 0x00, 0x00, 0x27, 0x0d, 0x00, 0x25, 0x00, 0x2c, 0x23, 0x02, 0x00, 0x00, 0x00, 0x2a, 0x22, 0x0d, 0x00, 0x00, 0x00, 0x29, 0x26, 0x11, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1d, 0x00, 0x00, 0x00, 0x29, 0x26, 0x02, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x1d, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x02, 0x00, 0x00, 0x00, 0x00, 0x25, 0x16, 0x00, 0x00, 0x00, 0x2e, 0x2a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1a, 0x00, 0x00, 0x00, 0x2a, 0x27, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x22, 0x16, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1e, 0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x20, 0x1d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1d, 0x1a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1e, 0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1b, 0x16, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1a, 0x16, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x22, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1e, 0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x20, 0x1d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1d, 0x1a, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1e, 0x1b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x22, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x27, 0x22, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x26, 0x22, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /////////////////////////// // Tune 3 /////////////////////////// 0x02, 0x16, 0x02, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x16, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x00, 0x11, 0x00, 0x00, 0x02, 0x00, 0x02, 0x16, 0x0a, 0x00, 0x02, 0x02, 0x00, 0x16, 0x0a, 0x00, 0x16, 0x0a, 0x00, 0x11, 0x11, 0x00, 0x02, 0x02, 0x00, 0x11, 0x11, 0x00, 0x02, 0x02, 0x00, 0x16, 0x0a, 0x00, 0x02, 0x02, 0x00, 0x16, 0x0a, 0x00, 0x16, 0x0a, 0x00, 0x11, 0x11, 0x00, 0x02, 0x02, 0x00, 0x11, 0x11, 0x00, 0x02, 0x02, 0x22, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x29, 0x22, 0x16, 0x00, 0x00, 0x16, 0x2e, 0x25, 0x11, 0x00, 0x00, 0x02, 0x2d, 0x27, 0x11, 0x00, 0x00, 0x02, 0x2e, 0x25, 0x16, 0x00, 0x00, 0x02, 0x29, 0x25, 0x16, 0x29, 0x25, 0x16, 0x2a, 0x27, 0x11, 0x00, 0x00, 0x02, 0x27, 0x24, 0x11, 0x00, 0x00, 0x02, 0x29, 0x25, 0x16, 0x00, 0x00, 0x02, 0x25, 0x22, 0x16, 0x25, 0x22, 0x16, 0x27, 0x24, 0x11, 0x00, 0x00, 0x02, 0x24, 0x21, 0x11, 0x00, 0x00, 0x02, 0x25, 0x22, 0x16, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x22, 0x1d, 0x16, 0x24, 0x20, 0x11, 0x00, 0x00, 0x02, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x1d, 0x1b, 0x16, 0x1d, 0x1b, 0x16, 0x1e, 0x1b, 0x11, 0x00, 0x00, 0x02, 0x21, 0x1b, 0x11, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x1d, 0x1b, 0x16, 0x1d, 0x1b, 0x16, 0x1e, 0x1b, 0x11, 0x00, 0x00, 0x02, 0x24, 0x1b, 0x11, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x29, 0x22, 0x16, 0x00, 0x00, 0x16, 0x2e, 0x25, 0x11, 0x00, 0x00, 0x02, 0x2d, 0x27, 0x11, 0x00, 0x00, 0x02, 0x2e, 0x25, 0x16, 0x00, 0x00, 0x02, 0x29, 0x25, 0x16, 0x29, 0x25, 0x16, 0x2a, 0x27, 0x11, 0x00, 0x00, 0x02, 0x27, 0x24, 0x11, 0x00, 0x00, 0x02, 0x29, 0x25, 0x16, 0x00, 0x00, 0x02, 0x25, 0x22, 0x16, 0x25, 0x22, 0x16, 0x27, 0x24, 0x11, 0x00, 0x00, 0x02, 0x24, 0x21, 0x11, 0x00, 0x00, 0x02, 0x25, 0x22, 0x16, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x22, 0x1d, 0x16, 0x24, 0x20, 0x11, 0x00, 0x00, 0x02, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x1d, 0x1b, 0x16, 0x1d, 0x1b, 0x16, 0x1e, 0x1b, 0x11, 0x00, 0x00, 0x02, 0x21, 0x1b, 0x11, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x1d, 0x1b, 0x16, 0x1d, 0x1b, 0x16, 0x1e, 0x1b, 0x11, 0x00, 0x00, 0x02, 0x24, 0x1b, 0x11, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x02, 0x02, 0x16, 0x00, 0x00, 0x16, 0x00, 0x00, 0x12, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x16, 0x24, 0x1d, 0x15, 0x00, 0x00, 0x02, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x02, 0x22, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x02, 0x02, 0x16, 0x00, 0x00, 0x16, 0x02, 0x02, 0x12, 0x00, 0x00, 0x02, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x02, 0x00, 0x00, 0x16, 0x00, 0x00, 0x16, 0x24, 0x20, 0x0f, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x25, 0x02, 0x19, 0x00, 0x00, 0x02, 0x25, 0x00, 0x19, 0x25, 0x00, 0x14, 0x27, 0x00, 0x14, 0x00, 0x00, 0x02, 0x24, 0x00, 0x14, 0x00, 0x00, 0x02, 0x25, 0x00, 0x0d, 0x00, 0x00, 0x02, 0x25, 0x00, 0x19, 0x25, 0x00, 0x14, 0x27, 0x00, 0x14, 0x00, 0x00, 0x02, 0x24, 0x00, 0x14, 0x00, 0x00, 0x02, 0x25, 0x02, 0x0d, 0x00, 0x00, 0x02, 0x02, 0x00, 0x19, 0x00, 0x00, 0x14, 0x02, 0x00, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00, 0x00, 0x14, 0x27, 0x24, 0x14, 0x00, 0x00, 0x02, 0x02, 0x02, 0x14, 0x00, 0x00, 0x02, 0x29, 0x25, 0x0d, 0x00, 0x00, 0x02, 0x29, 0x25, 0x19, 0x29, 0x25, 0x14, 0x2a, 0x27, 0x14, 0x00, 0x00, 0x02, 0x27, 0x24, 0x14, 0x00, 0x00, 0x02, 0x29, 0x25, 0x0d, 0x00, 0x00, 0x02, 0x29, 0x25, 0x19, 0x29, 0x25, 0x14, 0x2a, 0x27, 0x14, 0x00, 0x00, 0x02, 0x27, 0x24, 0x14, 0x00, 0x00, 0x02, 0x29, 0x25, 0x0d, 0x00, 0x00, 0x02, 0x02, 0x02, 0x19, 0x00, 0x00, 0x14, 0x02, 0x02, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x02, 0x02, 0x0d, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00, 0x00, 0x14, 0x2b, 0x22, 0x0d, 0x00, 0x00, 0x02, 0x02, 0x02, 0x0f, 0x00, 0x00, 0x02, 0x2c, 0x24, 0x14, 0x00, 0x00, 0x02, 0x2c, 0x24, 0x14, 0x2c, 0x24, 0x0f, 0x2c, 0x27, 0x14, 0x00, 0x00, 0x02, 0x2c, 0x24, 0x14, 0x00, 0x00, 0x02, 0x2e, 0x27, 0x0d, 0x00, 0x00, 0x02, 0x2c, 0x29, 0x19, 0x00, 0x00, 0x14, 0x2c, 0x29, 0x0d, 0x00, 0x00, 0x02, 0x2b, 0x22, 0x19, 0x00, 0x00, 0x02, 0x2c, 0x24, 0x14, 0x00, 0x00, 0x02, 0x2c, 0x24, 0x14, 0x2c, 0x24, 0x0f, 0x2c, 0x27, 0x14, 0x00, 0x00, 0x02, 0x2c, 0x24, 0x14, 0x00, 0x00, 0x02, 0x2e, 0x27, 0x0d, 0x00, 0x00, 0x02, 0x2c, 0x29, 0x19, 0x00, 0x00, 0x14, 0x2c, 0x29, 0x0d, 0x00, 0x00, 0x02, 0x2b, 0x22, 0x19, 0x00, 0x00, 0x02, 0x2c, 0x24, 0x14, 0x00, 0x00, 0x02, 0x2c, 0x24, 0x14, 0x2c, 0x27, 0x0f, 0x2c, 0x24, 0x14, 0x00, 0x00, 0x02, 0x2c, 0x27, 0x14, 0x00, 0x00, 0x02, 0x2b, 0x22, 0x14, 0x00, 0x00, 0x02, 0x2b, 0x24, 0x14, 0x2b, 0x25, 0x0f, 0x2b, 0x22, 0x14, 0x00, 0x00, 0x02, 0x2b, 0x25, 0x14, 0x00, 0x00, 0x02, 0x2a, 0x22, 0x14, 0x00, 0x00, 0x02, 0x2a, 0x24, 0x14, 0x2a, 0x25, 0x0f, 0x2a, 0x22, 0x14, 0x00, 0x00, 0x02, 0x27, 0x24, 0x14, 0x00, 0x00, 0x02, 0x24, 0x1b, 0x14, 0x00, 0x00, 0x02, 0x25, 0x20, 0x14, 0x00, 0x00, 0x0f, 0x27, 0x24, 0x14, 0x00, 0x00, 0x02, 0x24, 0x1b, 0x14, 0x00, 0x00, 0x02, 0x27, 0x1d, 0x0a, 0x00, 0x00, 0x02, 0x25, 0x1d, 0x16, 0x25, 0x1d, 0x11, 0x24, 0x1d, 0x0a, 0x00, 0x00, 0x02, 0x25, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x02, 0x02, 0x0a, 0x00, 0x00, 0x02, 0x20, 0x1d, 0x16, 0x22, 0x20, 0x11, 0x20, 0x1d, 0x0a, 0x00, 0x00, 0x02, 0x1d, 0x02, 0x16, 0x00, 0x00, 0x02, 0x27, 0x1c, 0x0a, 0x00, 0x00, 0x02, 0x25, 0x1d, 0x16, 0x25, 0x1d, 0x11, 0x24, 0x1d, 0x0a, 0x00, 0x00, 0x02, 0x25, 0x1d, 0x16, 0x00, 0x00, 0x02, 0x02, 0x02, 0x0a, 0x00, 0x00, 0x02, 0x20, 0x1d, 0x16, 0x22, 0x20, 0x11, 0x20, 0x1d, 0x0a, 0x00, 0x00, 0x02, 0x1d, 0x02, 0x16, 0x00, 0x00, 0x02, 0x20, 0x18, 0x14, 0x00, 0x00, 0x02, 0x02, 0x02, 0x14, 0x00, 0x00, 0x0f, 0x02, 0x02, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x02, 0x02, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x02, 0x02, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x02, 0x02, 0x02, 0x14, 0x00, 0x00, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x0f, 0x21, 0x1d, 0x14, 0x00, 0x00, 0x02, 0x02, 0x02, 0x14, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /////////////////////////// // Tune 4 /////////////////////////// 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2f, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2b, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1d, 0x2e, 0x00, 0x00, 0x2c, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x1d, 0x2c, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x1a, 0x00, 0x00, 0x00, 0x23, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x27, 0x00, 0x00, 0x20, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1b, 0x2f, 0x00, 0x00, 0x33, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x1d, 0x31, 0x00, 0x00, 0x2f, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, 0x1d, 0x14, 0x2a, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x12, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x0f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x20, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x17, 0x00, 0x00, 0x00, 0x20, 0x02, 0x14, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2f, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2b, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1d, 0x2e, 0x00, 0x00, 0x2c, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x1d, 0x2c, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x1a, 0x00, 0x00, 0x00, 0x23, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x22, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x27, 0x00, 0x00, 0x20, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1b, 0x2f, 0x00, 0x00, 0x33, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x1d, 0x31, 0x00, 0x00, 0x2f, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, 0x1d, 0x14, 0x2a, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x12, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x0f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x0f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x20, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x17, 0x00, 0x00, 0x00, 0x20, 0x02, 0x14, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x33, 0x2a, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x02, 0x00, 0x33, 0x2a, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x02, 0x00, 0x34, 0x2c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x02, 0x02, 0x00, 0x33, 0x2a, 0x20, 0x00, 0x00, 0x00, 0x02, 0x02, 0x19, 0x00, 0x00, 0x00, 0x31, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x30, 0x00, 0x20, 0x31, 0x00, 0x00, 0x33, 0x02, 0x19, 0x31, 0x00, 0x00, 0x30, 0x00, 0x20, 0x33, 0x00, 0x00, 0x31, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x31, 0x28, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x02, 0x00, 0x31, 0x28, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x02, 0x00, 0x33, 0x2a, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x02, 0x02, 0x00, 0x31, 0x29, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x02, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x1e, 0x2f, 0x00, 0x00, 0x31, 0x02, 0x17, 0x2f, 0x00, 0x00, 0x2e, 0x00, 0x1e, 0x31, 0x00, 0x00, 0x2f, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x31, 0x29, 0x13, 0x00, 0x00, 0x00, 0x2f, 0x27, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x11, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2b, 0x02, 0x17, 0x2c, 0x00, 0x00, 0x2e, 0x02, 0x11, 0x2c, 0x00, 0x00, 0x2b, 0x00, 0x17, 0x2e, 0x00, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x00, 0x00, 0x00, 0x33, 0x2b, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0f, 0x29, 0x02, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x02, 0x14, 0x00, 0x00, 0x00, 0x2c, 0x1b, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x02, 0x02, 0x2c, 0x00, 0x00, 0x2e, 0x1d, 0x14, 0x2c, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x2c, 0x1b, 0x14, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x33, 0x2a, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x02, 0x00, 0x33, 0x2a, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x02, 0x00, 0x34, 0x2c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x02, 0x02, 0x00, 0x33, 0x2a, 0x20, 0x00, 0x00, 0x00, 0x02, 0x02, 0x19, 0x00, 0x00, 0x00, 0x31, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x30, 0x00, 0x20, 0x31, 0x00, 0x00, 0x33, 0x02, 0x19, 0x31, 0x00, 0x00, 0x30, 0x00, 0x20, 0x33, 0x00, 0x00, 0x31, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x31, 0x28, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x02, 0x00, 0x31, 0x28, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x02, 0x00, 0x33, 0x2a, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x02, 0x02, 0x00, 0x31, 0x29, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x02, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x1e, 0x2f, 0x00, 0x00, 0x31, 0x02, 0x17, 0x2f, 0x00, 0x00, 0x2e, 0x00, 0x1e, 0x31, 0x00, 0x00, 0x2f, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x31, 0x29, 0x13, 0x00, 0x00, 0x00, 0x2f, 0x27, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x1b, 0x00, 0x00, 0x00, 0x2e, 0x25, 0x11, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2b, 0x02, 0x17, 0x2c, 0x00, 0x00, 0x2e, 0x02, 0x11, 0x2c, 0x00, 0x00, 0x2b, 0x00, 0x17, 0x2e, 0x00, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x00, 0x00, 0x00, 0x33, 0x2b, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0f, 0x29, 0x02, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x02, 0x14, 0x00, 0x00, 0x00, 0x2c, 0x1b, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x02, 0x02, 0x2c, 0x00, 0x00, 0x2e, 0x1d, 0x14, 0x2c, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x2c, 0x1b, 0x14, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /////////////////////////// // Tune 5 /////////////////////////// 0x1e, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x1e, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1e, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x16, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x16, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1b, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x19, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x19, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /////////////////////////// // Tune 6 /////////////////////////// 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x29, 0x02, 0x18, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x25, 0x00, 0x00, 0x24, 0x1b, 0x14, 0x25, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x29, 0x02, 0x18, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x25, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x25, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x27, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x27, 0x00, 0x00, 0x25, 0x1e, 0x1b, 0x29, 0x00, 0x00, 0x25, 0x02, 0x18, 0x00, 0x00, 0x00, 0x25, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x02, 0x12, 0x25, 0x00, 0x00, 0x24, 0x1e, 0x0f, 0x27, 0x00, 0x00, 0x24, 0x02, 0x11, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x29, 0x02, 0x18, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x25, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x25, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x00, 0x00, 0x00, 0x2c, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2e, 0x02, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x27, 0x02, 0x11, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x29, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x25, 0x02, 0x16, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x27, 0x02, 0x11, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x00, 0x00, 0x00, 0x2c, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2e, 0x02, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x27, 0x02, 0x11, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x29, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x25, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x00, 0x00, 0x00, 0x2c, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2e, 0x02, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x27, 0x02, 0x11, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x29, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x25, 0x02, 0x16, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x27, 0x02, 0x11, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x00, 0x00, 0x00, 0x2c, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2e, 0x02, 0x16, 0x00, 0x00, 0x00, 0x2c, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x27, 0x02, 0x11, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x22, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x29, 0x02, 0x18, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x25, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x25, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x29, 0x02, 0x18, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x25, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x25, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x27, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x27, 0x00, 0x00, 0x25, 0x1e, 0x1b, 0x29, 0x00, 0x00, 0x25, 0x02, 0x18, 0x00, 0x00, 0x00, 0x25, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x27, 0x02, 0x12, 0x25, 0x00, 0x00, 0x24, 0x1e, 0x0f, 0x27, 0x00, 0x00, 0x24, 0x02, 0x11, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x27, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x29, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x11, 0x29, 0x00, 0x00, 0x27, 0x1d, 0x19, 0x2a, 0x00, 0x00, 0x29, 0x02, 0x18, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x25, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x25, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x25, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x02, 0x29, 0x00, 0x00, 0x29, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x29, 0x00, 0x00, 0x29, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x29, 0x00, 0x00, 0x29, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x29, 0x00, 0x00, 0x29, 0x00, 0x00, 0x2e, 0x19, 0x16, 0x2d, 0x00, 0x00, 0x2c, 0x02, 0x02, 0x2a, 0x19, 0x16, 0x2c, 0x00, 0x00, 0x2a, 0x02, 0x02, 0x29, 0x19, 0x16, 0x27, 0x00, 0x00, 0x25, 0x02, 0x02, 0x24, 0x1b, 0x15, 0x25, 0x00, 0x00, 0x21, 0x02, 0x02, 0x22, 0x19, 0x16, 0x24, 0x00, 0x00, 0x25, 0x02, 0x02, 0x27, 0x19, 0x16, 0x29, 0x00, 0x00, 0x2a, 0x02, 0x02, 0x2c, 0x19, 0x16, 0x29, 0x00, 0x00, 0x29, 0x02, 0x02, 0x2d, 0x1b, 0x15, 0x29, 0x00, 0x00, 0x29, 0x02, 0x02, 0x2a, 0x19, 0x16, 0x31, 0x00, 0x00, 0x30, 0x02, 0x02, 0x2e, 0x19, 0x16, 0x2c, 0x00, 0x00, 0x2a, 0x02, 0x02, 0x29, 0x19, 0x16, 0x27, 0x00, 0x00, 0x25, 0x02, 0x02, 0x24, 0x1b, 0x15, 0x27, 0x00, 0x00, 0x25, 0x02, 0x02, 0x29, 0x19, 0x16, 0x27, 0x00, 0x00, 0x25, 0x02, 0x02, 0x24, 0x02, 0x02, 0x25, 0x00, 0x00, 0x27, 0x00, 0x00, 0x22, 0x02, 0x02, 0x25, 0x00, 0x00, 0x24, 0x00, 0x00, 0x21, 0x00, 0x00, 0x24, 0x00, 0x00, 0x21, 0x00, 0x00, 0x22, 0x19, 0x16, 0x24, 0x00, 0x00, 0x25, 0x02, 0x02, 0x27, 0x19, 0x16, 0x29, 0x00, 0x00, 0x2a, 0x02, 0x02, 0x2e, 0x19, 0x16, 0x2d, 0x00, 0x00, 0x2c, 0x02, 0x02, 0x2a, 0x1b, 0x15, 0x29, 0x00, 0x00, 0x27, 0x02, 0x02, 0x25, 0x19, 0x16, 0x27, 0x00, 0x00, 0x25, 0x02, 0x02, 0x24, 0x19, 0x16, 0x25, 0x00, 0x00, 0x21, 0x02, 0x02, 0x22, 0x19, 0x16, 0x24, 0x00, 0x00, 0x25, 0x02, 0x02, 0x27, 0x19, 0x16, 0x29, 0x00, 0x00, 0x2a, 0x02, 0x02, 0x2e, 0x1b, 0x16, 0x33, 0x00, 0x00, 0x31, 0x02, 0x02, 0x30, 0x1b, 0x16, 0x2e, 0x00, 0x00, 0x2c, 0x02, 0x02, 0x2e, 0x1b, 0x16, 0x2c, 0x00, 0x00, 0x2a, 0x02, 0x02, 0x29, 0x1b, 0x16, 0x27, 0x00, 0x00, 0x25, 0x02, 0x02, 0x27, 0x19, 0x16, 0x25, 0x00, 0x00, 0x24, 0x02, 0x02, 0x25, 0x19, 0x16, 0x24, 0x00, 0x00, 0x22, 0x02, 0x02, 0x24, 0x1b, 0x15, 0x21, 0x00, 0x00, 0x21, 0x02, 0x02, 0x24, 0x02, 0x02, 0x21, 0x00, 0x00, 0x21, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x24, 0x00, 0x00, 0x24, 0x02, 0x02, 0x27, 0x02, 0x02, 0x24, 0x00, 0x00, 0x24, 0x00, 0x00, 0x2a, 0x21, 0x1e, 0x27, 0x00, 0x00, 0x27, 0x02, 0x02, 0x2a, 0x02, 0x02, 0x27, 0x00, 0x00, 0x27, 0x00, 0x00, 0x2d, 0x18, 0x21, 0x2a, 0x00, 0x00, 0x2a, 0x02, 0x02, 0x2d, 0x02, 0x02, 0x2a, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x33, 0x1b, 0x02, 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x33, 0x1b, 0x02, 0x30, 0x18, 0x00, 0x30, 0x18, 0x00, 0x2e, 0x16, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x1d, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x00, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x22, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x00, 0x02, 0x11, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x17, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x23, 0x02, 0x17, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x00, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x22, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x22, 0x02, 0x11, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x27, 0x02, 0x11, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x21, 0x02, 0x11, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x00, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x22, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x22, 0x02, 0x11, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x17, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x23, 0x02, 0x17, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x12, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x1b, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x22, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x21, 0x02, 0x11, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x22, 0x02, 0x16, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x29, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x27, 0x02, 0x11, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x21, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x29, 0x02, 0x16, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x22, 0x02, 0x11, 0x00, 0x00, 0x00, 0x25, 0x1d, 0x19, 0x00, 0x00, 0x00, 0x21, 0x02, 0x11, 0x00, 0x00, 0x00, 0x24, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x27, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x21, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x22, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x1b, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x19, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /////////////////////////// // Tune 7 /////////////////////////// 0x27, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1b, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1b, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x1b, 0x16, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0f, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x17, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x1c, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x1c, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x1e, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1c, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x1e, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x1c, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x1e, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x1c, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x02, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x1f, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; #endif stella-5.1.1/src/emucore/CartCV.cxx000066400000000000000000000112421324334165500171040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartCV.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCV::CartridgeCV(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size) { if(mySize == 2048) { // Copy the ROM data into my buffer memcpy(myImage, image.get(), 2048); } else if(mySize == 4096) { // The game has something saved in the RAM // Useful for MagiCard program listings // Copy the ROM data into my buffer memcpy(myImage, image.get() + 2048, 2048); // Copy the RAM image into a buffer for use in reset() myInitialRAM = make_unique(1024); memcpy(myInitialRAM.get(), image.get(), 1024); } createCodeAccessBase(2048+1024); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCV::reset() { if(myInitialRAM) { // Copy the RAM image into my buffer memcpy(myRAM, myInitialRAM.get(), 1024); } else initializeRAM(myRAM, 1024); myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCV::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[addr & 0x07FF]; access.codeAccessBase = &myCodeAccessBase[addr & 0x07FF]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM writing pages access.directPeekBase = nullptr; access.codeAccessBase = nullptr; access.type = System::PA_WRITE; for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x03FF]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x03FF]; access.codeAccessBase = &myCodeAccessBase[2048 + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCV::peek(uInt16 address) { // The only way we can get to this method is if we attempt to read from // the write port (0xF400 - 0xF800, 1024 bytes), in which case an // unwanted write is triggered uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(address); return myRAM[address & 0x03FF] = value; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCV::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0800) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions // The following will work for both reads and writes myRAM[address & 0x03FF] = value; } else myImage[address & 0x07FF] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeCV::getImage(uInt32& size) const { size = 2048; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCV::save(Serializer& out) const { try { out.putString(name()); out.putByteArray(myRAM, 1024); } catch(...) { cerr << "ERROR: CartridgeCV::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCV::load(Serializer& in) { try { if(in.getString() != name()) return false; in.getByteArray(myRAM, 1024); } catch(...) { cerr << "ERROR: CartridgeCV::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/CartCV.hxx000066400000000000000000000100361324334165500171110ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECV_HXX #define CARTRIDGECV_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartCVWidget.hxx" #endif /** Cartridge class used for Commavid's extra-RAM games. $F000-$F3FF read from RAM $F400-$F7FF write to RAM $F800-$FFFF ROM @author Eckhard Stolberg */ class CartridgeCV : public Cartridge { friend class CartridgeCVWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeCV(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeCV() = default; public: /** Reset cartridge to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeCV"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeCVWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override; private: // Pointer to the initial RAM data from the cart // This doesn't always exist, so we don't pre-allocate it BytePtr myInitialRAM; // Initial size of the cart data uInt32 mySize; // The 2k ROM image for the cartridge uInt8 myImage[2048]; // The 1024 bytes of RAM uInt8 myRAM[1024]; private: // Following constructors and assignment operators not supported CartridgeCV() = delete; CartridgeCV(const CartridgeCV&) = delete; CartridgeCV(CartridgeCV&&) = delete; CartridgeCV& operator=(const CartridgeCV&) = delete; CartridgeCV& operator=(CartridgeCV&&) = delete; }; #endif stella-5.1.1/src/emucore/CartCVPlus.cxx000066400000000000000000000145051324334165500177550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "TIA.hxx" #include "CartCVPlus.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeCVPlus::CartridgeCVPlus(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), myCurrentBank(0) { // Allocate array for the ROM image myImage = make_unique(mySize); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), mySize); createCodeAccessBase(mySize + 1024); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCVPlus::reset() { initializeRAM(myRAM, 1024); // We'll map the startup bank into the first segment upon reset bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeCVPlus::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READWRITE); // The hotspot ($3D) is in TIA address space, so we claim it here for(uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Set the page accessing method for the RAM writing pages access.directPeekBase = nullptr; access.codeAccessBase = nullptr; access.type = System::PA_WRITE; for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x03FF]; access.codeAccessBase = &myCodeAccessBase[mySize + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x03FF]; access.codeAccessBase = &myCodeAccessBase[mySize + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank into the first segment bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeCVPlus::peek(uInt16 address) { if((address & 0x0FFF) < 0x0800) // Write port is at 0xF400 - 0xF800 (1024 bytes) { // Read port is handled in ::install() // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(address); return myRAM[address & 0x03FF] = value; } } else return myImage[(address & 0x07FF) + (myCurrentBank << 11)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCVPlus::poke(uInt16 address, uInt8 value) { address &= 0x0FFF; // Switch banks if necessary if(address == 0x003D) bank(value); // Handle TIA space that we claimed above mySystem->tia().poke(address, value); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCVPlus::bank(uInt16 bank) { if(bankLocked()) return false; // Make sure the bank they're asking for is reasonable if((uInt32(bank) << 11) < mySize) { myCurrentBank = bank; } else { // Oops, the bank they're asking for isn't valid so let's wrap it // around to a valid bank number myCurrentBank = bank % (mySize >> 11); } uInt32 offset = myCurrentBank << 11; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1800; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x07FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x07FF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCVPlus::getBank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeCVPlus::bankCount() const { return mySize >> 11; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCVPlus::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0800) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions // The following will work for both reads and writes myRAM[address & 0x03FF] = value; } else myImage[(address & 0x07FF) + (myCurrentBank << 11)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeCVPlus::getImage(uInt32& size) const { size = mySize; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCVPlus::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); out.putByteArray(myRAM, 1024); } catch(...) { cerr << "ERROR: CartridgeCVPlus::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeCVPlus::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 1024); } catch(...) { cerr << "ERROR: CartridgeCVPlus::load" << endl; return false; } // Now, go to the current bank bank(myCurrentBank); return true; } stella-5.1.1/src/emucore/CartCVPlus.hxx000066400000000000000000000121441324334165500177570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGECVPlus_HXX #define CARTRIDGECVPlus_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartCVPlusWidget.hxx" #endif /** Cartridge class based on both Commavid and 3F/3E schemes: Commavid (RAM): $F000-$F3FF read from RAM $F400-$F7FF write to RAM 3F/3E (ROM): $F800-$FFFF ROM In this bankswitching scheme the 2600's 4K cartridge address space is broken into two 2K segments. The lower 2K is RAM, as decribed above (same as CV/Commavid scheme). To map ROM, the desired bank number of the upper 2K segment is selected by storing its value into $3D. @author Stephen Anthony, LS_Dracon */ class CartridgeCVPlus : public Cartridge { friend class CartridgeCVPlusWidget; public: /** Create a new cartridge using the specified image and size @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeCVPlus(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeCVPlus() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeCV+"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeCVPlusWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // Pointer to a dynamically allocated ROM image of the cartridge BytePtr myImage; // The 1024 bytes of RAM uInt8 myRAM[1024]; // Size of the ROM image uInt32 mySize; // Indicates which bank is currently active for the first segment uInt16 myCurrentBank; private: // Following constructors and assignment operators not supported CartridgeCVPlus() = delete; CartridgeCVPlus(const CartridgeCVPlus&) = delete; CartridgeCVPlus(CartridgeCVPlus&&) = delete; CartridgeCVPlus& operator=(const CartridgeCVPlus&) = delete; CartridgeCVPlus& operator=(CartridgeCVPlus&&) = delete; }; #endif stella-5.1.1/src/emucore/CartDASH.cxx000066400000000000000000000257241324334165500173250ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "TIA.hxx" #include "CartDASH.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDASH::CartridgeDASH(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size) { // Allocate array for the ROM image myImage = make_unique(mySize); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), mySize); createCodeAccessBase(mySize + RAM_TOTAL_SIZE); // Remember startup bank (0 per spec, rather than last per 3E scheme). // Set this to go to 3rd 1K Bank. myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASH::reset() { initializeRAM(myRAM, RAM_TOTAL_SIZE); // Initialise bank values for all ROM/RAM access // This is used to reverse-lookup from address to bank location for(uInt32 b = 0; b < 8; b++) { bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible! segmentInUse[b/2] = BANK_UNDEFINED; } initializeBankState(); // We'll map the startup banks 0 and 3 from the image into the third 1K bank upon reset bankROM((0 << BANK_BITS) | 0); bankROM((3 << BANK_BITS) | 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASH::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READWRITE); // The hotspots are in TIA address space, so we claim it here for (uInt16 addr = 0x00; addr < 0x40; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Initialise bank values for all ROM/RAM access // This is used to reverse-lookup from address to bank location for (uInt32 b = 0; b < 8; b++) { bankInUse[b] = BANK_UNDEFINED; // bank is undefined and inaccessible! segmentInUse[b/2] = BANK_UNDEFINED; } initializeBankState(); // Setup the last segment (of 4, each 1K) to point to the first ROM slice // Actually we DO NOT want "always". It's just on bootup, and can be out switched later bankROM((0 << BANK_BITS) | 0); bankROM((3 << BANK_BITS) | 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDASH::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // restrict to 4K address range uInt8 value = 0; uInt32 bank = (address >> (ROM_BANK_TO_POWER - 1)) & 7; // convert to 512 byte bank index (0-7) uInt16 imageBank = bankInUse[bank]; // the ROM/RAM bank that's here if (imageBank == BANK_UNDEFINED) // an uninitialised bank? { // accessing invalid bank, so return should be... random? value = mySystem->randGenerator().next(); } else if (imageBank & BITMASK_ROMRAM) // a RAM bank { // Reading from the write port triggers an unwanted write value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); Int32 ramBank = imageBank & BIT_BANK_MASK; // discard irrelevant bits Int32 offset = ramBank << RAM_BANK_TO_POWER; // base bank address in RAM offset += (address & BITMASK_RAM_BANK); // + byte offset in RAM bank return myRAM[offset] = value; } } return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDASH::poke(uInt16 address, uInt8 value) { bool changed = false; // Check for write to the bank switch address. RAM/ROM and bank # are encoded in 'value' // There are NO mirrored hotspots. if (address == BANK_SWITCH_HOTSPOT_RAM) changed = bankRAM(value); else if (address == BANK_SWITCH_HOTSPOT_ROM) changed = bankROM(value); // Handle TIA space that we claimed above mySystem->tia().poke(address, value); return changed; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDASH::bankRAM(uInt8 bank) { if (bankLocked()) // debugger can lock RAM return false; // Each RAM bank uses two slots, separated by 0x800 in memory -- one read, one write. bankRAMSlot(bank | BITMASK_ROMRAM | 0); bankRAMSlot(bank | BITMASK_ROMRAM | BITMASK_LOWERUPPER); // Remember that this hotspot was accessed for RAM segmentInUse[(bank >> BANK_BITS) & 3] = bank | BITMASK_ROMRAM; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASH::bankRAMSlot(uInt16 bank) { uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) to 512 byte block uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range bool upper = bank & BITMASK_LOWERUPPER; // is this the read or write port uInt32 startCurrentBank = currentBank << RAM_BANK_TO_POWER; // Effectively * 512 bytes // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); if(upper) // We're mapping the write port { bankInUse[bankNumber + 4] = Int16(bank); access.type = System::PA_WRITE; } else // We're mapping the read port { bankInUse[bankNumber] = Int16(bank); access.type = System::PA_READ; } uInt16 start = 0x1000 + (bankNumber << RAM_BANK_TO_POWER) + (upper ? RAM_WRITE_OFFSET : 0); uInt16 end = start + RAM_BANK_SIZE - 1; for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) { if(upper) access.directPokeBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; else access.directPeekBase = &myRAM[startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; access.codeAccessBase = &myCodeAccessBase[mySize + startCurrentBank + (addr & (RAM_BANK_SIZE - 1))]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDASH::bankROM(uInt8 bank) { if (bankLocked()) // debugger can lock ROM return false; // Map ROM bank image into the system into the correct slot // Memory map is 1K slots at 0x1000, 0x1400, 0x1800, 0x1C00 // Each ROM uses 2 consecutive 512 byte slots bankROMSlot(bank | 0); bankROMSlot(bank | BITMASK_LOWERUPPER); // Remember that this hotspot was accessed for ROM segmentInUse[(bank >> BANK_BITS) & 3] = bank; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASH::bankROMSlot(uInt16 bank) { uInt16 bankNumber = (bank >> BANK_BITS) & 3; // which bank # we are switching TO (BITS D6,D7) uInt16 currentBank = bank & BIT_BANK_MASK; // Wrap around/restrict to valid range bool upper = bank & BITMASK_LOWERUPPER; // is this the lower or upper 512b bankInUse[bankNumber * 2 + (upper ? 1 : 0)] = Int16(bank); // Record which bank switched in (as ROM) uInt32 startCurrentBank = currentBank << ROM_BANK_TO_POWER; // Effectively *1K // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); uInt16 start = 0x1000 + (bankNumber << ROM_BANK_TO_POWER) + (upper ? ROM_BANK_SIZE / 2 : 0); uInt16 end = start + ROM_BANK_SIZE / 2 - 1; for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; access.codeAccessBase = &myCodeAccessBase[startCurrentBank + (addr & (ROM_BANK_SIZE - 1))]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDASH::initializeBankState() { // Switch in each 512b slot for(uInt32 b = 0; b < 8; b++) { if(bankInUse[b] == BANK_UNDEFINED) { // All accesses point to peek/poke above System::PageAccess access(this, System::PA_READ); uInt16 start = 0x1000 + (b << RAM_BANK_TO_POWER); uInt16 end = start + RAM_BANK_SIZE - 1; for (uInt16 addr = start; addr <= end; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); } else if (bankInUse[b] & BITMASK_ROMRAM) bankRAMSlot(bankInUse[b]); else bankROMSlot(bankInUse[b]); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDASH::patch(uInt16 address, uInt8 value) { #if 0 // Patch the cartridge ROM (for debugger) myBankChanged = true; uInt32 bankNumber = (address >> RAM_BANK_TO_POWER) & 7; // now 512 byte bank # (ie: 0-7) Int16 whichBankIsThere = bankInUse[bankNumber]; // ROM or RAM bank reference if (whichBankIsThere == BANK_UNDEFINED) { // We're trying to access undefined memory (no bank here yet). Fail! myBankChanged = false; } else if (whichBankIsThere & BITMASK_ROMRAM) { // patching RAM (512 byte banks) uInt32 byteOffset = address & BITMASK_RAM_BANK; uInt32 baseAddress = ((whichBankIsThere & BIT_BANK_MASK) << RAM_BANK_TO_POWER) + byteOffset; myRAM[baseAddress] = value; // write to RAM // TODO: Stephen -- should we set 'myBankChanged' true when there's a RAM write? } else { // patching ROM (1K banks) uInt32 byteOffset = address & BITMASK_ROM_BANK; uInt32 baseAddress = (whichBankIsThere << ROM_BANK_TO_POWER) + byteOffset; myImage[baseAddress] = value; // write to the image } return myBankChanged; #else return false; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDASH::getImage(uInt32& size) const { size = mySize; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDASH::save(Serializer& out) const { try { out.putString(name()); out.putShortArray(bankInUse, 8); out.putShortArray(segmentInUse, 4); out.putByteArray(myRAM, RAM_TOTAL_SIZE); } catch (...) { cerr << "ERROR: CartridgeDASH::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDASH::load(Serializer& in) { try { if (in.getString() != name()) return false; in.getShortArray(bankInUse, 8); in.getShortArray(segmentInUse, 4); in.getByteArray(myRAM, RAM_TOTAL_SIZE); } catch (...) { cerr << "ERROR: CartridgeDASH::load" << endl; return false; } initializeBankState(); return true; } stella-5.1.1/src/emucore/CartDASH.hxx000066400000000000000000000256271324334165500173340ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEDASH_HXX #define CARTRIDGEDASH_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT class CartridgeDASHWidget; #include "CartDASHWidget.hxx" #endif /** Cartridge class for new tiling engine "Boulder Dash" format games with RAM. Kind of a combination of 3F and 3E, with better switchability. B.Watson's Cart3E was used as a template for building this implementation. The destination bank (0-3) is held in the top bits of the value written to $3E (for RAM switching) or $3F (for ROM switching). The low 6 bits give the actual bank number (0-63) corresponding to 512 byte blocks for RAM and 1024 byte blocks for ROM. The maximum size is therefore 32K RAM and 64K ROM. D7D6 indicate the bank number (0-3) D5D4D3D2D1D0 indicate the actual # (0-63) from the image/ram ROM: Note: in descriptions $F000 is equivalent to $1000 -- that is, we only deal with the low 13 bits of addressing. Stella code uses $1000, I'm used to $F000 So, mask with top bits clear :) when reading this document. In this scheme, the 4K address space is broken into four 1K ROM segments. living at 0x1000, 0x1400, 0x1800, 0x1C00 (or, same thing, 0xF000... etc.), and four 512 byte RAM segments, living at 0x1000, 0x1200, 0x1400, 0x1600 with write-mirrors +0x800 of these. The last 1K ROM ($FC00-$FFFF) segment in the 6502 address space (ie: $1C00-$1FFF) is initialised to point to the FIRST 1K of the ROM image, so the reset vectors must be placed at the end of the first 1K in the ROM image. Note, this is DIFFERENT to 3E which switches in the UPPER bank and this bank is fixed. This allows variable sized ROM without having to detect size. First bank (0) in ROM is the default fixed bank mapped to $FC00. The system requires the reset vectors to be valid on a reset, so either the hardware first switches in the first bank, or the programmer must ensure that the reset vector is present in ALL ROM banks which might be switched into the last bank area. Currently the latter (programmer onus) is required, but it would be nice for the cartridge hardware to auto-switch on reset. ROM switching (write of block+bank number to $3F) D7D6 upper 2 bits of bank # indicates the destination segment (0-3, corresponding to $F000, $F400, $F800, $FC00), and lower 6 bits indicate the 1K bank to switch in. Can handle 64 x 1K ROM banks (64K total). D7 D6 D5D4D3D2D1D0 0 0 x x x x x x switch a 1K ROM bank xxxxx to $F000 0 1 switch a 1K ROM bank xxxxx to $F400 1 0 switch a 1K ROM bank xxxxx to $F800 1 1 switch a 1K ROM bank xxxxx to $FC00 RAM switching (write of segment+bank number to $3E) with D7D6 upper 2 bits of bank # indicates the destination RAM segment (0-3, corresponding to $F000, $F200, $F400, $F600). Note that this allows contiguous 2K of RAM to be configured by setting 4 consecutive RAM segments each 512 bytes with consecutive addresses. However, as the write address of RAM is +0x800, this invalidates ROM access as described below. can handle 64 x 512 byte RAM banks (32K total) D7 D6 D5D4D3D2D1D0 0 0 x x x x x x switch a 512 byte RAM bank xxxxx to $F000 with write @ $F800 0 1 switch a 512 byte RAM bank xxxxx to $F200 with write @ $FA00 1 0 switch a 512 byte RAM bank xxxxx to $F400 with write @ $FC00 1 1 switch a 512 byte RAM bank xxxxx to $F600 with write @ $FE00 It is possible to switch multiple RAM banks and ROM banks together For example, F000-F1FF RAM bank A (512 byte READ) F200-F3FF high 512 bytes of ROM bank previously loaded at F000 F400 ROM bank 0 (1K) F800 RAM bank A (512 byte WRITE) FA00-FBFF high 512 bytes of ROM bank previously loaded at F400 FC00 ROM bank 1 This example shows 512 bytes of RAM, and 2 1K ROM banks and two 512 byte ROM bank halves. Switching RAM blocks (D7D6 of $3E) partially invalidates ROM blocks, as below... RAM block Invalidates ROM block 0 0 (lower half), 2 (lower half) 1 0 (upper half), 2 (upper half) 2 1 (lower half), 3 (upper half) 3 1 (upper half), 3 (lower half) For example, RAM block 1 uses address $F200-$F3FF and $FA00-$FBFF ROM block 0 uses address $F000-$F3FF, and ROM block 2 uses address $F800-$FBFF Switching in RAM block 1 makes F200-F3FF ROM inaccessible, however F000-F1FF is still readable. So, care must be paid. This crazy RAM layout is useful as it allows contiguous RAM to be switched in, up to 2K in one sequentially accessible block. This means you CAN have 2K of consecutive RAM (don't forget to copy your reset vectors!) @author Andrew Davie */ class CartridgeDASH: public Cartridge { friend class CartridgeDASHWidget; public: /** Create a new cartridge using the specified image and size @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeDASH(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeDASH() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeDASH"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeDASHWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: bool bankRAM(uInt8 bank); // switch a RAM bank bool bankROM(uInt8 bank); // switch a ROM bank void bankRAMSlot(uInt16 bank); // switch in a 512b RAM slot (lower or upper 1/2 bank) void bankROMSlot(uInt16 bank); // switch in a 512b RAM slot (read or write port) void initializeBankState(); // set all banks according to current bankInUse state // We have an array that indicates for each of the 8 512 byte areas of the address space, which ROM/RAM // bank is used in that area. ROM switches 1K so occupies 2 successive entries for each switch. RAM occupies // two as well, one 512 byte for read and one for write. The RAM locations are +0x800 apart, and the ROM // are consecutive. This allows us to determine on a read/write exactly where the data is. static constexpr uInt16 BANK_UNDEFINED = 0x8000; // bank is undefined and inaccessible uInt16 bankInUse[8]; // bank being used for ROM/RAM (eight 512 byte areas) uInt16 segmentInUse[4]; // set by bank methods, to know which hotspot was accessed static constexpr uInt16 BANK_SWITCH_HOTSPOT_RAM = 0x3E; // writes to this address cause bankswitching static constexpr uInt16 BANK_SWITCH_HOTSPOT_ROM = 0x3F; // writes to this address cause bankswitching static constexpr uInt8 BANK_BITS = 6; // # bits for bank static constexpr uInt8 BIT_BANK_MASK = (1 << BANK_BITS) - 1; // mask for those bits static constexpr uInt16 BITMASK_LOWERUPPER = 0x100; // flags lower or upper section of bank (1==upper) static constexpr uInt16 BITMASK_ROMRAM = 0x200; // flags ROM or RAM bank switching (1==RAM) static constexpr uInt16 MAXIMUM_BANK_COUNT = (1 << BANK_BITS); static constexpr uInt16 RAM_BANK_TO_POWER = 9; // 2^n = 512 static constexpr uInt16 RAM_BANK_SIZE = (1 << RAM_BANK_TO_POWER); static constexpr uInt16 BITMASK_RAM_BANK = (RAM_BANK_SIZE - 1); static constexpr uInt32 RAM_TOTAL_SIZE = MAXIMUM_BANK_COUNT * RAM_BANK_SIZE; static constexpr uInt16 ROM_BANK_TO_POWER = 10; // 2^n = 1024 static constexpr uInt16 ROM_BANK_SIZE = (1 << ROM_BANK_TO_POWER); static constexpr uInt16 BITMASK_ROM_BANK = (ROM_BANK_SIZE - 1); static constexpr uInt16 ROM_BANK_COUNT = 64; static constexpr uInt16 RAM_WRITE_OFFSET = 0x800; BytePtr myImage; // Pointer to a dynamically allocated ROM image of the cartridge uInt32 mySize; // Size of the ROM image uInt8 myRAM[RAM_TOTAL_SIZE]; private: // Following constructors and assignment operators not supported CartridgeDASH() = delete; CartridgeDASH(const CartridgeDASH&) = delete; CartridgeDASH(CartridgeDASH&&) = delete; CartridgeDASH& operator=(const CartridgeDASH&) = delete; CartridgeDASH& operator=(CartridgeDASH&&) = delete; }; #endif stella-5.1.1/src/emucore/CartDF.cxx000066400000000000000000000105201324334165500170630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartDF.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDF::CartridgeDF(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(131072u, size)); createCodeAccessBase(131072); // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDF::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDF::install(System& system) { mySystem = &system; // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDF::peek(uInt16 address) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FC0) && (address <= 0x0FDF)) bank(address - 0x0FC0); return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FC0) && (address <= 0x0FDF)) bank(address - 0x0FC0); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1000; addr < (0x1FC0U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDF::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDF::bankCount() const { return 32; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDF::getImage(uInt32& size) const { size = 131072; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::save(Serializer& out) const { try { out.putString(name()); out.putInt(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeDF::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDF::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getInt(); } catch(...) { cerr << "ERROR: CartridgeDF::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartDF.hxx000066400000000000000000000111541324334165500170740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEDF_HXX #define CARTRIDGEDF_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDFWidget.hxx" #endif /** Update of EF cartridge class used for Homestar Runner by Paul Slocum. There are 32 4K banks (total of 128K ROM). Accessing $1FC0 - $1FDF switches to each bank. @author Mike Saarna */ class CartridgeDF : public Cartridge { friend class CartridgeDFWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeDF(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeDF() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeDF"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeDFWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 128K ROM image of the cartridge uInt8 myImage[32 * 4096]; // Indicates the offset into the ROM image (aligns to current bank) uInt32 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeDF() = delete; CartridgeDF(const CartridgeDF&) = delete; CartridgeDF(CartridgeDF&&) = delete; CartridgeDF& operator=(const CartridgeDF&) = delete; CartridgeDF& operator=(CartridgeDF&&) = delete; }; #endif stella-5.1.1/src/emucore/CartDFSC.cxx000066400000000000000000000137231324334165500173210ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartDFSC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDFSC::CartridgeDFSC(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(131072u, size)); createCodeAccessBase(131072); // Remember startup bank myStartBank = 15; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSC::reset() { initializeRAM(myRAM, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDFSC::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDFSC::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FC0) && (address <= 0x0FDF)) bank(address - 0x0FC0); if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } else return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDFSC::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FC0) && (address <= 0x0FDF)) bank(address - 0x0FC0); // NOTE: This does not handle accessing RAM, however, this method // should never be called for RAM because of the way page accessing // has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDFSC::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FC0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1100; addr < (0x1FC0U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDFSC::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDFSC::bankCount() const { return 32; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDFSC::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0100) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x007F] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDFSC::getImage(uInt32& size) const { size = 131072; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDFSC::save(Serializer& out) const { try { out.putString(name()); out.putInt(myBankOffset); out.putByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeDFSC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDFSC::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getInt(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeDFSC::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartDFSC.hxx000066400000000000000000000113261324334165500173230ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEDFSC_HXX #define CARTRIDGEDFSC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDFSCWidget.hxx" #endif /** There are 32 4K banks (total of 128K ROM) with 128 bytes of RAM. Accessing $1FC0 - $1FDF switches to each bank. RAM read port is $1080 - $10FF, write port is $1000 - $107F. @author Stephen Anthony */ class CartridgeDFSC : public Cartridge { friend class CartridgeDFSCWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeDFSC(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeDFSC() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeDFSC"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeDFSCWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 128K ROM image of the cartridge uInt8 myImage[32 * 4096]; // The 128 bytes of RAM uInt8 myRAM[128]; // Indicates the offset into the ROM image (aligns to current bank) uInt32 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeDFSC() = delete; CartridgeDFSC(const CartridgeDFSC&) = delete; CartridgeDFSC(CartridgeDFSC&&) = delete; CartridgeDFSC& operator=(const CartridgeDFSC&) = delete; CartridgeDFSC& operator=(CartridgeDFSC&&) = delete; }; #endif stella-5.1.1/src/emucore/CartDPC.cxx000066400000000000000000000325511324334165500172100ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartDPC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPC::CartridgeDPC(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), myAudioCycles(0), myFractionalClocks(0.0), myBankOffset(0) { // Make a copy of the entire image memcpy(myImage, image.get(), std::min(size, 8192u + 2048u + 256u)); createCodeAccessBase(8192); // Pointer to the program ROM (8K @ 0 byte offset) myProgramImage = myImage; // Pointer to the display ROM (2K @ 8K offset) myDisplayImage = myProgramImage + 8192; // Initialize the DPC data fetcher registers for(int i = 0; i < 8; ++i) myTops[i] = myBottoms[i] = myCounters[i] = myFlags[i] = 0; // None of the data fetchers are in music mode myMusicMode[0] = myMusicMode[1] = myMusicMode[2] = false; // Initialize the DPC's random number generator register (must be non-zero) myRandomNumber = 1; // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPC::reset() { myAudioCycles = 0; myFractionalClocks = 0.0; // define random startup bank randomizeStartBank(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPC::install(System& system) { mySystem = &system; // Set the page accessing method for the DPC reading & writing pages System::PageAccess access(this, System::PA_READWRITE); for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeDPC::clockRandomNumberGenerator() { // Table for computing the input bit of the random number generator's // shift register (it's the NOT of the EOR of four bits) static constexpr uInt8 f[16] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 }; // Using bits 7, 5, 4, & 3 of the shift register compute the input // bit for the shift register uInt8 bit = f[((myRandomNumber >> 3) & 0x07) | ((myRandomNumber & 0x80) ? 0x08 : 0x00)]; // Update the shift register myRandomNumber = (myRandomNumber << 1) | bit; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeDPC::updateMusicModeDataFetchers() { // Calculate the number of cycles since the last update uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles); myAudioCycles = mySystem->cycles(); // Calculate the number of DPC OSC clocks since the last update double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); if(wholeClocks <= 0) return; // Let's update counters and flags of the music mode data fetchers for(int x = 5; x <= 7; ++x) { // Update only if the data fetcher is in music mode if(myMusicMode[x - 5]) { Int32 top = myTops[x] + 1; Int32 newLow = Int32(myCounters[x] & 0x00ff); if(myTops[x] != 0) { newLow -= (wholeClocks % top); if(newLow < 0) newLow += top; } else newLow = 0; // Update flag register for this data fetcher if(newLow <= myBottoms[x]) myFlags[x] = 0x00; else if(newLow <= myTops[x]) myFlags[x] = 0xff; myCounters[x] = (myCounters[x] & 0x0700) | uInt16(newLow); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDPC::peek(uInt16 address) { address &= 0x0FFF; // In debugger/bank-locked mode, we ignore all hotspots and in general // anything that can change the internal state of the cart if(bankLocked()) return myProgramImage[myBankOffset + address]; // Clock the random number generator. This should be done for every // cartridge access, however, we're only doing it for the DPC and // hot-spot accesses to save time. clockRandomNumberGenerator(); if(address < 0x0040) { uInt8 result = 0; // Get the index of the data fetcher that's being accessed uInt32 index = address & 0x07; uInt32 function = (address >> 3) & 0x07; // Update flag register for selected data fetcher if((myCounters[index] & 0x00ff) == myTops[index]) { myFlags[index] = 0xff; } else if((myCounters[index] & 0x00ff) == myBottoms[index]) { myFlags[index] = 0x00; } switch(function) { case 0x00: { // Is this a random number read if(index < 4) { result = myRandomNumber; } // No, it's a music read else { static constexpr uInt8 musicAmplitudes[8] = { 0x00, 0x04, 0x05, 0x09, 0x06, 0x0a, 0x0b, 0x0f }; // Update the music data fetchers (counter & flag) updateMusicModeDataFetchers(); uInt8 i = 0; if(myMusicMode[0] && myFlags[5]) { i |= 0x01; } if(myMusicMode[1] && myFlags[6]) { i |= 0x02; } if(myMusicMode[2] && myFlags[7]) { i |= 0x04; } result = musicAmplitudes[i]; } break; } // DFx display data read case 0x01: { result = myDisplayImage[2047 - myCounters[index]]; break; } // DFx display data read AND'd w/flag case 0x02: { result = myDisplayImage[2047 - myCounters[index]] & myFlags[index]; break; } // DFx flag case 0x07: { result = myFlags[index]; break; } default: { result = 0; } } // Clock the selected data fetcher's counter if needed if((index < 5) || ((index >= 5) && (!myMusicMode[index - 5]))) { myCounters[index] = (myCounters[index] - 1) & 0x07ff; } return result; } else { // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); break; case 0x0FF9: // Set the current bank to the upper 4k bank bank(1); break; default: break; } return myProgramImage[myBankOffset + address]; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::poke(uInt16 address, uInt8 value) { address &= 0x0FFF; // Clock the random number generator. This should be done for every // cartridge access, however, we're only doing it for the DPC and // hot-spot accesses to save time. clockRandomNumberGenerator(); if((address >= 0x0040) && (address < 0x0080)) { // Get the index of the data fetcher that's being accessed uInt32 index = address & 0x07; uInt32 function = (address >> 3) & 0x07; switch(function) { // DFx top count case 0x00: { myTops[index] = value; myFlags[index] = 0x00; break; } // DFx bottom count case 0x01: { myBottoms[index] = value; break; } // DFx counter low case 0x02: { if((index >= 5) && myMusicMode[index - 5]) { // Data fetcher is in music mode so its low counter value // should be loaded from the top register not the poked value myCounters[index] = (myCounters[index] & 0x0700) | uInt16(myTops[index]); } else { // Data fetcher is either not a music mode data fetcher or it // isn't in music mode so it's low counter value should be loaded // with the poked value myCounters[index] = (myCounters[index] & 0x0700) | uInt16(value); } break; } // DFx counter high case 0x03: { myCounters[index] = ((uInt16(value) & 0x07) << 8) | (myCounters[index] & 0x00ff); // Execute special code for music mode data fetchers if(index >= 5) { myMusicMode[index - 5] = (value & 0x10); // NOTE: We are not handling the clock source input for // the music mode data fetchers. We're going to assume // they always use the OSC input. } break; } // Random Number Generator Reset case 0x06: { myRandomNumber = 1; break; } default: { break; } } } else { // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); break; case 0x0FF9: // Set the current bank to the upper 4k bank bank(1); break; default: break; } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1080; addr < (0x1FF8U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myProgramImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDPC::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDPC::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; // For now, we ignore attempts to patch the DPC address space if(address >= 0x0080) { myProgramImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDPC::getImage(uInt32& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::save(Serializer& out) const { try { out.putString(name()); // Indicates which bank is currently active out.putShort(myBankOffset); // The top registers for the data fetchers out.putByteArray(myTops, 8); // The bottom registers for the data fetchers out.putByteArray(myBottoms, 8); // The counter registers for the data fetchers out.putShortArray(myCounters, 8); // The flag registers for the data fetchers out.putByteArray(myFlags, 8); // The music mode flags for the data fetchers for(int i = 0; i < 3; ++i) out.putBool(myMusicMode[i]); // The random number generator register out.putByte(myRandomNumber); out.putLong(myAudioCycles); out.putDouble(myFractionalClocks); } catch(...) { cerr << "ERROR: CartridgeDPC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPC::load(Serializer& in) { try { if(in.getString() != name()) return false; // Indicates which bank is currently active myBankOffset = in.getShort(); // The top registers for the data fetchers in.getByteArray(myTops, 8); // The bottom registers for the data fetchers in.getByteArray(myBottoms, 8); // The counter registers for the data fetchers in.getShortArray(myCounters, 8); // The flag registers for the data fetchers in.getByteArray(myFlags, 8); // The music mode flags for the data fetchers for(int i = 0; i < 3; ++i) myMusicMode[i] = in.getBool(); // The random number generator register myRandomNumber = in.getByte(); // Get system cycles and fractional clocks myAudioCycles = in.getLong(); myFractionalClocks = in.getDouble(); } catch(...) { cerr << "ERROR: CartridgeDPC::load" << endl; return false; } // Now, go to the current bank bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartDPC.hxx000066400000000000000000000140341324334165500172110ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_DPC_HXX #define CARTRIDGE_DPC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDPCWidget.hxx" #endif /** Cartridge class used for Pitfall II. There are two 4K program banks, a 2K display bank, and the DPC chip. The bankswitching itself is the same as F8 scheme (hotspots at $1FF8 and $1FF9). DPC chip access is mapped to $1000 - $1080 ($1000 - $103F is read port, $1040 - $107F is write port). For complete details on the DPC chip see David P. Crane's United States Patent Number 4,644,495. @author Bradford W. Mott */ class CartridgeDPC : public Cartridge { friend class CartridgeDPCWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeDPC(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeDPC() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeDPC"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeDPCWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Clocks the random number generator to move it to its next state */ void clockRandomNumberGenerator(); /** Updates any data fetchers in music mode based on the number of CPU cycles which have passed since the last update. */ void updateMusicModeDataFetchers(); private: // The ROM image uInt8 myImage[8192 + 2048 + 256]; // (Actual) Size of the ROM image uInt32 mySize; // Pointer to the 8K program ROM image of the cartridge uInt8* myProgramImage; // Pointer to the 2K display ROM image of the cartridge uInt8* myDisplayImage; // The top registers for the data fetchers uInt8 myTops[8]; // The bottom registers for the data fetchers uInt8 myBottoms[8]; // The counter registers for the data fetchers uInt16 myCounters[8]; // The flag registers for the data fetchers uInt8 myFlags[8]; // The music mode DF5, DF6, & DF7 enabled flags bool myMusicMode[3]; // The random number generator register uInt8 myRandomNumber; // System cycle count from when the last update to music data fetchers occurred uInt64 myAudioCycles; // Fractional DPC music OSC clocks unused during the last update double myFractionalClocks; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeDPC() = delete; CartridgeDPC(const CartridgeDPC&) = delete; CartridgeDPC(CartridgeDPC&&) = delete; CartridgeDPC& operator=(const CartridgeDPC&) = delete; CartridgeDPC& operator=(CartridgeDPC&&) = delete; }; #endif stella-5.1.1/src/emucore/CartDPCPlus.cxx000066400000000000000000000511101324334165500200440ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #include "System.hxx" #include "Thumbulator.hxx" #include "CartDPCPlus.hxx" #include "TIA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeDPCPlus::CartridgeDPCPlus(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myFastFetch(false), myLDAimmediate(false), myParameterPointer(0), myAudioCycles(0), myARMCycles(0), myFractionalClocks(0.0), myBankOffset(0) { // Image is always 32K, but in the case of ROM > 29K, the image is // copied to the end of the buffer mySize = std::min(size, 32768u); if(mySize < 32768u) memset(myImage, 0, 32768); memcpy(myImage + (32768u - mySize), image.get(), size); createCodeAccessBase(4096 * 6); // Pointer to the program ROM (24K @ 3072 byte offset; ignore first 3K) myProgramImage = myImage + 0xC00; // Pointer to the display RAM myDisplayImage = myDPCRAM + 0xC00; // Pointer to the Frequency RAM myFrequencyImage = myDisplayImage + 0x1000; // Create Thumbulator ARM emulator myThumbEmulator = make_unique (reinterpret_cast(myImage), reinterpret_cast(myDPCRAM), settings.getBool("thumb.trapfatal"), Thumbulator::ConfigureFor::DPCplus, this); setInitialState(); // DPC+ always starts in bank 5 myStartBank = 5; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlus::reset() { myAudioCycles = myARMCycles = 0; myFractionalClocks = 0.0; setInitialState(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlus::setInitialState() { // Reset various ROM and RAM locations memset(myDPCRAM, 0, 8192); // Copy initial DPC display data and Frequency table state to Harmony RAM memcpy(myDisplayImage, myProgramImage + 0x6000, 0x1400); // Initialize the DPC data fetcher registers for(int i = 0; i < 8; ++i) myTops[i] = myBottoms[i] = myCounters[i] = myFractionalIncrements[i] = myFractionalCounters[i] = 0; // Set waveforms to first waveform entry myMusicWaveforms[0] = myMusicWaveforms[1] = myMusicWaveforms[2] = 0; // Initialize the DPC's random number generator register (must be non-zero) myRandomNumber = 0x2B435044; // "DPC+" } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlus::consoleChanged(ConsoleTiming timing) { myThumbEmulator->setConsoleTiming(timing); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeDPCPlus::install(System& system) { mySystem = &system; // Map all of the accesses to call peek and poke System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeDPCPlus::clockRandomNumberGenerator() { // Update random number generator (32-bit LFSR) myRandomNumber = ((myRandomNumber & (1<<10)) ? 0x10adab1e: 0x00) ^ ((myRandomNumber >> 11) | (myRandomNumber << 21)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeDPCPlus::priorClockRandomNumberGenerator() { // Update random number generator (32-bit LFSR, reversed) myRandomNumber = ((myRandomNumber & (1u<<31)) ? ((0x10adab1e^myRandomNumber) << 11) | ((0x10adab1e^myRandomNumber) >> 21) : (myRandomNumber << 11) | (myRandomNumber >> 21)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeDPCPlus::updateMusicModeDataFetchers() { // Calculate the number of cycles since the last update uInt32 cycles = uInt32(mySystem->cycles() - myAudioCycles); myAudioCycles = mySystem->cycles(); // Calculate the number of DPC+ OSC clocks since the last update double clocks = ((20000.0 * cycles) / 1193191.66666667) + myFractionalClocks; uInt32 wholeClocks = uInt32(clocks); myFractionalClocks = clocks - double(wholeClocks); // Let's update counters and flags of the music mode data fetchers if(wholeClocks > 0) for(int x = 0; x <= 2; ++x) myMusicCounters[x] += myMusicFrequencies[x] * wholeClocks; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void CartridgeDPCPlus::callFunction(uInt8 value) { // myParameter uInt16 ROMdata = (myParameter[1] << 8) + myParameter[0]; switch (value) { case 0: // Parameter Pointer reset myParameterPointer = 0; break; case 1: // Copy ROM to fetcher for(int i = 0; i < myParameter[3]; ++i) myDisplayImage[myCounters[myParameter[2] & 0x7]+i] = myProgramImage[ROMdata+i]; myParameterPointer = 0; break; case 2: // Copy value to fetcher for(int i = 0; i < myParameter[3]; ++i) myDisplayImage[myCounters[myParameter[2]]+i] = myParameter[0]; myParameterPointer = 0; break; // Call user written ARM code (most likely be C compiled for ARM) case 254: // call with IRQ driven audio, no special handling needed at this // time for Stella as ARM code "runs in zero 6507 cycles". case 255: // call without IRQ driven audio try { Int32 cycles = Int32(mySystem->cycles() - myARMCycles); myARMCycles = mySystem->cycles(); myThumbEmulator->run(cycles); } catch(const runtime_error& e) { if(!mySystem->autodetectMode()) { #ifdef DEBUGGER_SUPPORT Debugger::debugger().startWithFatalError(e.what()); #else cout << e.what() << endl; #endif } } break; // reserved } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeDPCPlus::peek(uInt16 address) { address &= 0x0FFF; uInt8 peekvalue = myProgramImage[myBankOffset + address]; uInt8 flag; // In debugger/bank-locked mode, we ignore all hotspots and in general // anything that can change the internal state of the cart if(bankLocked()) return peekvalue; // Check if we're in Fast Fetch mode and the prior byte was an A9 (LDA #value) if(myFastFetch && myLDAimmediate) { if(peekvalue < 0x0028) // if #value is a read-register then we want to use that as the address address = peekvalue; } myLDAimmediate = false; if(address < 0x0028) { uInt8 result = 0; // Get the index of the data fetcher that's being accessed uInt32 index = address & 0x07; uInt32 function = (address >> 3) & 0x07; // Update flag for selected data fetcher flag = (((myTops[index]-(myCounters[index] & 0x00ff)) & 0xFF) > ((myTops[index]-myBottoms[index]) & 0xFF)) ? 0xFF : 0; switch(function) { case 0x00: { switch(index) { case 0x00: // RANDOM0NEXT - advance and return byte 0 of random clockRandomNumberGenerator(); result = myRandomNumber & 0xFF; break; case 0x01: // RANDOM0PRIOR - return to prior and return byte 0 of random priorClockRandomNumberGenerator(); result = myRandomNumber & 0xFF; break; case 0x02: // RANDOM1 result = (myRandomNumber>>8) & 0xFF; break; case 0x03: // RANDOM2 result = (myRandomNumber>>16) & 0xFF; break; case 0x04: // RANDOM3 result = (myRandomNumber>>24) & 0xFF; break; case 0x05: // AMPLITUDE { // Update the music data fetchers (counter & flag) updateMusicModeDataFetchers(); // using myDisplayImage[] instead of myProgramImage[] because waveforms // can be modified during runtime. uInt32 i = myDisplayImage[(myMusicWaveforms[0] << 5) + (myMusicCounters[0] >> 27)] + myDisplayImage[(myMusicWaveforms[1] << 5) + (myMusicCounters[1] >> 27)] + myDisplayImage[(myMusicWaveforms[2] << 5) + (myMusicCounters[2] >> 27)]; result = uInt8(i); break; } case 0x06: // reserved case 0x07: // reserved break; } break; } // DFxDATA - display data read case 0x01: { result = myDisplayImage[myCounters[index]]; myCounters[index] = (myCounters[index] + 0x1) & 0x0fff; break; } // DFxDATAW - display data read AND'd w/flag ("windowed") case 0x02: { result = myDisplayImage[myCounters[index]] & flag; myCounters[index] = (myCounters[index] + 0x1) & 0x0fff; break; } // DFxFRACDATA - display data read w/fractional increment case 0x03: { result = myDisplayImage[myFractionalCounters[index] >> 8]; myFractionalCounters[index] = (myFractionalCounters[index] + myFractionalIncrements[index]) & 0x0fffff; break; } case 0x04: { switch (index) { case 0x00: // DF0FLAG case 0x01: // DF1FLAG case 0x02: // DF2FLAG case 0x03: // DF3FLAG { result = flag; break; } case 0x04: // reserved case 0x05: // reserved case 0x06: // reserved case 0x07: // reserved break; } break; } default: { result = 0; } } return result; } else { // Switch banks if necessary switch(address) { case 0x0FF6: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF7: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF8: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF9: // Set the current bank to the fourth 4k bank bank(3); break; case 0x0FFA: // Set the current bank to the fifth 4k bank bank(4); break; case 0x0FFB: // Set the current bank to the last 4k bank bank(5); break; default: break; } if(myFastFetch) myLDAimmediate = (peekvalue == 0xA9); return peekvalue; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPCPlus::poke(uInt16 address, uInt8 value) { address &= 0x0FFF; if((address >= 0x0028) && (address < 0x0080)) { // Get the index of the data fetcher that's being accessed uInt32 index = address & 0x07; uInt32 function = ((address - 0x28) >> 3) & 0x0f; switch(function) { //DFxFRACLOW - fractional data pointer low byte case 0x00: myFractionalCounters[index] = (myFractionalCounters[index] & 0x0F00FF) | (uInt16(value) << 8); break; // DFxFRACHI - fractional data pointer high byte case 0x01: myFractionalCounters[index] = ((uInt16(value) & 0x0F) << 16) | (myFractionalCounters[index] & 0x00ffff); break; //DFxFRACINC - Fractional Increment amount case 0x02: myFractionalIncrements[index] = value; myFractionalCounters[index] = myFractionalCounters[index] & 0x0FFF00; break; // DFxTOP - set top of window (for reads of DFxDATAW) case 0x03: myTops[index] = value; break; // DFxBOT - set bottom of window (for reads of DFxDATAW) case 0x04: myBottoms[index] = value; break; // DFxLOW - data pointer low byte case 0x05: myCounters[index] = (myCounters[index] & 0x0F00) | value ; break; // Control registers case 0x06: switch (index) { case 0x00: // FASTFETCH - turns on LDA #setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDPCPlus::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeDPCPlus::bankCount() const { return 6; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPCPlus::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; // For now, we ignore attempts to patch the DPC address space if(address >= 0x0080) { myProgramImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeDPCPlus::getImage(uInt32& size) const { size = mySize; return myImage + (32768u - mySize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPCPlus::save(Serializer& out) const { try { out.putString(name()); // Indicates which bank is currently active out.putShort(myBankOffset); // Harmony RAM out.putByteArray(myDPCRAM, 8192); // The top registers for the data fetchers out.putByteArray(myTops, 8); // The bottom registers for the data fetchers out.putByteArray(myBottoms, 8); // The counter registers for the data fetchers out.putShortArray(myCounters, 8); // The counter registers for the fractional data fetchers out.putIntArray(myFractionalCounters, 8); // The fractional registers for the data fetchers out.putByteArray(myFractionalIncrements, 8); // The Fast Fetcher Enabled flag out.putBool(myFastFetch); out.putBool(myLDAimmediate); // Control Byte to update out.putByteArray(myParameter, 8); // The music counters out.putIntArray(myMusicCounters, 3); // The music frequencies out.putIntArray(myMusicFrequencies, 3); // The music waveforms out.putShortArray(myMusicWaveforms, 3); // The random number generator register out.putInt(myRandomNumber); // Get system cycles and fractional clocks out.putLong(myAudioCycles); out.putDouble(myFractionalClocks); // Clock info for Thumbulator out.putLong(myARMCycles); } catch(...) { cerr << "ERROR: CartridgeDPCPlus::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeDPCPlus::load(Serializer& in) { try { if(in.getString() != name()) return false; // Indicates which bank is currently active myBankOffset = in.getShort(); // Harmony RAM in.getByteArray(myDPCRAM, 8192); // The top registers for the data fetchers in.getByteArray(myTops, 8); // The bottom registers for the data fetchers in.getByteArray(myBottoms, 8); // The counter registers for the data fetchers in.getShortArray(myCounters, 8); // The counter registers for the fractional data fetchers in.getIntArray(myFractionalCounters, 8); // The fractional registers for the data fetchers in.getByteArray(myFractionalIncrements, 8); // The Fast Fetcher Enabled flag myFastFetch = in.getBool(); myLDAimmediate = in.getBool(); // Control Byte to update in.getByteArray(myParameter, 8); // The music mode counters for the data fetchers in.getIntArray(myMusicCounters, 3); // The music mode frequency addends for the data fetchers in.getIntArray(myMusicFrequencies, 3); // The music waveforms in.getShortArray(myMusicWaveforms, 3); // The random number generator register myRandomNumber = in.getInt(); // Get audio cycles and fractional clocks myAudioCycles = in.getLong(); myFractionalClocks = in.getDouble(); // Clock info for Thumbulator myARMCycles = in.getLong(); } catch(...) { cerr << "ERROR: CartridgeDPCPlus::load" << endl; return false; } // Now, go to the current bank bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartDPCPlus.hxx000066400000000000000000000173231324334165500200610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_DPC_PLUS_HXX #define CARTRIDGE_DPC_PLUS_HXX class System; #include "Thumbulator.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDPCPlusWidget.hxx" #endif #include "bspf.hxx" #include "Cart.hxx" /** Cartridge class used for DPC+, derived from Pitfall II. There are six 4K program banks, a 4K display bank, 1K frequency table and the DPC chip. DPC chip access is mapped to $1000 - $1080 ($1000 - $103F is read port, $1040 - $107F is write port). Program banks are accessible by read/write to $1FF6 - $1FFB. FIXME: THIS NEEDS TO BE UPDATED For complete details on the DPC chip see David P. Crane's United States Patent Number 4,644,495. @authors Darrell Spice Jr, Fred Quimby, Stephen Anthony, Bradford W. Mott */ class CartridgeDPCPlus : public Cartridge { friend class CartridgeDPCPlusWidget; friend class CartridgeRamDPCPlusWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeDPCPlus(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeDPCPlus() = default; public: /** Reset device to its power-on state */ void reset() override; /** Notification method invoked by the system when the console type has changed. We need this to inform the Thumbulator that the timing has changed. @param timing Enum representing the new console type */ void consoleChanged(ConsoleTiming timing) override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeDPC+"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeDPCPlusWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Sets the initial state of the DPC pointers and RAM */ void setInitialState(); /** Clocks the random number generator to move it to its next state */ void clockRandomNumberGenerator(); /** Clocks the random number generator to move it to its prior state */ void priorClockRandomNumberGenerator(); /** Updates any data fetchers in music mode based on the number of CPU cycles which have passed since the last update. */ void updateMusicModeDataFetchers(); /** Call Special Functions */ void callFunction(uInt8 value); private: // The ROM image and size uInt8 myImage[32768]; uInt32 mySize; // Pointer to the 24K program ROM image of the cartridge uInt8* myProgramImage; // Pointer to the 4K display ROM image of the cartridge uInt8* myDisplayImage; // The DPC 8k RAM image, used as: // 3K DPC+ driver // 4K Display Data // 1K Frequency Data uInt8 myDPCRAM[8192]; // Pointer to the Thumb ARM emulator object unique_ptr myThumbEmulator; // Pointer to the 1K frequency table uInt8* myFrequencyImage; // The top registers for the data fetchers uInt8 myTops[8]; // The bottom registers for the data fetchers uInt8 myBottoms[8]; // The counter registers for the data fetchers uInt16 myCounters[8]; // The counter registers for the fractional data fetchers uInt32 myFractionalCounters[8]; // The fractional increments for the data fetchers uInt8 myFractionalIncrements[8]; // The Fast Fetcher Enabled flag bool myFastFetch; // Flags that last byte peeked was A9 (LDA #) bool myLDAimmediate; // Parameter for special functions uInt8 myParameter[8]; // Parameter pointer for special functions uInt8 myParameterPointer; // The music mode counters uInt32 myMusicCounters[3]; // The music frequency uInt32 myMusicFrequencies[3]; // The music waveforms uInt16 myMusicWaveforms[3]; // The random number generator register uInt32 myRandomNumber; // System cycle count from when the last update to music data fetchers occurred uInt64 myAudioCycles; // System cycle count when the last Thumbulator::run() occurred uInt64 myARMCycles; // Fractional DPC music OSC clocks unused during the last update double myFractionalClocks; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeDPCPlus() = delete; CartridgeDPCPlus(const CartridgeDPCPlus&) = delete; CartridgeDPCPlus(CartridgeDPCPlus&&) = delete; CartridgeDPCPlus& operator=(const CartridgeDPCPlus&) = delete; CartridgeDPCPlus& operator=(CartridgeDPCPlus&&) = delete; }; #endif stella-5.1.1/src/emucore/CartDetector.cxx000066400000000000000000000772021324334165500203550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Cart.hxx" #include "Cart0840.hxx" #include "Cart2K.hxx" #include "Cart3E.hxx" #include "Cart3EPlus.hxx" #include "Cart3F.hxx" #include "Cart4A50.hxx" #include "Cart4K.hxx" #include "Cart4KSC.hxx" #include "CartAR.hxx" #include "CartBUS.hxx" #include "CartCDF.hxx" #include "CartCM.hxx" #include "CartCTY.hxx" #include "CartCV.hxx" #include "CartCVPlus.hxx" #include "CartDASH.hxx" #include "CartDPC.hxx" #include "CartDPCPlus.hxx" #include "CartE0.hxx" #include "CartE7.hxx" #include "CartE78K.hxx" #include "CartEF.hxx" #include "CartEFSC.hxx" #include "CartBF.hxx" #include "CartBFSC.hxx" #include "CartDF.hxx" #include "CartDFSC.hxx" #include "CartF0.hxx" #include "CartF4.hxx" #include "CartF4SC.hxx" #include "CartF6.hxx" #include "CartF6SC.hxx" #include "CartF8.hxx" #include "CartF8SC.hxx" #include "CartFA.hxx" #include "CartFA2.hxx" #include "CartFE.hxx" #include "CartMDM.hxx" #include "CartSB.hxx" #include "CartUA.hxx" #include "CartWD.hxx" #include "CartX07.hxx" #include "MD5.hxx" #include "Props.hxx" #include "Settings.hxx" #include "CartDetector.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unique_ptr CartDetector::create(const BytePtr& image, uInt32 size, string& md5, const string& propertiesType, const OSystem& osystem) { unique_ptr cartridge; BSType type = Bankswitch::nameToType(propertiesType), detectedType = type; string id; // Collect some info about the ROM ostringstream buf; // See if we should try to auto-detect the cartridge type // If we ask for extended info, always do an autodetect if(type == BSType::_AUTO || osystem.settings().getBool("rominfo")) { detectedType = autodetectType(image, size); if(type != BSType::_AUTO && type != detectedType) cerr << "Auto-detection not consistent: " << Bankswitch::typeToName(type) << ", " << Bankswitch::typeToName(detectedType) << endl; type = detectedType; buf << Bankswitch::typeToName(type) << "*"; } else buf << Bankswitch::typeToName(type); // Check for multicart first; if found, get the correct part of the image switch(type) { case BSType::_2IN1: // Make sure we have a valid sized image if(size == 2*2048 || size == 2*4096 || size == 2*8192 || size == 2*16384) { cartridge = createFromMultiCart(image, size, 2, md5, detectedType, id, osystem); buf << id; } else throw runtime_error("Invalid cart size for type '" + Bankswitch::typeToName(type) + "'"); break; case BSType::_4IN1: // Make sure we have a valid sized image if(size == 4*2048 || size == 4*4096 || size == 4*8192) { cartridge = createFromMultiCart(image, size, 4, md5, detectedType, id, osystem); buf << id; } else throw runtime_error("Invalid cart size for type '" + Bankswitch::typeToName(type) + "'"); break; case BSType::_8IN1: // Make sure we have a valid sized image if(size == 8*2048 || size == 8*4096 || size == 8*8192) { cartridge = createFromMultiCart(image, size, 8, md5, detectedType, id, osystem); buf << id; } else throw runtime_error("Invalid cart size for type '" + Bankswitch::typeToName(type) + "'"); break; case BSType::_16IN1: // Make sure we have a valid sized image if(size == 16*2048 || size == 16*4096 || size == 16*8192) { cartridge = createFromMultiCart(image, size, 16, md5, detectedType, id, osystem); buf << id; } else throw runtime_error("Invalid cart size for type '" + Bankswitch::typeToName(type) + "'"); break; case BSType::_32IN1: // Make sure we have a valid sized image if(size == 32*2048 || size == 32*4096) { cartridge = createFromMultiCart(image, size, 32, md5, detectedType, id, osystem); buf << id; } else throw runtime_error("Invalid cart size for type '" + Bankswitch::typeToName(type) + "'"); break; case BSType::_64IN1: // Make sure we have a valid sized image if(size == 64*2048 || size == 64*4096) { cartridge = createFromMultiCart(image, size, 64, md5, detectedType, id, osystem); buf << id; } else throw runtime_error("Invalid cart size for type '" + Bankswitch::typeToName(type) + "'"); break; case BSType::_128IN1: // Make sure we have a valid sized image if(size == 128*2048 || size == 128*4096) { cartridge = createFromMultiCart(image, size, 128, md5, detectedType, id, osystem); buf << id; } else throw runtime_error("Invalid cart size for type '" + Bankswitch::typeToName(type) + "'"); break; default: cartridge = createFromImage(image, size, detectedType, md5, osystem); break; } if(size < 1024) buf << " (" << size << "B) "; else buf << " (" << (size/1024) << "K) "; cartridge->setAbout(buf.str(), Bankswitch::typeToName(type), id); return cartridge; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unique_ptr CartDetector::createFromMultiCart(const BytePtr& image, uInt32& size, uInt32 numroms, string& md5, BSType type, string& id, const OSystem& osystem) { // Get a piece of the larger image uInt32 i = osystem.settings().getInt("romloadcount"); size /= numroms; BytePtr slice = make_unique(size); memcpy(slice.get(), image.get()+i*size, size); // We need a new md5 and name md5 = MD5::hash(slice, size); ostringstream buf; buf << " [G" << (i+1) << "]"; id = buf.str(); // Move to the next game the next time this ROM is loaded osystem.settings().setValue("romloadcount", (i+1)%numroms); if(size <= 2048) type = BSType::_2K; else if(size == 4096) type = BSType::_4K; else if(size == 8192) type = BSType::_F8; else /* default */ type = BSType::_4K; return createFromImage(slice, size, type, md5, osystem); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unique_ptr CartDetector::createFromImage(const BytePtr& image, uInt32 size, BSType type, const string& md5, const OSystem& osystem) { // We should know the cart's type by now so let's create it switch(type) { case BSType::_0840: return make_unique(image, size, osystem.settings()); case BSType::_2K: return make_unique(image, size, osystem.settings()); case BSType::_3E: return make_unique(image, size, osystem.settings()); case BSType::_3EP: return make_unique(image, size, osystem.settings()); case BSType::_3F: return make_unique(image, size, osystem.settings()); case BSType::_4A50: return make_unique(image, size, osystem.settings()); case BSType::_4K: return make_unique(image, size, osystem.settings()); case BSType::_4KSC: return make_unique(image, size, osystem.settings()); case BSType::_AR: return make_unique(image, size, osystem.settings()); case BSType::_BUS: return make_unique(image, size, osystem.settings()); case BSType::_CDF: return make_unique(image, size, osystem.settings()); case BSType::_CM: return make_unique(image, size, osystem.settings()); case BSType::_CTY: return make_unique(image, size, osystem); case BSType::_CV: return make_unique(image, size, osystem.settings()); case BSType::_CVP: return make_unique(image, size, osystem.settings()); case BSType::_DASH: return make_unique(image, size, osystem.settings()); case BSType::_DPC: return make_unique(image, size, osystem.settings()); case BSType::_DPCP: return make_unique(image, size, osystem.settings()); case BSType::_E0: return make_unique(image, size, osystem.settings()); case BSType::_E7: return make_unique(image, size, osystem.settings()); case BSType::_E78K: return make_unique(image, size, osystem.settings()); case BSType::_EF: return make_unique(image, size, osystem.settings()); case BSType::_EFSC: return make_unique(image, size, osystem.settings()); case BSType::_BF: return make_unique(image, size, osystem.settings()); case BSType::_BFSC: return make_unique(image, size, osystem.settings()); case BSType::_DF: return make_unique(image, size, osystem.settings()); case BSType::_DFSC: return make_unique(image, size, osystem.settings()); case BSType::_F0: return make_unique(image, size, osystem.settings()); case BSType::_F4: return make_unique(image, size, osystem.settings()); case BSType::_F4SC: return make_unique(image, size, osystem.settings()); case BSType::_F6: return make_unique(image, size, osystem.settings()); case BSType::_F6SC: return make_unique(image, size, osystem.settings()); case BSType::_F8: return make_unique(image, size, md5, osystem.settings()); case BSType::_F8SC: return make_unique(image, size, osystem.settings()); case BSType::_FA: return make_unique(image, size, osystem.settings()); case BSType::_FA2: return make_unique(image, size, osystem); case BSType::_FE: return make_unique(image, size, osystem.settings()); case BSType::_MDM: return make_unique(image, size, osystem.settings()); case BSType::_UA: return make_unique(image, size, osystem.settings()); case BSType::_SB: return make_unique(image, size, osystem.settings()); case BSType::_WD: return make_unique(image, size, osystem.settings()); case BSType::_X07: return make_unique(image, size, osystem.settings()); default: return nullptr; // The remaining types have already been handled } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BSType CartDetector::autodetectType(const BytePtr& image, uInt32 size) { // Guess type based on size BSType type = BSType::_AUTO; if(isProbablyCVPlus(image,size)) { type = BSType::_CVP; } else if((size % 8448) == 0 || size == 6144) { type = BSType::_AR; } else if(size < 2048) // Sub2K images { type = BSType::_2K; } else if((size == 2048) || (size == 4096 && memcmp(image.get(), image.get() + 2048, 2048) == 0)) { type = isProbablyCV(image, size) ? BSType::_CV : BSType::_2K; } else if(size == 4096) { if(isProbablyCV(image, size)) type = BSType::_CV; else if(isProbably4KSC(image, size)) type = BSType::_4KSC; else type = BSType::_4K; } else if(size == 8*1024) // 8K { // First check for *potential* F8 uInt8 signature[] = { 0x8D, 0xF9, 0x1F }; // STA $1FF9 bool f8 = searchForBytes(image.get(), size, signature, 3, 2); if(isProbablySC(image, size)) type = BSType::_F8SC; else if(memcmp(image.get(), image.get() + 4096, 4096) == 0) type = BSType::_4K; else if(isProbablyE0(image, size)) type = BSType::_E0; else if(isProbably3E(image, size)) type = BSType::_3E; else if(isProbably3F(image, size)) type = BSType::_3F; else if(isProbablyUA(image, size)) type = BSType::_UA; else if(isProbablyFE(image, size) && !f8) type = BSType::_FE; else if(isProbably0840(image, size)) type = BSType::_0840; else if(isProbablyE78K(image, size)) type = BSType::_E78K; else type = BSType::_F8; } else if(size == 8*1024 + 3) // 8195 bytes (Experimental) { type = BSType::_WD; } else if(size >= 10240 && size <= 10496) // ~10K - Pitfall2 { type = BSType::_DPC; } else if(size == 12*1024) // 12K { type = BSType::_FA; } else if(size == 16*1024) // 16K { if(isProbablySC(image, size)) type = BSType::_F6SC; else if(isProbablyE7(image, size)) type = BSType::_E7; else if(isProbably3E(image, size)) type = BSType::_3E; /* no known 16K 3F ROMS else if(isProbably3F(image, size)) type = BSType::_3F; */ else type = BSType::_F6; } else if(size == 24*1024 || size == 28*1024) // 24K & 28K { type = BSType::_FA2; } else if(size == 29*1024) // 29K { if(isProbablyARM(image, size)) type = BSType::_FA2; else /*if(isProbablyDPCplus(image, size))*/ type = BSType::_DPCP; } else if(size == 32*1024) // 32K { if(isProbablySC(image, size)) type = BSType::_F4SC; else if(isProbably3E(image, size)) type = BSType::_3E; else if(isProbably3F(image, size)) type = BSType::_3F; else if (isProbablyBUS(image, size)) type = BSType::_BUS; else if (isProbablyCDF(image, size)) type = BSType::_CDF; else if(isProbablyDPCplus(image, size)) type = BSType::_DPCP; else if(isProbablyCTY(image, size)) type = BSType::_CTY; else if(isProbablyFA2(image, size)) type = BSType::_FA2; else type = BSType::_F4; } else if(size == 64*1024) // 64K { if(isProbably3E(image, size)) type = BSType::_3E; else if(isProbably3F(image, size)) type = BSType::_3F; else if(isProbably4A50(image, size)) type = BSType::_4A50; else if(isProbablyEF(image, size, type)) ; // type has been set directly in the function else if(isProbablyX07(image, size)) type = BSType::_X07; else type = BSType::_F0; } else if(size == 128*1024) // 128K { if(isProbably3E(image, size)) type = BSType::_3E; else if(isProbablyDF(image, size, type)) ; // type has been set directly in the function else if(isProbably3F(image, size)) type = BSType::_3F; else if(isProbably4A50(image, size)) type = BSType::_4A50; else if(isProbablySB(image, size)) type = BSType::_SB; } else if(size == 256*1024) // 256K { if(isProbably3E(image, size)) type = BSType::_3E; else if(isProbablyBF(image, size, type)) ; // type has been set directly in the function else if(isProbably3F(image, size)) type = BSType::_3F; else /*if(isProbablySB(image, size))*/ type = BSType::_SB; } else // what else can we do? { if(isProbably3E(image, size)) type = BSType::_3E; else if(isProbably3F(image, size)) type = BSType::_3F; else type = BSType::_4K; // Most common bankswitching type } // Variable sized ROM formats are independent of image size and come last if(isProbablyDASH(image, size)) type = BSType::_DASH; else if(isProbably3EPlus(image, size)) type = BSType::_3EP; else if(isProbablyMDM(image, size)) type = BSType::_MDM; return type; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::searchForBytes(const uInt8* image, uInt32 imagesize, const uInt8* signature, uInt32 sigsize, uInt32 minhits) { uInt32 count = 0; for(uInt32 i = 0; i < imagesize - sigsize; ++i) { uInt32 matches = 0; for(uInt32 j = 0; j < sigsize; ++j) { if(image[i+j] == signature[j]) ++matches; else break; } if(matches == sigsize) { ++count; i += sigsize; // skip past this signature 'window' entirely } if(count >= minhits) break; } return (count >= minhits); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablySC(const BytePtr& image, uInt32 size) { // We assume a Superchip cart repeats the first 128 bytes for the second // 128 bytes in the RAM area, which is the first 256 bytes of each 4K bank const uInt8* ptr = image.get(); while(size) { if(memcmp(ptr, ptr + 128, 128) != 0) return false; ptr += 4096; size -= 4096; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbably4KSC(const BytePtr& image, uInt32 size) { // We check if the first 256 bytes are identical *and* if there's // an "SC" signature for one of our larger SC types at 1FFA. uInt8 first = image[0]; for(uInt32 i = 1; i < 256; ++i) if(image[i] != first) return false; if((image[size-6]=='S') && (image[size-5]=='C')) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyARM(const BytePtr& image, uInt32 size) { // ARM code contains the following 'loader' patterns in the first 1K // Thanks to Thomas Jentzsch of AtariAge for this advice uInt8 signature[2][4] = { { 0xA0, 0xC1, 0x1F, 0xE0 }, { 0x00, 0x80, 0x02, 0xE0 } }; if(searchForBytes(image.get(), std::min(size, 1024u), signature[0], 4, 1)) return true; else return searchForBytes(image.get(), std::min(size, 1024u), signature[1], 4, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbably0840(const BytePtr& image, uInt32 size) { // 0840 cart bankswitching is triggered by accessing addresses 0x0800 // or 0x0840 at least twice uInt8 signature1[3][3] = { { 0xAD, 0x00, 0x08 }, // LDA $0800 { 0xAD, 0x40, 0x08 }, // LDA $0840 { 0x2C, 0x00, 0x08 } // BIT $0800 }; for(uInt32 i = 0; i < 3; ++i) if(searchForBytes(image.get(), size, signature1[i], 3, 2)) return true; uInt8 signature2[2][4] = { { 0x0C, 0x00, 0x08, 0x4C }, // NOP $0800; JMP ... { 0x0C, 0xFF, 0x0F, 0x4C } // NOP $0FFF; JMP ... }; for(uInt32 i = 0; i < 2; ++i) if(searchForBytes(image.get(), size, signature2[i], 4, 2)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbably3E(const BytePtr& image, uInt32 size) { // 3E cart bankswitching is triggered by storing the bank number // in address 3E using 'STA $3E', commonly followed by an // immediate mode LDA uInt8 signature[] = { 0x85, 0x3E, 0xA9, 0x00 }; // STA $3E; LDA #$00 return searchForBytes(image.get(), size, signature, 4, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbably3EPlus(const BytePtr& image, uInt32 size) { // 3E+ cart is identified key 'TJ3E' in the ROM uInt8 signature[] = { 'T', 'J', '3', 'E' }; return searchForBytes(image.get(), size, signature, 4, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbably3F(const BytePtr& image, uInt32 size) { // 3F cart bankswitching is triggered by storing the bank number // in address 3F using 'STA $3F' // We expect it will be present at least 2 times, since there are // at least two banks uInt8 signature[] = { 0x85, 0x3F }; // STA $3F return searchForBytes(image.get(), size, signature, 2, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbably4A50(const BytePtr& image, uInt32 size) { // 4A50 carts store address $4A50 at the NMI vector, which // in this scheme is always in the last page of ROM at // $1FFA - $1FFB (at least this is true in rev 1 of the format) if(image[size-6] == 0x50 && image[size-5] == 0x4A) return true; // Program starts at $1Fxx with NOP $6Exx or NOP $6Fxx? if(((image[0xfffd] & 0x1f) == 0x1f) && (image[image[0xfffd] * 256 + image[0xfffc]] == 0x0c) && ((image[image[0xfffd] * 256 + image[0xfffc] + 2] & 0xfe) == 0x6e)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyCTY(const BytePtr&, uInt32) { return false; // TODO - add autodetection } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyCV(const BytePtr& image, uInt32 size) { // CV RAM access occurs at addresses $f3ff and $f400 // These signatures are attributed to the MESS project uInt8 signature[2][3] = { { 0x9D, 0xFF, 0xF3 }, // STA $F3FF.X { 0x99, 0x00, 0xF4 } // STA $F400.Y }; if(searchForBytes(image.get(), size, signature[0], 3, 1)) return true; else return searchForBytes(image.get(), size, signature[1], 3, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyCVPlus(const BytePtr& image, uInt32) { // CV+ cart is identified key 'commavidplus' @ $04 in the ROM // We inspect only this area to speed up the search uInt8 signature[12] = { 'c', 'o', 'm', 'm', 'a', 'v', 'i', 'd', 'p', 'l', 'u', 's' }; return searchForBytes(image.get()+4, 24, signature, 12, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyDASH(const BytePtr& image, uInt32 size) { // DASH cart is identified key 'TJAD' in the ROM uInt8 signature[] = { 'T', 'J', 'A', 'D' }; return searchForBytes(image.get(), size, signature, 4, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyDPCplus(const BytePtr& image, uInt32 size) { // DPC+ ARM code has 2 occurrences of the string DPC+ // Note: all Harmony/Melody custom drivers also contain the value // 0x10adab1e (LOADABLE) if needed for future improvement uInt8 signature[] = { 'D', 'P', 'C', '+' }; return searchForBytes(image.get(), size, signature, 4, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyE0(const BytePtr& image, uInt32 size) { // E0 cart bankswitching is triggered by accessing addresses // $FE0 to $FF9 using absolute non-indexed addressing // To eliminate false positives (and speed up processing), we // search for only certain known signatures // Thanks to "stella@casperkitty.com" for this advice // These signatures are attributed to the MESS project uInt8 signature[8][3] = { { 0x8D, 0xE0, 0x1F }, // STA $1FE0 { 0x8D, 0xE0, 0x5F }, // STA $5FE0 { 0x8D, 0xE9, 0xFF }, // STA $FFE9 { 0x0C, 0xE0, 0x1F }, // NOP $1FE0 { 0xAD, 0xE0, 0x1F }, // LDA $1FE0 { 0xAD, 0xE9, 0xFF }, // LDA $FFE9 { 0xAD, 0xED, 0xFF }, // LDA $FFED { 0xAD, 0xF3, 0xBF } // LDA $BFF3 }; for(uInt32 i = 0; i < 8; ++i) if(searchForBytes(image.get(), size, signature[i], 3, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyE7(const BytePtr& image, uInt32 size) { // E7 cart bankswitching is triggered by accessing addresses // $FE0 to $FE6 using absolute non-indexed addressing // To eliminate false positives (and speed up processing), we // search for only certain known signatures // Thanks to "stella@casperkitty.com" for this advice // These signatures are attributed to the MESS project uInt8 signature[7][3] = { { 0xAD, 0xE2, 0xFF }, // LDA $FFE2 { 0xAD, 0xE5, 0xFF }, // LDA $FFE5 { 0xAD, 0xE5, 0x1F }, // LDA $1FE5 { 0xAD, 0xE7, 0x1F }, // LDA $1FE7 { 0x0C, 0xE7, 0x1F }, // NOP $1FE7 { 0x8D, 0xE7, 0xFF }, // STA $FFE7 { 0x8D, 0xE7, 0x1F } // STA $1FE7 }; for(uInt32 i = 0; i < 7; ++i) if(searchForBytes(image.get(), size, signature[i], 3, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyE78K(const BytePtr& image, uInt32 size) { // E78K cart bankswitching is triggered by accessing addresses // $FE4 to $FE6 using absolute non-indexed addressing // To eliminate false positives (and speed up processing), we // search for only certain known signatures uInt8 signature[3][3] = { { 0xAD, 0xE4, 0xFF }, // LDA $FFE4 { 0xAD, 0xE5, 0xFF }, // LDA $FFE5 { 0xAD, 0xE6, 0xFF }, // LDA $FFE6 }; for(uInt32 i = 0; i < 3; ++i) if(searchForBytes(image.get(), size, signature[i], 3, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyEF(const BytePtr& image, uInt32 size, BSType& type) { // Newer EF carts store strings 'EFEF' and 'EFSC' starting at address $FFF8 // This signature is attributed to "RevEng" of AtariAge uInt8 efef[] = { 'E', 'F', 'E', 'F' }; uInt8 efsc[] = { 'E', 'F', 'S', 'C' }; if(searchForBytes(image.get()+size-8, 8, efef, 4, 1)) { type = BSType::_EF; return true; } else if(searchForBytes(image.get()+size-8, 8, efsc, 4, 1)) { type = BSType::_EFSC; return true; } // Otherwise, EF cart bankswitching switches banks by accessing addresses // 0xFE0 to 0xFEF, usually with either a NOP or LDA // It's likely that the code will switch to bank 0, so that's what is tested bool isEF = false; uInt8 signature[4][3] = { { 0x0C, 0xE0, 0xFF }, // NOP $FFE0 { 0xAD, 0xE0, 0xFF }, // LDA $FFE0 { 0x0C, 0xE0, 0x1F }, // NOP $1FE0 { 0xAD, 0xE0, 0x1F } // LDA $1FE0 }; for(uInt32 i = 0; i < 4; ++i) { if(searchForBytes(image.get(), size, signature[i], 3, 1)) { isEF = true; break; } } // Now that we know that the ROM is EF, we need to check if it's // the SC variant if(isEF) { type = isProbablySC(image, size) ? BSType::_EFSC : BSType::_EF; return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyBF(const BytePtr& image, uInt32 size, BSType& type) { // BF carts store strings 'BFBF' and 'BFSC' starting at address $FFF8 // This signature is attributed to "RevEng" of AtariAge uInt8 bf[] = { 'B', 'F', 'B', 'F' }; uInt8 bfsc[] = { 'B', 'F', 'S', 'C' }; if(searchForBytes(image.get()+size-8, 8, bf, 4, 1)) { type = BSType::_BF; return true; } else if(searchForBytes(image.get()+size-8, 8, bfsc, 4, 1)) { type = BSType::_BFSC; return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyBUS(const BytePtr& image, uInt32 size) { // BUS ARM code has 2 occurrences of the string BUS // Note: all Harmony/Melody custom drivers also contain the value // 0x10adab1e (LOADABLE) if needed for future improvement uInt8 bus[] = { 'B', 'U', 'S'}; return searchForBytes(image.get(), size, bus, 3, 2); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyCDF(const BytePtr& image, uInt32 size) { // CDF ARM code has 3 occurrences of the string DPC+ // Note: all Harmony/Melody custom drivers also contain the value // 0x10adab1e (LOADABLE) if needed for future improvement uInt8 signature[] = { 'C', 'D', 'F' }; return searchForBytes(image.get(), size, signature, 3, 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyDF(const BytePtr& image, uInt32 size, BSType& type) { // BF carts store strings 'DFDF' and 'DFSC' starting at address $FFF8 // This signature is attributed to "RevEng" of AtariAge uInt8 df[] = { 'D', 'F', 'D', 'F' }; uInt8 dfsc[] = { 'D', 'F', 'S', 'C' }; if(searchForBytes(image.get()+size-8, 8, df, 4, 1)) { type = BSType::_DF; return true; } else if(searchForBytes(image.get()+size-8, 8, dfsc, 4, 1)) { type = BSType::_DFSC; return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyFA2(const BytePtr& image, uInt32) { // This currently tests only the 32K version of FA2; the 24 and 28K // versions are easy, in that they're the only possibility with those // file sizes // 32K version has all zeros in 29K-32K area for(uInt32 i = 29*1024; i < 32*1024; ++i) if(image[i] != 0) return false; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyFE(const BytePtr& image, uInt32 size) { // FE bankswitching is very weird, but always seems to include a // 'JSR $xxxx' // These signatures are attributed to the MESS project uInt8 signature[4][5] = { { 0x20, 0x00, 0xD0, 0xC6, 0xC5 }, // JSR $D000; DEC $C5 { 0x20, 0xC3, 0xF8, 0xA5, 0x82 }, // JSR $F8C3; LDA $82 { 0xD0, 0xFB, 0x20, 0x73, 0xFE }, // BNE $FB; JSR $FE73 { 0x20, 0x00, 0xF0, 0x84, 0xD6 } // JSR $F000; STY $D6 }; for(uInt32 i = 0; i < 4; ++i) if(searchForBytes(image.get(), size, signature[i], 5, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyMDM(const BytePtr& image, uInt32 size) { // MDM cart is identified key 'MDMC' in the first 8K of ROM uInt8 signature[] = { 'M', 'D', 'M', 'C' }; return searchForBytes(image.get(), std::min(size, 8192u), signature, 4, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablySB(const BytePtr& image, uInt32 size) { // SB cart bankswitching switches banks by accessing address 0x0800 uInt8 signature[2][3] = { { 0xBD, 0x00, 0x08 }, // LDA $0800,x { 0xAD, 0x00, 0x08 } // LDA $0800 }; if(searchForBytes(image.get(), size, signature[0], 3, 1)) return true; else return searchForBytes(image.get(), size, signature[1], 3, 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyUA(const BytePtr& image, uInt32 size) { // UA cart bankswitching switches to bank 1 by accessing address 0x240 // using 'STA $240' or 'LDA $240' uInt8 signature[3][3] = { { 0x8D, 0x40, 0x02 }, // STA $240 { 0xAD, 0x40, 0x02 }, // LDA $240 { 0xBD, 0x1F, 0x02 } // LDA $21F,X }; for(uInt32 i = 0; i < 3; ++i) if(searchForBytes(image.get(), size, signature[i], 3, 1)) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartDetector::isProbablyX07(const BytePtr& image, uInt32 size) { // X07 bankswitching switches to bank 0, 1, 2, etc by accessing address 0x08xd uInt8 signature[6][3] = { { 0xAD, 0x0D, 0x08 }, // LDA $080D { 0xAD, 0x1D, 0x08 }, // LDA $081D { 0xAD, 0x2D, 0x08 }, // LDA $082D { 0x0C, 0x0D, 0x08 }, // NOP $080D { 0x0C, 0x1D, 0x08 }, // NOP $081D { 0x0C, 0x2D, 0x08 } // NOP $082D }; for(uInt32 i = 0; i < 6; ++i) if(searchForBytes(image.get(), size, signature[i], 3, 1)) return true; return false; } stella-5.1.1/src/emucore/CartDetector.hxx000066400000000000000000000212731324334165500203570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_DETECTOR_HXX #define CARTRIDGE_DETECTOR_HXX class Cartridge; class Properties; class OSystem; #include "bspf.hxx" #include "BSType.hxx" /** Auto-detect cart type based on various attributes (file size, signatures, filenames, etc) @author Stephen Anthony */ class CartDetector { public: /** Create a new cartridge object allocated on the heap. The type of cartridge created depends on the properties object. @param image A pointer to the ROM image @param size The size of the ROM image @param md5 The md5sum for the given ROM image (can be updated) @param dtype The detected bankswitch type of the ROM image @param system The osystem associated with the system @return Pointer to the new cartridge object allocated on the heap */ static unique_ptr create(const BytePtr& image, uInt32 size, string& md5, const string& dtype, const OSystem& system); private: /** Create a cartridge from a multi-cart image pointer; internally this takes a slice of the ROM image ues that for the cartridge. @param image A pointer to the complete ROM image @param size The size of the ROM image slice @param numroms The number of ROMs in the multicart @param md5 The md5sum for the slice of the ROM image @param type The detected type of the slice of the ROM image @param id The ID for the slice of the ROM image @param osystem The osystem associated with the system @return Pointer to the new cartridge object allocated on the heap */ static unique_ptr createFromMultiCart(const BytePtr& image, uInt32& size, uInt32 numroms, string& md5, BSType type, string& id, const OSystem& osystem); /** Create a cartridge from the entire image pointer. @param image A pointer to the complete ROM image @param size The size of the ROM image @param type The bankswitch type of the ROM image @param md5 The md5sum for the ROM image @param osystem The osystem associated with the system @return Pointer to the new cartridge object allocated on the heap */ static unique_ptr createFromImage(const BytePtr& image, uInt32 size, BSType type, const string& md5, const OSystem& osystem); /** Try to auto-detect the bankswitching type of the cartridge @param image A pointer to the ROM image @param size The size of the ROM image @return The "best guess" for the cartridge type */ static BSType autodetectType(const BytePtr& image, uInt32 size); /** Search the image for the specified byte signature @param image A pointer to the ROM image @param imagesize The size of the ROM image @param signature The byte sequence to search for @param sigsize The number of bytes in the signature @param minhits The minimum number of times a signature is to be found @return True if the signature was found at least 'minhits' time, else false */ static bool searchForBytes(const uInt8* image, uInt32 imagesize, const uInt8* signature, uInt32 sigsize, uInt32 minhits); /** Returns true if the image is probably a SuperChip (128 bytes RAM) Note: should be called only on ROMs with size multiple of 4K */ static bool isProbablySC(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a 4K SuperChip (128 bytes RAM) */ static bool isProbably4KSC(const BytePtr& image, uInt32 size); /** Returns true if the image probably contains ARM code in the first 1K */ static bool isProbablyARM(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a 0840 bankswitching cartridge */ static bool isProbably0840(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a 3E bankswitching cartridge */ static bool isProbably3E(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a 3E+ bankswitching cartridge */ static bool isProbably3EPlus(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a 3F bankswitching cartridge */ static bool isProbably3F(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a 4A50 bankswitching cartridge */ static bool isProbably4A50(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a BF/BFSC bankswitching cartridge */ static bool isProbablyBF(const BytePtr& image, uInt32 size, BSType& type); /** Returns true if the image is probably a BUS bankswitching cartridge */ static bool isProbablyBUS(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a CDF bankswitching cartridge */ static bool isProbablyCDF(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a CTY bankswitching cartridge */ static bool isProbablyCTY(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a CV bankswitching cartridge */ static bool isProbablyCV(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a CV+ bankswitching cartridge */ static bool isProbablyCVPlus(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a DASH bankswitching cartridge */ static bool isProbablyDASH(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a DF/DFSC bankswitching cartridge */ static bool isProbablyDF(const BytePtr& image, uInt32 size, BSType& type); /** Returns true if the image is probably a DPC+ bankswitching cartridge */ static bool isProbablyDPCplus(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a E0 bankswitching cartridge */ static bool isProbablyE0(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a E7 bankswitching cartridge */ static bool isProbablyE7(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a E78K bankswitching cartridge */ static bool isProbablyE78K(const BytePtr& image, uInt32 size); /** Returns true if the image is probably an EF/EFSC bankswitching cartridge */ static bool isProbablyEF(const BytePtr& image, uInt32 size, BSType& type); /** Returns true if the image is probably an F6 bankswitching cartridge */ //static bool isProbablyF6(const BytePtr& image, uInt32 size); /** Returns true if the image is probably an FA2 bankswitching cartridge */ static bool isProbablyFA2(const BytePtr& image, uInt32 size); /** Returns true if the image is probably an FE bankswitching cartridge */ static bool isProbablyFE(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a MDM bankswitching cartridge */ static bool isProbablyMDM(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a SB bankswitching cartridge */ static bool isProbablySB(const BytePtr& image, uInt32 size); /** Returns true if the image is probably a UA bankswitching cartridge */ static bool isProbablyUA(const BytePtr& image, uInt32 size); /** Returns true if the image is probably an X07 bankswitching cartridge */ static bool isProbablyX07(const BytePtr& image, uInt32 size); private: // Following constructors and assignment operators not supported CartDetector() = delete; CartDetector(const CartDetector&) = delete; CartDetector(CartDetector&&) = delete; CartDetector& operator=(const CartDetector&) = delete; CartDetector& operator=(CartDetector&&) = delete; }; #endif stella-5.1.1/src/emucore/CartE0.cxx000066400000000000000000000145001324334165500170400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartE0.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE0::CartridgeE0(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(8192u, size)); createCodeAccessBase(8192); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::reset() { // Setup segments to some default slices if(randomStartBank()) { segmentZero(mySystem->randGenerator().next() % 8); segmentOne(mySystem->randGenerator().next() % 8); segmentTwo(mySystem->randGenerator().next() % 8); } else { segmentZero(4); segmentOne(5); segmentTwo(6); } myCurrentSlice[3] = 7; // fixed myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page acessing methods for the first part of the last segment for(uInt16 addr = 0x1C00; addr < (0x1FE0U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[7168 + (addr & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[7168 + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } // Set the page accessing methods for the hot spots in the last segment access.directPeekBase = nullptr; access.codeAccessBase = &myCodeAccessBase[8128]; access.type = System::PA_READ; for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeE0::peek(uInt16 address) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { segmentZero(address & 0x0007); } else if((address >= 0x0FE8) && (address <= 0x0FEF)) { segmentOne(address & 0x0007); } else if((address >= 0x0FF0) && (address <= 0x0FF7)) { segmentTwo(address & 0x0007); } return myImage[(myCurrentSlice[address >> 10] << 10) + (address & 0x03FF)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE0::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { segmentZero(address & 0x0007); } else if((address >= 0x0FE8) && (address <= 0x0FEF)) { segmentOne(address & 0x0007); } else if((address >= 0x0FF0) && (address <= 0x0FF7)) { segmentTwo(address & 0x0007); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::segmentZero(uInt16 slice) { if(bankLocked()) return; // Remember the new slice myCurrentSlice[0] = slice; uInt16 offset = slice << 10; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x1400; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::segmentOne(uInt16 slice) { if(bankLocked()) return; // Remember the new slice myCurrentSlice[1] = slice; uInt16 offset = slice << 10; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE0::segmentTwo(uInt16 slice) { if(bankLocked()) return; // Remember the new slice myCurrentSlice[2] = slice; uInt16 offset = slice << 10; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x03FF)]; access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE0::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; myImage[(myCurrentSlice[address >> 10] << 10) + (address & 0x03FF)] = value; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeE0::getImage(uInt32& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE0::save(Serializer& out) const { try { out.putString(name()); out.putShortArray(myCurrentSlice, 4); } catch(...) { cerr << "ERROR: CartridgeE0::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeE0::load(Serializer& in) { try { if(in.getString() != name()) return false; in.getShortArray(myCurrentSlice, 4); } catch(...) { cerr << "ERROR: CartridgeE0::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/CartE0.hxx000066400000000000000000000122041324334165500170440ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEE0_HXX #define CARTRIDGEE0_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartE0Widget.hxx" #endif /** This is the cartridge class for Parker Brothers' 8K games. In this bankswitching scheme the 2600's 4K cartridge address space is broken into four 1K segments. The desired 1K slice of the ROM is selected by accessing $1FE0 to $1FE7 for the first 1K. $1FE8 to $1FEF selects the slice for the second 1K, and $1FF0 to $1FF7 selects the slice for the third 1K. The last 1K segment always points to the last 1K of the ROM image. Because of the complexity of this scheme, the cart reports having only one actual bank, in which pieces of it can be swapped out in many different ways. @author Bradford W. Mott */ class CartridgeE0 : public Cartridge { friend class CartridgeE0Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeE0(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeE0() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeE0"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeE0Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Install the specified slice for segment zero @param slice The slice to map into the segment */ void segmentZero(uInt16 slice); /** Install the specified slice for segment one @param slice The slice to map into the segment */ void segmentOne(uInt16 slice); /** Install the specified slice for segment two @param slice The slice to map into the segment */ void segmentTwo(uInt16 slice); private: // Indicates the slice mapped into each of the four segments uInt16 myCurrentSlice[4]; // The 8K ROM image of the cartridge uInt8 myImage[8192]; private: // Following constructors and assignment operators not supported CartridgeE0() = delete; CartridgeE0(const CartridgeE0&) = delete; CartridgeE0(CartridgeE0&&) = delete; CartridgeE0& operator=(const CartridgeE0&) = delete; CartridgeE0& operator=(CartridgeE0&&) = delete; }; #endif stella-5.1.1/src/emucore/CartE7.cxx000066400000000000000000000025071324334165500170530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartE7.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE7::CartridgeE7(const BytePtr& image, uInt32 size, const Settings& settings) : CartridgeMNetwork(image, size, settings) { initialize(image, size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE7::checkSwitchBank(uInt16 address) { // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FE7)) { bank(address & 0x0007); } else if((address >= 0x0FE8) && (address <= 0x0FEB)) { bankRAM(address & 0x0003); } } stella-5.1.1/src/emucore/CartE7.hxx000066400000000000000000000046001324334165500170540ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEE7_HXX #define CARTRIDGEE7_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartE7Widget.hxx" #endif #include "CartMNetwork.hxx" /** This is the cartridge class for 16K M-Network bankswitched games. @author Bradford W. Mott, Thomas Jentzsch */ class CartridgeE7 : public CartridgeMNetwork { public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeE7(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeE7() = default; public: /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeE7"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeE7Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif private: /** Check hotspots and switch bank if triggered. */ void checkSwitchBank(uInt16 address) override; private: // Following constructors and assignment operators not supported CartridgeE7() = delete; CartridgeE7(const CartridgeE7&) = delete; CartridgeE7(CartridgeE7&&) = delete; CartridgeE7& operator=(const CartridgeE7&) = delete; CartridgeE7& operator=(CartridgeE7&&) = delete; }; #endif stella-5.1.1/src/emucore/CartE78K.cxx000066400000000000000000000025171324334165500172570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartE78K.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeE78K::CartridgeE78K(const BytePtr& image, uInt32 size, const Settings& settings) : CartridgeMNetwork(image, size, settings) { initialize(image, size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeE78K::checkSwitchBank(uInt16 address) { // Switch banks if necessary if((address >= 0x0FE4) && (address <= 0x0FE7)) { bank(address & 0x0003); } else if((address >= 0x0FE8) && (address <= 0x0FEB)) { bankRAM(address & 0x0003); } } stella-5.1.1/src/emucore/CartE78K.hxx000066400000000000000000000046571324334165500172730ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_E78K_HXX #define CARTRIDGE_E78K_HXX #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartE78KWidget.hxx" #endif #include "CartMNetwork.hxx" /** This is the cartridge class for 8K M-Network bankswitched games. @author Bradford W. Mott, Thomas Jentzsch */ class CartridgeE78K : public CartridgeMNetwork { public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeE78K(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeE78K() = default; public: /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeE78K"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeE78KWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif private: /** Check hotspots and switch bank if triggered. */ void checkSwitchBank(uInt16 address) override; private: // Following constructors and assignment operators not supported CartridgeE78K() = delete; CartridgeE78K(const CartridgeE78K&) = delete; CartridgeE78K(CartridgeE78K&&) = delete; CartridgeE78K& operator=(const CartridgeE78K&) = delete; CartridgeE78K& operator=(CartridgeE78K&&) = delete; }; #endif stella-5.1.1/src/emucore/CartEF.cxx000066400000000000000000000105211324334165500170650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartEF.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEF::CartridgeEF(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(65536u, size)); createCodeAccessBase(65536); // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEF::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEF::install(System& system) { mySystem = &system; // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeEF::peek(uInt16 address) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FEF)) bank(address - 0x0FE0); return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FEF)) bank(address - 0x0FE0); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1000; addr < (0x1FE0U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEF::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEF::bankCount() const { return 16; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeEF::getImage(uInt32& size) const { size = 65536; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeEF::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEF::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeEF::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartEF.hxx000066400000000000000000000111371324334165500170760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEEF_HXX #define CARTRIDGEEF_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartEFWidget.hxx" #endif /** Cartridge class used for Homestar Runner by Paul Slocum. There are 16 4K banks (total of 64K ROM). Accessing $1FE0 - $1FEF switches to each bank. @author Stephen Anthony */ class CartridgeEF : public Cartridge { friend class CartridgeEFWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeEF(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeEF() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeEF"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeEFWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 64K ROM image of the cartridge uInt8 myImage[65536]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeEF() = delete; CartridgeEF(const CartridgeEF&) = delete; CartridgeEF(CartridgeEF&&) = delete; CartridgeEF& operator=(const CartridgeEF&) = delete; CartridgeEF& operator=(CartridgeEF&&) = delete; }; #endif stella-5.1.1/src/emucore/CartEFSC.cxx000066400000000000000000000137261324334165500173250ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartEFSC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeEFSC::CartridgeEFSC(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(65536u, size)); createCodeAccessBase(65536); // Remember startup bank myStartBank = 15; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSC::reset() { initializeRAM(myRAM, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeEFSC::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeEFSC::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FEF)) bank(address - 0x0FE0); if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } else return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEFSC::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FE0) && (address <= 0x0FEF)) bank(address - 0x0FE0); // NOTE: This does not handle accessing RAM, however, this function // should never be called for RAM because of the way page accessing // has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEFSC::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1100; addr < (0x1FE0U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEFSC::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeEFSC::bankCount() const { return 16; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEFSC::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0100) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x007F] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeEFSC::getImage(uInt32& size) const { size = 65536; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEFSC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); out.putByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeEFSC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeEFSC::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeEFSC::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartEFSC.hxx000066400000000000000000000114131324334165500173210ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEEFSC_HXX #define CARTRIDGEEFSC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartEFSCWidget.hxx" #endif /** Cartridge class used for Homestar Runner by Paul Slocum. There are 16 4K banks (total of 64K ROM) with 128 bytes of RAM. Accessing $1FE0 - $1FEF switches to each bank. RAM read port is $1080 - $10FF, write port is $1000 - $107F. @author Stephen Anthony */ class CartridgeEFSC : public Cartridge { friend class CartridgeEFSCWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeEFSC(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeEFSC() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeEFSC"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeEFSCWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 64K ROM image of the cartridge uInt8 myImage[65536]; // The 128 bytes of RAM uInt8 myRAM[128]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeEFSC() = delete; CartridgeEFSC(const CartridgeEFSC&) = delete; CartridgeEFSC(CartridgeEFSC&&) = delete; CartridgeEFSC& operator=(const CartridgeEFSC&) = delete; CartridgeEFSC& operator=(CartridgeEFSC&&) = delete; }; #endif stella-5.1.1/src/emucore/CartF0.cxx000066400000000000000000000110471324334165500170440ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartF0.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF0::CartridgeF0(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(65536u, size)); createCodeAccessBase(65536); // Remember startup bank myStartBank = 15; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF0::reset() { // define random startup bank randomizeStartBank(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF0::install(System& system) { mySystem = &system; // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF0::peek(uInt16 address) { address &= 0x0FFF; // Switch to next bank if(address == 0x0FF0) incbank(); return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch to next bank if(address == 0x0FF0) incbank(); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF0::incbank() { // Determine current bank, and increment to the next one uInt8 nextBank = ((myBankOffset >> 12) + 1) & 0x0F; bank(nextBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1000; addr < (0x1FF0U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF0::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF0::bankCount() const { return 16; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF0::getImage(uInt32& size) const { size = 65536; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeF0::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF0::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF0::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartF0.hxx000066400000000000000000000112301324334165500170430ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF0_HXX #define CARTRIDGEF0_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF0Widget.hxx" #endif /** Cartridge class used for Dynacom Megaboy There are 16 4K banks. Accessing $1FF0 switches to next bank. @author Eckhard Stolberg */ class CartridgeF0 : public Cartridge { friend class CartridgeF0Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeF0(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeF0() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeF0"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeF0Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Install pages for the next bank in the system */ void incbank(); private: // The 64K ROM image of the cartridge uInt8 myImage[65536]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeF0() = delete; CartridgeF0(const CartridgeF0&) = delete; CartridgeF0(CartridgeF0&&) = delete; CartridgeF0& operator=(const CartridgeF0&) = delete; CartridgeF0& operator=(CartridgeF0&&) = delete; }; #endif stella-5.1.1/src/emucore/CartF4.cxx000066400000000000000000000106571324334165500170560ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Random.hxx" #include "System.hxx" #include "CartF4.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4::CartridgeF4(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(32768u, size)); createCodeAccessBase(32768); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4::reset() { // define random startup bank randomizeStartBank(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4::install(System& system) { mySystem = &system; // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF4::peek(uInt16 address) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FF4) && (address <= 0x0FFB)) { bank(address - 0x0FF4); } return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FF4) && (address <= 0x0FFB)) { bank(address - 0x0FF4); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1000; addr < (0x1FF4U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF4::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF4::bankCount() const { return 8; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF4::getImage(uInt32& size) const { size = 32768; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeF4::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF4::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartF4.hxx000066400000000000000000000111131324334165500170470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF4_HXX #define CARTRIDGEF4_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF4Widget.hxx" #endif /** Cartridge class used for Atari's 32K bankswitched games. There are eight 4K banks, accessible by read/write to $1FF4 - $1FFB. @author Bradford W. Mott */ class CartridgeF4 : public Cartridge { friend class CartridgeF4Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeF4(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeF4() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeF4"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeF4Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 32K ROM image of the cartridge uInt8 myImage[32768]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeF4() = delete; CartridgeF4(const CartridgeF4&) = delete; CartridgeF4(CartridgeF4&&) = delete; CartridgeF4& operator=(const CartridgeF4&) = delete; CartridgeF4& operator=(CartridgeF4&&) = delete; }; #endif stella-5.1.1/src/emucore/CartF4SC.cxx000066400000000000000000000142451324334165500173010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartF4SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF4SC::CartridgeF4SC(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(32768u, size)); createCodeAccessBase(32768); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4SC::reset() { initializeRAM(myRAM, 128); // define random startup bank randomizeStartBank(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF4SC::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF4SC::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FF4) && (address <= 0x0FFB)) bank(address - 0x0FF4); if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } // NOTE: This does not handle accessing RAM, however, this function // should never be called for RAM because of the way page accessing // has been setup return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4SC::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary if((address >= 0x0FF4) && (address <= 0x0FFB)) bank(address - 0x0FF4); // NOTE: This does not handle accessing RAM, however, this function // should never be called for RAM because of the way page accessing // has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4SC::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1100; addr < (0x1FF4U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF4SC::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF4SC::bankCount() const { return 8; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4SC::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0100) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x007F] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF4SC::getImage(uInt32& size) const { size = 32768; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4SC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); out.putByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF4SC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF4SC::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF4SC::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartF4SC.hxx000066400000000000000000000113671324334165500173100ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF4SC_HXX #define CARTRIDGEF4SC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF4SCWidget.hxx" #endif /** Cartridge class used for Atari's 32K bankswitched games with 128 bytes of RAM. There are eight 4K banks, accessible by read/write to $1FF4 - $1FFB. RAM read port is $1080 - $10FF, write port is $1000 - $107F. @author Bradford W. Mott */ class CartridgeF4SC : public Cartridge { friend class CartridgeF4SCWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeF4SC(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeF4SC() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeF4SC"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeF4SCWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 32K ROM image of the cartridge uInt8 myImage[32768]; // The 128 bytes of RAM uInt8 myRAM[128]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeF4SC() = delete; CartridgeF4SC(const CartridgeF4SC&) = delete; CartridgeF4SC(CartridgeF4SC&&) = delete; CartridgeF4SC& operator=(const CartridgeF4SC&) = delete; CartridgeF4SC& operator=(CartridgeF4SC&&) = delete; }; #endif stella-5.1.1/src/emucore/CartF6.cxx000066400000000000000000000121471324334165500170540ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartF6.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6::CartridgeF6(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(16384u, size)); createCodeAccessBase(16384); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6::reset() { // define random startup bank randomizeStartBank(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6::install(System& system) { mySystem = &system; // Upon install we'll setup the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF6::peek(uInt16 address) { address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF6: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF7: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF8: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF9: // Set the current bank to the forth 4k bank bank(3); break; default: break; } return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF6: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF7: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF8: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF9: // Set the current bank to the forth 4k bank bank(3); break; default: break; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1000; addr < (0x1FF6U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF6::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF6::bankCount() const { return 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF6::getImage(uInt32& size) const { size = 16384; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeF6::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF6::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartF6.hxx000066400000000000000000000111121324334165500170500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF6_HXX #define CARTRIDGEF6_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF6Widget.hxx" #endif /** Cartridge class used for Atari's 16K bankswitched games. There are four 4K banks, accessible by read/write to $1FF6 - $1FF9. @author Bradford W. Mott */ class CartridgeF6 : public Cartridge { friend class CartridgeF6Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeF6(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeF6() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeF6"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeF6Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 16K ROM image of the cartridge uInt8 myImage[16384]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeF6() = delete; CartridgeF6(const CartridgeF6&) = delete; CartridgeF6(CartridgeF6&&) = delete; CartridgeF6& operator=(const CartridgeF6&) = delete; CartridgeF6& operator=(CartridgeF6&&) = delete; }; #endif stella-5.1.1/src/emucore/CartF6SC.cxx000066400000000000000000000153451324334165500173050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartF6SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF6SC::CartridgeF6SC(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(16384u, size)); createCodeAccessBase(16384); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6SC::reset() { // define random startup bank randomizeStartBank(); initializeRAM(myRAM, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF6SC::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF6SC::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF6: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF7: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF8: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF9: // Set the current bank to the forth 4k bank bank(3); break; default: break; } if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } else return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6SC::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF6: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF7: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF8: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF9: // Set the current bank to the forth 4k bank bank(3); break; default: break; } // NOTE: This does not handle accessing RAM, however, this function // should never be called for RAM because of the way page accessing // has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6SC::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF6 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1100; addr < (0x1FF6U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF6SC::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF6SC::bankCount() const { return 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6SC::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0100) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x007F] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF6SC::getImage(uInt32& size) const { size = 16384; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6SC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); out.putByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF6SC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF6SC::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF6SC::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartF6SC.hxx000066400000000000000000000113661324334165500173110ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF6SC_HXX #define CARTRIDGEF6SC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF6SCWidget.hxx" #endif /** Cartridge class used for Atari's 16K bankswitched games with 128 bytes of RAM. There are four 4K banks, accessible by read/write to $1FF6 - $1FF9. RAM read port is $1080 - $10FF, write port is $1000 - $107F. @author Bradford W. Mott */ class CartridgeF6SC : public Cartridge { friend class CartridgeF6SCWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeF6SC(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeF6SC() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeF6SC"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeF6SCWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 16K ROM image of the cartridge uInt8 myImage[16384]; // The 128 bytes of RAM uInt8 myRAM[128]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeF6SC() = delete; CartridgeF6SC(const CartridgeF6SC&) = delete; CartridgeF6SC(CartridgeF6SC&&) = delete; CartridgeF6SC& operator=(const CartridgeF6SC&) = delete; CartridgeF6SC& operator=(CartridgeF6SC&&) = delete; }; #endif stella-5.1.1/src/emucore/CartF8.cxx000066400000000000000000000124011324334165500170470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartF8.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8::CartridgeF8(const BytePtr& image, uInt32 size, const string& md5, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(8192u, size)); createCodeAccessBase(8192); // Normally bank 1 is the reset bank, unless we're dealing with ROMs // that have been incorrectly created with banks in the opposite order myStartBank = (md5 == "bc24440b59092559a1ec26055fd1270e" || // Private Eye [a] md5 == "75ea60884c05ba496473c23a58edf12f" || // 8-in-1 Yars Revenge md5 == "75ee371ccfc4f43e7d9b8f24e1266b55" || // Snow White md5 == "74c8a6f20f8adaa7e05183f796eda796" || // Tricade Demo md5 == "9905f9f4706223dadee84f6867ede8e3" || // Challenge md5 == "3c7a7b3a0a7e6319b2fa0f923ef6c9af") // Racer Prototype ? 0 : 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8::reset() { // define random startup bank randomizeStartBank(); // Upon reset we switch to the reset bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8::install(System& system) { mySystem = &system; // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF8::peek(uInt16 address) { address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); break; case 0x0FF9: // Set the current bank to the upper 4k bank bank(1); break; default: break; } return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); break; case 0x0FF9: // Set the current bank to the upper 4k bank bank(1); break; default: break; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1000; addr < (0x1FF8U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF8::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF8::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF8::getImage(uInt32& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeF8::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeF8::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartF8.hxx000066400000000000000000000112301324334165500170530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF8_HXX #define CARTRIDGEF8_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF8Widget.hxx" #endif /** Cartridge class used for Atari's 8K bankswitched games. There are two 4K banks, accessible by read/write to $1FF8 - $1FF9. @author Bradford W. Mott */ class CartridgeF8 : public Cartridge { friend class CartridgeF8Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param md5 MD5sum of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeF8(const BytePtr& image, uInt32 size, const string& md5, const Settings& settings); virtual ~CartridgeF8() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeF8"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeF8Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 8K ROM image of the cartridge uInt8 myImage[8192]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeF8() = delete; CartridgeF8(const CartridgeF8&) = delete; CartridgeF8(CartridgeF8&&) = delete; CartridgeF8& operator=(const CartridgeF8&) = delete; CartridgeF8& operator=(CartridgeF8&&) = delete; }; #endif stella-5.1.1/src/emucore/CartF8SC.cxx000066400000000000000000000145251324334165500173060ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartF8SC.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeF8SC::CartridgeF8SC(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(8192u, size)); createCodeAccessBase(8192); // Remember startup bank myStartBank = 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8SC::reset() { // define startup bank randomizeStartBank(); initializeRAM(myRAM, 128); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeF8SC::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1080; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[addr & 0x007F]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1080; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x007F]; access.codeAccessBase = &myCodeAccessBase[0x80 + (addr & 0x007F)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeF8SC::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); break; case 0x0FF9: // Set the current bank to the upper 4k bank bank(1); break; default: break; } if(address < 0x0080) // Write port is at 0xF000 - 0xF080 (128 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } else return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8SC::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); break; case 0x0FF9: // Set the current bank to the upper 4k bank bank(1); break; default: break; } // NOTE: This does not handle accessing RAM, however, this function // should never be called for RAM because of the way page accessing // has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8SC::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1100; addr < (0x1FF8U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF8SC::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeF8SC::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8SC::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0100) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x007F] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeF8SC::getImage(uInt32& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8SC::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); out.putByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF8SC::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeF8SC::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); in.getByteArray(myRAM, 128); } catch(...) { cerr << "ERROR: CartridgeF8SC::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartF8SC.hxx000066400000000000000000000113621324334165500173070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEF8SC_HXX #define CARTRIDGEF8SC_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartF8SCWidget.hxx" #endif /** Cartridge class used for Atari's 8K bankswitched games with 128 bytes of RAM. There are two 4K banks, accessible by read/write to $1FF8 - $1FF9. RAM read port is $1080 - $10FF, write port is $1000 - $107F. @author Bradford W. Mott */ class CartridgeF8SC : public Cartridge { friend class CartridgeF8SCWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeF8SC(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeF8SC() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeF8SC"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeF8SCWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 8K ROM image of the cartridge uInt8 myImage[8192]; // The 128 bytes of RAM uInt8 myRAM[128]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeF8SC() = delete; CartridgeF8SC(const CartridgeF8SC&) = delete; CartridgeF8SC(CartridgeF8SC&&) = delete; CartridgeF8SC& operator=(const CartridgeF8SC&) = delete; CartridgeF8SC& operator=(CartridgeF8SC&&) = delete; }; #endif stella-5.1.1/src/emucore/CartFA.cxx000066400000000000000000000150001324334165500170560ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartFA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA::CartridgeFA(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(12288u, size)); createCodeAccessBase(12288); // Remember startup bank myStartBank = 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA::reset() { // define random startup bank randomizeStartBank(); initializeRAM(myRAM, 256); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x00FF]; access.codeAccessBase = &myCodeAccessBase[addr & 0x00FF]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x00FF]; access.codeAccessBase = &myCodeAccessBase[0x100 + (addr & 0x00FF)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFA::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); break; case 0x0FF9: // Set the current bank to the middle 4k bank bank(1); break; case 0x0FFA: // Set the current bank to the upper 4k bank bank(2); break; default: break; } if(address < 0x0100) // Write port is at 0xF000 - 0xF100 (256 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } else return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF8: // Set the current bank to the lower 4k bank bank(0); break; case 0x0FF9: // Set the current bank to the middle 4k bank bank(1); break; case 0x0FFA: // Set the current bank to the upper 4k bank bank(2); break; default: break; } // NOTE: This does not handle accessing RAM, however, this function // should never be called for RAM because of the way page accessing // has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF8 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1200; addr < (0x1FF8U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFA::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFA::bankCount() const { return 3; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0200) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x00FF] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeFA::getImage(uInt32& size) const { size = 12288; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); out.putByteArray(myRAM, 256); } catch(...) { cerr << "ERROR: CartridgeFA::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); in.getByteArray(myRAM, 256); } catch(...) { cerr << "ERROR: CartridgeFA::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartFA.hxx000066400000000000000000000113361324334165500170730ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEFA_HXX #define CARTRIDGEFA_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartFAWidget.hxx" #endif /** Cartridge class used for CBS' RAM Plus cartridges. There are three 4K banks, accessible by read/write at $1FF8 - $1FFA, and 256 bytes of RAM. RAM read port is $1100 - $11FF, write port is $1000 - $10FF. @author Bradford W. Mott */ class CartridgeFA : public Cartridge { friend class CartridgeFAWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeFA(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeFA() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeFA"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeFAWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 12K ROM image of the cartridge uInt8 myImage[12288]; // The 256 bytes of RAM on the cartridge uInt8 myRAM[256]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeFA() = delete; CartridgeFA(const CartridgeFA&) = delete; CartridgeFA(CartridgeFA&&) = delete; CartridgeFA& operator=(const CartridgeFA&) = delete; CartridgeFA& operator=(CartridgeFA&&) = delete; }; #endif stella-5.1.1/src/emucore/CartFA2.cxx000066400000000000000000000262651324334165500171570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Serializer.hxx" #include "System.hxx" #include "CartFA2.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFA2::CartridgeFA2(const BytePtr& image, uInt32 size, const OSystem& osystem) : Cartridge(osystem.settings()), myOSystem(osystem), mySize(28 * 1024), myRamAccessTimeout(0), myBankOffset(0) { // 29/32K version of FA2 has valid data @ 1K - 29K const uInt8* img_ptr = image.get(); if(size >= 29 * 1024) img_ptr += 1024; else if(size < mySize) mySize = size; // Copy the ROM image into my buffer memcpy(myImage, img_ptr, mySize); createCodeAccessBase(mySize); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2::reset() { // define random startup bank randomizeStartBank(); initializeRAM(myRAM, 256); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing method for the RAM writing pages access.type = System::PA_WRITE; for(uInt16 addr = 0x1000; addr < 0x1100; addr += System::PAGE_SIZE) { access.directPokeBase = &myRAM[addr & 0x00FF]; access.codeAccessBase = &myCodeAccessBase[addr & 0x00FF]; mySystem->setPageAccess(addr, access); } // Set the page accessing method for the RAM reading pages access.directPokeBase = nullptr; access.type = System::PA_READ; for(uInt16 addr = 0x1100; addr < 0x1200; addr += System::PAGE_SIZE) { access.directPeekBase = &myRAM[addr & 0x00FF]; access.codeAccessBase = &myCodeAccessBase[0x100 + (addr & 0x00FF)]; mySystem->setPageAccess(addr, access); } // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFA2::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF4: // Load/save RAM to/from Harmony cart flash if(mySize == 28*1024 && !bankLocked()) return ramReadWrite(); break; case 0x0FF5: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF6: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF7: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF8: // Set the current bank to the fourth 4k bank bank(3); break; case 0x0FF9: // Set the current bank to the fifth 4k bank bank(4); break; case 0x0FFA: // Set the current bank to the sixth 4k bank bank(5); break; case 0x0FFB: // Set the current bank to the seventh 4k bank // This is only available on 28K ROMs if(mySize == 28*1024) bank(6); break; default: break; } if(address < 0x0100) // Write port is at 0xF000 - 0xF100 (256 bytes) { // Reading from the write port triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address] = value; } } else return myImage[myBankOffset + address]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA2::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary switch(address) { case 0x0FF4: // Load/save RAM to/from Harmony cart flash if(mySize == 28*1024 && !bankLocked()) ramReadWrite(); break; case 0x0FF5: // Set the current bank to the first 4k bank bank(0); break; case 0x0FF6: // Set the current bank to the second 4k bank bank(1); break; case 0x0FF7: // Set the current bank to the third 4k bank bank(2); break; case 0x0FF8: // Set the current bank to the fourth 4k bank bank(3); break; case 0x0FF9: // Set the current bank to the fifth 4k bank bank(4); break; case 0x0FFA: // Set the current bank to the sixth 4k bank bank(5); break; case 0x0FFB: // Set the current bank to the seventh 4k bank // This is only available on 28K ROMs if(mySize == 28*1024) bank(6); break; default: break; } // NOTE: This does not handle accessing RAM, however, this function // should never be called for RAM because of the way page accessing // has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA2::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FF4 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Setup the page access methods for the current bank for(uInt16 addr = 0x1200; addr < (0x1FF4U & ~System::PAGE_MASK); addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFA2::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFA2::bankCount() const { return (mySize / 4096); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA2::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; if(address < 0x0200) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x00FF] = value; } else myImage[myBankOffset + address] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeFA2::getImage(uInt32& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA2::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); out.putByteArray(myRAM, 256); } catch(...) { cerr << "ERROR: CartridgeFA2::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFA2::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); in.getByteArray(myRAM, 256); } catch(...) { cerr << "ERROR: CartridgeFA2::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2::setRomName(const string& name) { myFlashFile = myOSystem.nvramDir() + name + "_flash.dat"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFA2::ramReadWrite() { /* The following algorithm implements accessing Harmony cart flash 1. Wait for an access to hotspot location $1FF4 (return 1 in bit 6 while busy). 2. Read byte 256 of RAM+ memory to determine the operation requested (1 = read, 2 = write). 3. Save or load the entire 256 bytes of RAM+ memory to a file. 4. Set byte 256 of RAM+ memory to zero to indicate success (will always happen in emulation). 5. Return 0 (in bit 6) on the next access to $1FF4, if enough time has passed to complete the operation on a real system (0.5 ms for read, 101 ms for write). */ // First access sets the timer if(myRamAccessTimeout == 0) { // Remember when the first access was made myRamAccessTimeout = myOSystem.getTicks(); // We go ahead and do the access now, and only return when a sufficient // amount of time has passed Serializer serializer(myFlashFile); if(serializer) { if(myRAM[255] == 1) // read { try { serializer.getByteArray(myRAM, 256); } catch(...) { memset(myRAM, 0, 256); } myRamAccessTimeout += 500; // Add 0.5 ms delay for read } else if(myRAM[255] == 2) // write { try { serializer.putByteArray(myRAM, 256); } catch(...) { // Maybe add logging here that save failed? cerr << name() << ": ERROR saving score table" << endl; } myRamAccessTimeout += 101000; // Add 101 ms delay for write } } // Bit 6 is 1, busy return myImage[myBankOffset + 0xFF4] | 0x40; } else { // Have we reached the timeout value yet? if(myOSystem.getTicks() >= myRamAccessTimeout) { myRamAccessTimeout = 0; // Turn off timer myRAM[255] = 0; // Successful operation // Bit 6 is 0, ready/success return myImage[myBankOffset + 0xFF4] & ~0x40; } else // Bit 6 is 1, busy return myImage[myBankOffset + 0xFF4] | 0x40; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFA2::flash(uInt8 operation) { Serializer serializer(myFlashFile); if(serializer) { if(operation == 0) // erase { try { uInt8 buf[256]; memset(buf, 0, 256); serializer.putByteArray(buf, 256); } catch(...) { } } else if(operation == 1) // read { try { serializer.getByteArray(myRAM, 256); } catch(...) { memset(myRAM, 0, 256); } } else if(operation == 2) // write { try { serializer.putByteArray(myRAM, 256); } catch(...) { // Maybe add logging here that save failed? cerr << name() << ": ERROR saving score table" << endl; } } } } stella-5.1.1/src/emucore/CartFA2.hxx000066400000000000000000000150561324334165500171600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEFA2_HXX #define CARTRIDGEFA2_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartFA2Widget.hxx" #endif /** This is an extended version of the CBS RAM Plus bankswitching scheme supported by the Harmony cartridge. There are six (or seven) 4K banks, accessible by read/write to $1FF5 - $1FFA (or $1FFB), and 256 bytes of RAM. The 256 bytes of RAM can be loaded/saved to Harmony cart flash by accessing $1FF4 (see ramReadWrite() for more information), which is emulated by storing in a file. RAM read port is $1100 - $11FF, write port is $1000 - $10FF. For 29K versions of the scheme, the first 1K is ARM code (implements actual bankswitching on the Harmony cart), which is completely ignored by the emulator. Also supported is a 32K variant. In any event, only data at 1K - 29K of the ROM is used. @author Chris D. Walton */ class CartridgeFA2 : public Cartridge { friend class CartridgeFA2Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param osystem A reference to the OSystem currently in use */ CartridgeFA2(const BytePtr& image, uInt32 size, const OSystem& osystem); virtual ~CartridgeFA2() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeFA2"; } /** Informs the cartridge about the name of the ROM file used when creating this cart. @param name The properties file name of the ROM */ void setRomName(const string& name) override; #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeFA2Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Either load or save internal RAM to Harmony flash (represented by a file in emulation). @return The value at $FF4 with bit 6 set or cleared (depending on whether the RAM access was busy or successful) */ uInt8 ramReadWrite(); /** Modify Harmony flash directly (represented by a file in emulation), ignoring any timing emulation. This is for use strictly in the debugger, so you can have low-level access to the Flash media. @param operation 0 for erase, 1 for read, 2 for write */ void flash(uInt8 operation); private: // OSsytem currently in use const OSystem& myOSystem; // The 24K/28K ROM image of the cartridge uInt8 myImage[28 * 1024]; // Actual usable size of the ROM image uInt32 mySize; // The 256 bytes of RAM on the cartridge uInt8 myRAM[256]; // The time after which the first request of a load/save operation // will actually be completed // Due to flash RAM constraints, a read/write isn't instantaneous, // so we need to emulate the delay as well uInt64 myRamAccessTimeout; // Full pathname of the file to use when emulating load/save // of internal RAM to Harmony cart flash string myFlashFile; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeFA2() = delete; CartridgeFA2(const CartridgeFA2&) = delete; CartridgeFA2(CartridgeFA2&&) = delete; CartridgeFA2& operator=(const CartridgeFA2&) = delete; CartridgeFA2& operator=(CartridgeFA2&&) = delete; }; #endif stella-5.1.1/src/emucore/CartFE.cxx000066400000000000000000000113611324334165500170700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "M6532.hxx" #include "System.hxx" #include "CartFE.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeFE::CartridgeFE(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0), myLastAccessWasFE(false) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(8192u, size)); createCodeAccessBase(8192); myStartBank = 0; // Decathlon requires this, since there is no startup vector in bank 1 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFE::reset() { bank(myStartBank); myLastAccessWasFE = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFE::install(System& system) { mySystem = &system; // The hotspot $01FE is in a mirror of zero-page RAM // We need to claim access to it here, and deal with it in peek/poke below System::PageAccess access(this, System::PA_READWRITE); for(uInt16 addr = 0x180; addr < 0x200; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Map all of the cart accesses to call peek and poke access.type = System::PA_READ; for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeFE::peek(uInt16 address) { uInt8 value = (address < 0x200) ? mySystem->m6532().peek(address) : myImage[myBankOffset + (address & 0x0FFF)]; // Check if we hit hotspot checkBankSwitch(address, value); return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::poke(uInt16 address, uInt8 value) { if(address < 0x200) mySystem->m6532().poke(address, value); // Check if we hit hotspot checkBankSwitch(address, value); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeFE::checkBankSwitch(uInt16 address, uInt8 value) { if(bankLocked()) return; // Did we detect $01FE on the last address bus access? // If so, we bankswitch according to the upper 3 bits of the data bus // NOTE: see the header file for the significance of 'value & 0x20' if(myLastAccessWasFE) bank((value & 0x20) ? 0 : 1); // On the next cycle, we use the (then) current data bus value to decode // the bank to use myLastAccessWasFE = address == 0x01FE; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::bank(uInt16 bank) { if(bankLocked()) return false; myBankOffset = bank << 12; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFE::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeFE::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeFE::getImage(uInt32& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); out.putBool(myLastAccessWasFE); } catch(...) { cerr << "ERROR: CartridgeFE::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeFE::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); myLastAccessWasFE = in.getBool(); } catch(...) { cerr << "ERROR: CartridgeF8SC::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/CartFE.hxx000066400000000000000000000165021324334165500170770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEFE_HXX #define CARTRIDGEFE_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartFEWidget.hxx" #endif /** Bankswitching method used by Activision's Robot Tank and Decathlon. This scheme was originally designed to have up to 8 4K banks, and is triggered by monitoring the address bus for address $01FE. All released carts had only two banks, and this implementation assumes that (ie, ROM is always 8K, and there are two 4K banks). The following is paraphrased from the original patent by David Crane, European Patent Application # 84300730.3, dated 06.02.84: --------------------------------------------------------------------------- The twelve line address bus is connected to a plurality of 4K by eight bit memories. The eight line data bus is connected to each of the banks of memory, also. An address comparator is connected to the bus for detecting the presence of the 01FE address. Actually, the comparator will detect only the lowest 12 bits of 1FE, because of the twelve bit limitation of the address bus. Upon detection of the 01FE address, a one cycle delay is activated which then actuates latch connected to the data bus. The three most significant bits on the data bus are latched and provide the address bits A13, A14, and A15 which are then applied to a 3 to 8 de-multiplexer. The 3 bits A13-A15 define a code for selecting one of the eight banks of memory which is used to enable one of the banks of memory by applying a control signal to the enable, EN, terminal thereof. Accordingly, memory bank selection is accomplished from address codes on the data bus following a particular program instruction, such as a jump to subroutine. --------------------------------------------------------------------------- Note that in the general scheme, we use D7, D6 and D5 for the bank number (3 bits, so 8 possible banks). However, the scheme as used historically by Activision only uses two banks. Furthermore, the two banks it uses are actually indicated by binary 110 and 111, and translated as follows: binary 110 -> decimal 6 -> Upper 4K ROM (bank 1) @ $D000 - $DFFF binary 111 -> decimal 7 -> Lower 4K ROM (bank 0) @ $F000 - $FFFF Since the actual bank numbers (0 and 1) do not map directly to their respective bitstrings (7 and 6), we simply test for D5 being 0 or 1. This is the significance of the test '(value & 0x20) ? 0 : 1' in the code. NOTE: Consult the patent application for more specific information, in particular *why* the address $01FE will be placed on the address bus after both the JSR and RTS opcodes. @author Stephen Anthony; with ideas/research from Christian Speckner and alex_79 and TomSon (of AtariAge) */ class CartridgeFE : public Cartridge { friend class CartridgeFEWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeFE(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeFE() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeFE"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeFEWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value. @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Perform bankswitch when necessary, by monitoring for $01FE on the address bus and getting the bank number from the data bus. */ void checkBankSwitch(uInt16 address, uInt8 value); private: // The 8K ROM image of the cartridge uInt8 myImage[8192]; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; // Whether previous address by peek/poke equals $01FE (hotspot) bool myLastAccessWasFE; private: // Following constructors and assignment operators not supported CartridgeFE() = delete; CartridgeFE(const CartridgeFE&) = delete; CartridgeFE(CartridgeFE&&) = delete; CartridgeFE& operator=(const CartridgeFE&) = delete; CartridgeFE& operator=(CartridgeFE&&) = delete; }; #endif stella-5.1.1/src/emucore/CartMDM.cxx000066400000000000000000000130761324334165500172200ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartMDM.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMDM::CartridgeMDM(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), myBankOffset(0), myBankingDisabled(false) { // Allocate array for the ROM image myImage = make_unique(mySize); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), mySize); createCodeAccessBase(mySize); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMDM::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMDM::install(System& system) { mySystem = &system; // Get the page accessing methods for the hot spots since they overlap // areas within the TIA we'll need to forward requests to the TIA myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800); myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900); myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00); myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00); myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00); myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00); myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00); myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00); // Set the page accessing methods for the hot spots System::PageAccess access(this, System::PA_READWRITE); for(uInt16 addr = 0x0800; addr < 0x0BFF; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Install pages for bank 0 bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeMDM::peek(uInt16 address) { // Because of the way we've set up accessing above, we can only // get here when the addresses are from 0x800 - 0xBFF if((address & 0x1C00) == 0x0800) bank(address & 0x0FF); int hotspot = ((address & 0x0F00) >> 8) - 8; return myHotSpotPageAccess[hotspot].device->peek(address); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMDM::poke(uInt16 address, uInt8 value) { // All possible addresses can appear here, but we only care // about those below $1000 if(!(address & 0x1000)) { if((address & 0x1C00) == 0x0800) bank(address & 0x0FF); int hotspot = ((address & 0x0F00) >> 8) - 8; myHotSpotPageAccess[hotspot].device->poke(address, value); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMDM::bank(uInt16 bank) { if(bankLocked() || myBankingDisabled) return false; // Remember what bank we're in // Wrap around to a valid bank number if necessary myBankOffset = (bank % bankCount()) << 12; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } // Accesses above bank 127 disable further bankswitching; we're only // concerned with the lower byte myBankingDisabled = myBankingDisabled || bank > 127; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeMDM::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeMDM::bankCount() const { return mySize >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMDM::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeMDM::getImage(uInt32& size) const { size = mySize; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMDM::save(Serializer& out) const { try { out.putString(name()); out.putInt(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeMDM::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMDM::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getInt(); } catch(...) { cerr << "ERROR: CartridgeMDM::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartMDM.hxx000066400000000000000000000130511324334165500172160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEMDM_HXX #define CARTRIDGEMDM_HXX #include "bspf.hxx" #include "Cart.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "CartMDMWidget.hxx" #endif /** Cartridge class used for "Menu Driven Megacart" as described at the following link and developed by Edwin Blink: http://atariage.com/forums/topic/56073-cheap-2k4k-x-in-1-menu-driven-multicart-for-atari-2600 Note that this code implements a modified scheme (as designed by E. Blink). In this version, the hotspots are from $800 to $BFF instead of $800 to $FFF. The hotspots in this scheme are read/write at addresses $800 to $BFF, where the lower byte determines the actual 4K bank switch to. In the current implementation, only 128 banks are supported, so selecting bank 128+ results in further bankswitching being locked. A reset line is used to reset to bank 0 and re-enable bankswitching. Therefore, there are 128 banks / 512K possible in total. @author Stephen Anthony, based on 0840 scheme by Fred X. Quimby */ class CartridgeMDM : public Cartridge { friend class CartridgeMDMWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeMDM(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeMDM() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeMDM"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeMDMWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // Pointer to a dynamically allocated ROM image of the cartridge BytePtr myImage; // Size of the ROM image uInt32 mySize; // Previous Device's page access System::PageAccess myHotSpotPageAccess[8]; // Indicates the offset into the ROM image (aligns to current bank) uInt32 myBankOffset; // Indicates whether banking has been disabled due to a bankswitch // above bank 127 bool myBankingDisabled; private: // Following constructors and assignment operators not supported CartridgeMDM() = delete; CartridgeMDM(const CartridgeMDM&) = delete; CartridgeMDM(CartridgeMDM&&) = delete; CartridgeMDM& operator=(const CartridgeMDM&) = delete; CartridgeMDM& operator=(CartridgeMDM&&) = delete; }; #endif stella-5.1.1/src/emucore/CartMNetwork.cxx000066400000000000000000000220111324334165500203360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartMNetwork.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeMNetwork::CartridgeMNetwork(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), myCurrentRAM(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetwork::initialize(const BytePtr& image, uInt32 size) { // Allocate array for the ROM image myImage = make_unique(size); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), std::min(romSize(), size)); createCodeAccessBase(romSize() + RAM_SIZE); // Remember startup bank myStartBank = 0; myRAMSlice = bankCount() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetwork::reset() { initializeRAM(myRAM, RAM_SIZE); // define random startup banks randomizeStartBank(); uInt32 ramBank = randomStartBank() ? mySystem->randGenerator().next() % 4 : 0; // Install some default banks for the RAM and first segment bankRAM(ramBank); bank(myStartBank); myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetwork::setAccess(uInt16 addrFrom, uInt16 size, uInt16 directOffset, uInt8* directData, uInt16 codeOffset, System::PageAccessType type, uInt16 addrMask) { if(addrMask == 0) addrMask = size - 1; System::PageAccess access(this, type); for(uInt16 addr = addrFrom; addr < addrFrom + size; addr += System::PAGE_SIZE) { if (type == System::PA_READ) access.directPeekBase = &directData[directOffset + (addr & addrMask)]; if(type == System::PA_WRITE) access.directPokeBase = &directData[directOffset + (addr & addrMask)]; access.codeAccessBase = &myCodeAccessBase[codeOffset + (addr & addrMask)]; mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetwork::install(System& system) { mySystem = &system; System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = (0x1FE0 & ~System::PAGE_MASK); addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[0x1fc0]; mySystem->setPageAccess(addr, access); } /*setAccess(0x1FE0 & ~System::PAGE_MASK, System::PAGE_SIZE, 0, nullptr, 0x1fc0, System::PA_NONE, 0x1fc0);*/ // Setup the second segment to always point to the last ROM slice setAccess(0x1A00, 0x1FE0U & (~System::PAGE_MASK - 0x1A00), myRAMSlice * BANK_SIZE, myImage.get(), myRAMSlice * BANK_SIZE, System::PA_READ, BANK_SIZE - 1); myCurrentSlice[1] = myRAMSlice; // Install some default banks for the RAM and first segment bankRAM(0); bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeMNetwork::peek(uInt16 address) { uInt16 peekAddress = address; address &= 0x0FFF; // Switch banks if necessary checkSwitchBank(address); if((myCurrentSlice[0] == myRAMSlice) && (address < BANK_SIZE / 2)) { // Reading from the 1K write port @ $1000 triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address & (BANK_SIZE / 2 - 1)] = value; } } else if((address >= 0x0800) && (address <= 0x08FF)) { // Reading from the 256B write port @ $1800 triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[1024 + (myCurrentRAM << 8) + (address & 0x00FF)] = value; } } else return myImage[(myCurrentSlice[address >> 11] << 11) + (address & (BANK_SIZE - 1))]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMNetwork::poke(uInt16 address, uInt8) { address &= 0x0FFF; // Switch banks if necessary checkSwitchBank(address); // NOTE: This does not handle writing to RAM, however, this // method should never be called for RAM because of the // way page accessing has been setup return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeMNetwork::bankRAM(uInt16 bank) { if(bankLocked()) return; // Remember what bank we're in myCurrentRAM = bank; uInt16 offset = bank << 8; // * RAM_SLICE_SIZE (256) // Setup the page access methods for the current bank // Set the page accessing method for the 256 bytes of RAM reading pages setAccess(0x1800, 0x100, 1024 + offset, myRAM, romSize() + BANK_SIZE / 2, System::PA_WRITE); // Set the page accessing method for the 256 bytes of RAM reading pages setAccess(0x1900, 0x100, 1024 + offset, myRAM, romSize() + BANK_SIZE / 2, System::PA_READ); myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMNetwork::bank(uInt16 slice) { if(bankLocked()) return false; // Remember what bank we're in myCurrentSlice[0] = slice; // Setup the page access methods for the current bank if(slice != myRAMSlice) { uInt16 offset = slice << 11; // * BANK_SIZE (2048) // Map ROM image into first segment setAccess(0x1000, BANK_SIZE, offset, myImage.get(), offset, System::PA_READ); } else { // Set the page accessing method for the 1K slice of RAM writing pages setAccess(0x1000, BANK_SIZE / 2, 0, myRAM, romSize(), System::PA_WRITE); // Set the page accessing method for the 1K slice of RAM reading pages setAccess(0x1000 + BANK_SIZE / 2, BANK_SIZE / 2, 0, myRAM, romSize(), System::PA_READ); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeMNetwork::getBank() const { return myCurrentSlice[0]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMNetwork::patch(uInt16 address, uInt8 value) { address = address & 0x0FFF; if(address < 0x0800) { if(myCurrentSlice[0] == myRAMSlice) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[address & 0x03FF] = value; } else myImage[(myCurrentSlice[0] << 11) + (address & (BANK_SIZE-1))] = value; } else if(address < 0x0900) { // Normally, a write to the read port won't do anything // However, the patch command is special in that ignores such // cart restrictions myRAM[1024 + (myCurrentRAM << 8) + (address & 0x00FF)] = value; } else myImage[(myCurrentSlice[address >> 11] << 11) + (address & (BANK_SIZE-1))] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeMNetwork::getImage(uInt32& size) const { size = bankCount() * BANK_SIZE; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMNetwork::save(Serializer& out) const { try { out.putString(name()); out.putShortArray(myCurrentSlice, NUM_SEGMENTS); out.putShort(myCurrentRAM); out.putByteArray(myRAM, RAM_SIZE); } catch(...) { cerr << "ERROR: " << name() << "::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeMNetwork::load(Serializer& in) { try { if(in.getString() != name()) return false; in.getShortArray(myCurrentSlice, NUM_SEGMENTS); myCurrentRAM = in.getShort(); in.getByteArray(myRAM, RAM_SIZE); } catch(...) { cerr << "ERROR: " << name() << "::load" << endl; return false; } // Set up the previously used banks for the RAM and segment bankRAM(myCurrentRAM); bank(myCurrentSlice[0]); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeMNetwork::bankCount() const { return mySize >> 11; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 CartridgeMNetwork::romSize() const { return bankCount() * BANK_SIZE; } stella-5.1.1/src/emucore/CartMNetwork.hxx000066400000000000000000000152651324334165500203600ustar00rootroot00000000000000 //============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGE_MNETWORK_HXX #define CARTRIDGE_MNETWORK_HXX #include "System.hxx" #include "bspf.hxx" #include "Cart.hxx" /** This is the abstract cartridge class for M-Network bankswitched games. In this bankswitching scheme the 2600's 4K cartridge address space is broken into two 2K segments. Kevin Horton describes E7 as follows: "Only M-Network used this scheme. This has to be the most complex method used in any cart! :-) It allows for the capability of 2K of RAM; although it doesn't have to be used (in fact, only one cart used it). There are now 8 2K banks, instead of 4. The last 2K in the cart always points to the last 2K of the ROM image, while the first 2K is selectable. You access 1FE0 to 1FE6 to select which 2K bank. Note that you cannot select the last 2K of the ROM image into the lower 2K of the cart! Accessing 1FE7 selects 1K of RAM at 1000-17FF instead of ROM! The 2K of RAM is broken up into two 1K sections. One 1K section is mapped in at 1000-17FF if 1FE7 has been accessed. 1000-13FF is the write port, while 1400-17FF is the read port. The second 1K of RAM appears at 1800-19FF. 1800-18FF is the write port while 1900-19FF is the read port. You select which 256 byte block appears here by accessing 1FE8 to 1FEB. This cart reports having 8 banks; 1 for each of the possible 7 slices in the lower 2K area, and the last for RAM in the lower 2K area." There are 8K, 12K and 16K variations, with or without RAM. @author Bradford W. Mott, Thomas Jentzsch */ class CartridgeMNetwork : public Cartridge { friend class CartridgeMNetworkWidget; friend class CartridgeE7Widget; friend class CartridgeE78KWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeMNetwork(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeMNetwork() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; protected: /** Class initialization */ void initialize(const BytePtr& image, uInt32 size); /** Install pages for the specified 256 byte bank of RAM @param bank The bank that should be installed in the system */ void bankRAM(uInt16 bank); // Size of a ROM or RAM bank static constexpr uInt32 BANK_SIZE = 0x800; // 2K private: // Size of RAM in the cart static constexpr uInt32 RAM_SIZE = 0x800; // 1K + 4 * 256B = 2K // Number of slices with 4K address space static constexpr uInt32 NUM_SEGMENTS = 2; /** Query the size of the BS type. */ uInt32 romSize() const; /** Check hotspots and switch bank if triggered. */ virtual void checkSwitchBank(uInt16 address) = 0; void setAccess(uInt16 addrFrom, uInt16 size, uInt16 directOffset, uInt8* directData, uInt16 codeOffset, System::PageAccessType type, uInt16 addrMask = 0); private: // Pointer to a dynamically allocated ROM image of the cartridge BytePtr myImage; // The 16K ROM image of the cartridge (works for E78K too) //uInt8 myImage[BANK_SIZE * 8]; // Size of the ROM image uInt32 mySize; // The 2K of RAM uInt8 myRAM[RAM_SIZE]; // Indicates which slice is in the segment uInt16 myCurrentSlice[NUM_SEGMENTS]; // Indicates which 256 byte bank of RAM is being used uInt16 myCurrentRAM; // The number of the RAM slice (== bankCount() - 1) uInt32 myRAMSlice; private: // Following constructors and assignment operators not supported CartridgeMNetwork() = delete; CartridgeMNetwork(const CartridgeMNetwork&) = delete; CartridgeMNetwork(CartridgeMNetwork&&) = delete; CartridgeMNetwork& operator=(const CartridgeMNetwork&) = delete; CartridgeMNetwork& operator=(CartridgeMNetwork&&) = delete; }; #endif stella-5.1.1/src/emucore/CartSB.cxx000066400000000000000000000130241324334165500171000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartSB.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeSB::CartridgeSB(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(size), myBankOffset(0) { // Allocate array for the ROM image myImage = make_unique(mySize); // Copy the ROM image into my buffer memcpy(myImage.get(), image.get(), mySize); createCodeAccessBase(mySize); // Remember startup bank myStartBank = bankCount() - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeSB::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeSB::install(System& system) { mySystem = &system; // Get the page accessing methods for the hot spots since they overlap // areas within the TIA we'll need to forward requests to the TIA myHotSpotPageAccess[0] = mySystem->getPageAccess(0x0800); myHotSpotPageAccess[1] = mySystem->getPageAccess(0x0900); myHotSpotPageAccess[2] = mySystem->getPageAccess(0x0A00); myHotSpotPageAccess[3] = mySystem->getPageAccess(0x0B00); myHotSpotPageAccess[4] = mySystem->getPageAccess(0x0C00); myHotSpotPageAccess[5] = mySystem->getPageAccess(0x0D00); myHotSpotPageAccess[6] = mySystem->getPageAccess(0x0E00); myHotSpotPageAccess[7] = mySystem->getPageAccess(0x0F00); System::PageAccess access(this, System::PA_READ); // Set the page accessing methods for the hot spots for(uInt16 addr = 0x0800; addr < 0x0FFF; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Install pages for startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeSB::peek(uInt16 address) { address &= (0x17FF + (mySize >> 12)); // Switch banks if necessary if ((address & 0x1800) == 0x0800) bank(address & myStartBank); if(!(address & 0x1000)) { // Because of the way we've set up accessing above, we can only // get here when the addresses are from 0x800 - 0xFFF int hotspot = ((address & 0x0F00) >> 8) - 8; return myHotSpotPageAccess[hotspot].device->peek(address); } return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::poke(uInt16 address, uInt8 value) { address &= (0x17FF + (mySize >> 12)); // Switch banks if necessary if((address & 0x1800) == 0x0800) bank(address & myStartBank); if(!(address & 0x1000)) { // Because of the way we've set up accessing above, we can only // get here when the addresses are from 0x800 - 0xFFF int hotspot = ((address & 0x0F00) >> 8) - 8; myHotSpotPageAccess[hotspot].device->poke(address, value); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeSB::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeSB::bankCount() const { return mySize >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeSB::getImage(uInt32& size) const { size = mySize; return myImage.get(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::save(Serializer& out) const { try { out.putString(name()); out.putInt(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeSB::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeSB::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getInt(); } catch(...) { cerr << "ERROR: CartridgeSB::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartSB.hxx000066400000000000000000000114661324334165500171150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGESB_HXX #define CARTRIDGESB_HXX #include "bspf.hxx" #include "Cart.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "CartSBWidget.hxx" #endif /** Cartridge class used for SB "SUPERbanking" 128k-256k bankswitched games. There are either 32 or 64 4K banks, accessible at hotspots $800 - $81F (32 banks) and $800 - $83F (64 banks). All mirrors up to $FFF are also used ($900, $A00, ...). @author Fred X. Quimby */ class CartridgeSB : public Cartridge { friend class CartridgeSBWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeSB(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeSB() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeSB"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeSBWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 128-256K ROM image and size of the cartridge BytePtr myImage; uInt32 mySize; // Indicates the offset into the ROM image (aligns to current bank) uInt32 myBankOffset; // Previous Device's page access System::PageAccess myHotSpotPageAccess[8]; private: // Following constructors and assignment operators not supported CartridgeSB() = delete; CartridgeSB(const CartridgeSB&) = delete; CartridgeSB(CartridgeSB&&) = delete; CartridgeSB& operator=(const CartridgeSB&) = delete; CartridgeSB& operator=(CartridgeSB&&) = delete; }; #endif stella-5.1.1/src/emucore/CartUA.cxx000066400000000000000000000122021324334165500170760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "CartUA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeUA::CartridgeUA(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myBankOffset(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(8192u, size)); createCodeAccessBase(8192); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeUA::reset() { // define startup bank randomizeStartBank(); // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeUA::install(System& system) { mySystem = &system; // Get the page accessing methods for the hot spots since they overlap // areas within the TIA we'll need to forward requests to the TIA myHotSpotPageAccess = mySystem->getPageAccess(0x0220); // Set the page accessing methods for the hot spots System::PageAccess access(this, System::PA_READ); mySystem->setPageAccess(0x0220, access); mySystem->setPageAccess(0x0240, access); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeUA::peek(uInt16 address) { address &= 0x1FFF; // Switch banks if necessary switch(address) { case 0x0220: // Set the current bank to the lower 4k bank bank(0); break; case 0x0240: // Set the current bank to the upper 4k bank bank(1); break; default: break; } // Because of the way accessing is set up, we will only get here // when doing a TIA read return myHotSpotPageAccess.device->peek(address); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::poke(uInt16 address, uInt8 value) { address &= 0x1FFF; // Switch banks if necessary switch(address) { case 0x0220: // Set the current bank to the lower 4k bank bank(0); break; case 0x0240: // Set the current bank to the upper 4k bank bank(1); break; default: break; } // Because of the way accessing is set up, we will may get here by // doing a write to TIA or cart; we ignore the cart write if(!(address & 0x1000)) myHotSpotPageAccess.device->poke(address, value); return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myBankOffset = bank << 12; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[myBankOffset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[myBankOffset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeUA::getBank() const { return myBankOffset >> 12; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeUA::bankCount() const { return 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::patch(uInt16 address, uInt8 value) { myImage[myBankOffset + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeUA::getImage(uInt32& size) const { size = 8192; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::save(Serializer& out) const { try { out.putString(name()); out.putShort(myBankOffset); } catch(...) { cerr << "ERROR: CartridgeUA::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeUA::load(Serializer& in) { try { if(in.getString() != name()) return false; myBankOffset = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeUA::load" << endl; return false; } // Remember what bank we were in bank(myBankOffset >> 12); return true; } stella-5.1.1/src/emucore/CartUA.hxx000066400000000000000000000112761324334165500171150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEUA_HXX #define CARTRIDGEUA_HXX #include "bspf.hxx" #include "Cart.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "CartUAWidget.hxx" #endif /** Cartridge class used for UA Limited's 8K bankswitched games. There are two 4K banks, which are switched by accessing $0220 (bank 0) and $0240 (bank 1). @author Bradford W. Mott */ class CartridgeUA : public Cartridge { friend class CartridgeUAWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeUA(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeUA() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeUA"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeUAWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 8K ROM image of the cartridge uInt8 myImage[8192]; // Previous Device's page access System::PageAccess myHotSpotPageAccess; // Indicates the offset into the ROM image (aligns to current bank) uInt16 myBankOffset; private: // Following constructors and assignment operators not supported CartridgeUA() = delete; CartridgeUA(const CartridgeUA&) = delete; CartridgeUA(CartridgeUA&&) = delete; CartridgeUA& operator=(const CartridgeUA&) = delete; CartridgeUA& operator=(CartridgeUA&&) = delete; }; #endif stella-5.1.1/src/emucore/CartWD.cxx000066400000000000000000000224261324334165500171140ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "TIA.hxx" #include "M6502.hxx" #include "System.hxx" #include "CartWD.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWD::CartridgeWD(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), mySize(std::min(8195u, size)), myCyclesAtBankswitchInit(0), myPendingBank(0), myCurrentBank(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), mySize); createCodeAccessBase(8192); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::reset() { initializeRAM(myRAM, 64); myCyclesAtBankswitchInit = 0; myPendingBank = 0xF0; // one more than the allowable bank # // Setup segments to some default slices bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::install(System& system) { mySystem = &system; // Set the page accessing method for the RAM reading pages System::PageAccess read(this, System::PA_READ); for(uInt16 addr = 0x1000; addr < 0x1040; addr += System::PAGE_SIZE) { read.directPeekBase = &myRAM[addr & 0x003F]; read.codeAccessBase = &myCodeAccessBase[addr & 0x003F]; mySystem->setPageAccess(addr, read); } // Set the page accessing method for the RAM writing pages System::PageAccess write(this, System::PA_WRITE); for(uInt16 addr = 0x1040; addr < 0x1080; addr += System::PAGE_SIZE) { write.directPokeBase = &myRAM[addr & 0x003F]; write.codeAccessBase = &myCodeAccessBase[addr & 0x003F]; mySystem->setPageAccess(addr, write); } // Mirror all access in TIA; by doing so we're taking responsibility // for that address space in peek and poke below. mySystem->tia().installDelegate(system, *this); // Setup segments to some default slices bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeWD::peek(uInt16 address) { // Is it time to do an actual bankswitch? if(myPendingBank != 0xF0 && !bankLocked() && mySystem->cycles() > (myCyclesAtBankswitchInit + 3)) { bank(myPendingBank); myPendingBank = 0xF0; } if(!(address & 0x1000)) // Hotspots below 0x1000 are also TIA addresses { // Hotspots at $30 - $3F // Note that a hotspot read triggers a bankswitch after at least 3 cycles // have passed, so we only initiate the switch here if(!bankLocked() && (address & 0x00FF) >= 0x30 && (address & 0x00FF) <= 0x3F) { myCyclesAtBankswitchInit = mySystem->cycles(); myPendingBank = address & 0x000F; } return mySystem->tia().peek(address); } else { uInt16 peekAddress = address; address &= 0x0FFF; if(address < 0x0040) // RAM read port return myRAM[address]; else if(address < 0x0080) // RAM write port { // Reading from the write port @ $1040 - $107F triggers an unwanted write uInt8 value = mySystem->getDataBusState(0xFF); if(bankLocked()) return value; else { triggerReadFromWritePort(peekAddress); return myRAM[address & 0x003F] = value; } } else if(address < 0x0400) return myImage[myOffset[0] + (address & 0x03FF)]; else if(address < 0x0800) return myImage[myOffset[1] + (address & 0x03FF)]; else if(address < 0x0C00) return myImage[myOffset[2] + (address & 0x03FF)]; else return mySegment3[address & 0x03FF]; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::poke(uInt16 address, uInt8 value) { // Only TIA writes will reach here if(!(address & 0x1000)) return mySystem->tia().poke(address, value); else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::bank(uInt16 bank) { if(bankLocked() || bank > 15) return false; myCurrentBank = bank; segmentZero(ourBankOrg[bank].zero); segmentOne(ourBankOrg[bank].one); segmentTwo(ourBankOrg[bank].two); segmentThree(ourBankOrg[bank].three, ourBankOrg[bank].map3bytes); return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::segmentZero(uInt8 slice) { uInt16 offset = slice << 10; System::PageAccess access(this, System::PA_READ); // Skip first 128 bytes; it is always RAM for(uInt16 addr = 0x1080; addr < 0x1400; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myOffset[0] = offset; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::segmentOne(uInt8 slice) { uInt16 offset = slice << 10; System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1400; addr < 0x1800; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myOffset[1] = offset; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::segmentTwo(uInt8 slice) { uInt16 offset = slice << 10; System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1800; addr < 0x1C00; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myOffset[2] = offset; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeWD::segmentThree(uInt8 slice, bool map3bytes) { uInt16 offset = slice << 10; // Make a copy of the address space pointed to by the slice // Then map in the extra 3 bytes, if required memcpy(mySegment3, myImage+offset, 1024); if(mySize == 8195 && map3bytes) { mySegment3[0x3FC] = myImage[0x2000+0]; mySegment3[0x3FD] = myImage[0x2000+1]; mySegment3[0x3FE] = myImage[0x2000+2]; } System::PageAccess access(this, System::PA_READ); for(uInt16 addr = 0x1C00; addr < 0x2000; addr += System::PAGE_SIZE) { access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x03FF)]; mySystem->setPageAccess(addr, access); } myOffset[3] = offset; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeWD::getBank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeWD::bankCount() const { return 16; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::patch(uInt16 address, uInt8 value) { address &= 0x0FFF; uInt16 idx = address >> 10; myImage[myOffset[idx] + (address & 0x03FF)] = value; // The upper segment is mirrored, so we need to patch its buffer too if(idx == 3) mySegment3[(address & 0x03FF)] = value; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeWD::getImage(uInt32& size) const { size = mySize; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); out.putByteArray(myRAM, 64); out.putLong(myCyclesAtBankswitchInit); out.putShort(myPendingBank); } catch(...) { cerr << "ERROR: CartridgeWD::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeWD::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); in.getByteArray(myRAM, 64); myCyclesAtBankswitchInit = in.getLong(); myPendingBank = in.getShort(); bank(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeWD::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeWD::BankOrg CartridgeWD::ourBankOrg[16] = { { 0, 0, 1, 2, false }, // Bank 0 { 0, 1, 3, 2, false }, // Bank 1 { 4, 5, 6, 7, false }, // Bank 2 { 7, 4, 3, 2, false }, // Bank 3 { 0, 0, 6, 7, false }, // Bank 4 { 0, 1, 7, 6, false }, // Bank 5 { 3, 2, 4, 5, false }, // Bank 6 { 6, 0, 5, 1, false }, // Bank 7 { 0, 0, 1, 2, false }, // Bank 8 { 0, 1, 3, 2, false }, // Bank 9 { 4, 5, 6, 7, false }, // Bank 10 { 7, 4, 3, 2, false }, // Bank 11 { 0, 0, 6, 7, true }, // Bank 12 { 0, 1, 7, 6, true }, // Bank 13 { 3, 2, 4, 5, true }, // Bank 14 { 6, 0, 5, 1, true } // Bank 15 }; stella-5.1.1/src/emucore/CartWD.hxx000066400000000000000000000157751324334165500171320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEWD_HXX #define CARTRIDGEWD_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartWDWidget.hxx" #endif /** This is the cartridge class for a "Wickstead Design" prototype cart. The ROM is normally 8K, but sometimes has an extra 3 bytes appended, to be mapped as described below. There is also 64 bytes of RAM. In this bankswitching scheme the 2600's 4K cartridge address space is broken into four 1K segments. The desired arrangement of 1K slices is selected by accessing $30 - $3F of TIA address space. The slices are mapped into all 4 segments at once as follows: $0030: 0,0,1,2 $0031: 0,1,3,2 $0032: 4,5,6,7 $0033: 7,4,3,2 $0034: 0,0,6,7 $0035: 0,1,7,6 $0036: 3,2,4,5 $0037: 6,0,5,1 $0038: 0,0,1,2 $0039: 0,1,3,2 $003A: 4,5,6,7 $003B: 7,4,3,2 $003C: 0,0,6,7* $003D: 0,1,7,6* $003E: 3,2,4,5* $003F: 6,0,5,1* In the last 4 cases, the extra 3 bytes of ROM past the 8K boundary are mapped into $3FC - $3FE of the uppermost (third) segment. The 64 bytes of RAM are accessible at $1000 - $103F (read port) and $1040 - $107F (write port). Because the RAM takes 128 bytes of address space, the range $1000 - $107F of segment 0 ROM will never be available. @author Stephen Anthony */ class CartridgeWD : public Cartridge { friend class CartridgeWDWidget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeWD(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeWD() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeWD"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeWDWidget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value. @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: /** Install the specified slice for segment zero. @param slice The slice to map into the segment */ void segmentZero(uInt8 slice); /** Install the specified slice for segment one. @param slice The slice to map into the segment */ void segmentOne(uInt8 slice); /** Install the specified slice for segment two. @param slice The slice to map into the segment */ void segmentTwo(uInt8 slice); /** Install the specified slice for segment three. Note that this method also takes care of mapping extra 3 bytes. @param slice The slice to map into the segment @param map3bytes Whether to map in an extra 3 bytes */ void segmentThree(uInt8 slice, bool map3bytes); private: // The 8K ROM image of the cartridge uInt8 myImage[8195]; // Indicates the actual size of the ROM image (either 8K or 8K + 3) uInt32 mySize; // The 64 bytes RAM of the cartridge uInt8 myRAM[64]; // The 1K ROM mirror of segment 3 (sometimes contains extra 3 bytes) uInt8 mySegment3[1024]; // Indicates the offset for each of the four segments uInt16 myOffset[4]; // Indicates the cycle at which a bankswitch was initiated uInt64 myCyclesAtBankswitchInit; // Indicates the bank we wish to switch to in the future uInt16 myPendingBank; // Indicates which bank is currently active uInt16 myCurrentBank; // The arrangement of banks to use on each hotspot read struct BankOrg { uInt8 zero, one, two, three; bool map3bytes; }; static BankOrg ourBankOrg[16]; private: // Following constructors and assignment operators not supported CartridgeWD() = delete; CartridgeWD(const CartridgeWD&) = delete; CartridgeWD(CartridgeWD&&) = delete; CartridgeWD& operator=(const CartridgeWD&) = delete; CartridgeWD& operator=(CartridgeWD&&) = delete; }; #endif stella-5.1.1/src/emucore/CartX07.cxx000066400000000000000000000122371324334165500171570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "M6532.hxx" #include "TIA.hxx" #include "CartX07.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CartridgeX07::CartridgeX07(const BytePtr& image, uInt32 size, const Settings& settings) : Cartridge(settings), myCurrentBank(0) { // Copy the ROM image into my buffer memcpy(myImage, image.get(), std::min(65536u, size)); createCodeAccessBase(65536); // Remember startup bank myStartBank = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeX07::reset() { // Upon reset we switch to the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CartridgeX07::install(System& system) { mySystem = &system; // Set the page accessing methods for the hot spots // The hotspots use almost all addresses below 0x1000, so we simply grab them // all and forward the TIA/RIOT calls from the peek and poke methods. System::PageAccess access(this, System::PA_READWRITE); for(uInt16 addr = 0x00; addr < 0x1000; addr += System::PAGE_SIZE) mySystem->setPageAccess(addr, access); // Install pages for the startup bank bank(myStartBank); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 CartridgeX07::peek(uInt16 address) { uInt8 value = 0; // Check for RAM or TIA mirroring uInt16 lowAddress = address & 0x3ff; if(lowAddress & 0x80) value = mySystem->m6532().peek(address); else if(!(lowAddress & 0x200)) value = mySystem->tia().peek(address); // Switch banks if necessary if((address & 0x180f) == 0x080d) bank((address & 0xf0) >> 4); else if((address & 0x1880) == 0) { if((myCurrentBank & 0xe) == 0xe) bank(((address & 0x40) >> 6) | (myCurrentBank & 0xe)); } return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeX07::poke(uInt16 address, uInt8 value) { // Check for RAM or TIA mirroring uInt16 lowAddress = address & 0x3ff; if(lowAddress & 0x80) mySystem->m6532().poke(address, value); else if(!(lowAddress & 0x200)) mySystem->tia().poke(address, value); // Switch banks if necessary if((address & 0x180f) == 0x080d) bank((address & 0xf0) >> 4); else if((address & 0x1880) == 0) { if((myCurrentBank & 0xe) == 0xe) bank(((address & 0x40) >> 6) | (myCurrentBank & 0xe)); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeX07::bank(uInt16 bank) { if(bankLocked()) return false; // Remember what bank we're in myCurrentBank = (bank & 0x0f); uInt32 offset = myCurrentBank << 12; // Setup the page access methods for the current bank System::PageAccess access(this, System::PA_READ); // Map ROM image into the system for(uInt16 addr = 0x1000; addr < 0x2000; addr += System::PAGE_SIZE) { access.directPeekBase = &myImage[offset + (addr & 0x0FFF)]; access.codeAccessBase = &myCodeAccessBase[offset + (addr & 0x0FFF)]; mySystem->setPageAccess(addr, access); } return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeX07::getBank() const { return myCurrentBank; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 CartridgeX07::bankCount() const { return 16; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeX07::patch(uInt16 address, uInt8 value) { myImage[(myCurrentBank << 12) + (address & 0x0FFF)] = value; return myBankChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* CartridgeX07::getImage(uInt32& size) const { size = 65536; return myImage; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeX07::save(Serializer& out) const { try { out.putString(name()); out.putShort(myCurrentBank); } catch(...) { cerr << "ERROR: CartridgeX07::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CartridgeX07::load(Serializer& in) { try { if(in.getString() != name()) return false; myCurrentBank = in.getShort(); } catch(...) { cerr << "ERROR: CartridgeX07::load" << endl; return false; } // Remember what bank we were in bank(myCurrentBank); return true; } stella-5.1.1/src/emucore/CartX07.hxx000066400000000000000000000116701324334165500171640ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CARTRIDGEX07_HXX #define CARTRIDGEX07_HXX class System; #include "bspf.hxx" #include "Cart.hxx" #ifdef DEBUGGER_SUPPORT #include "CartX07Widget.hxx" #endif /** Bankswitching method as defined/created by John Payson (aka Supercat) and Fred Quimby (aka batari). This bankswitching method has 16 4K banks that can be accessed at addresses $1000 to $1FFF. The bankswitching hotspots are all below $1000. X07 uses two types of hotspots: 0 1xxx nnnn 1101 -- Switch to bank nnnn 0 0xxx 0nxx xxxx -- If in bank 111x, switch to bank 111n. In any other bank, do not switch. Note that the latter will hit on almost any TIA access. @author Eckhard Stolberg */ class CartridgeX07 : public Cartridge { friend class CartridgeX07Widget; public: /** Create a new cartridge using the specified image @param image Pointer to the ROM image @param size The size of the ROM image @param settings A reference to the various settings (read-only) */ CartridgeX07(const BytePtr& image, uInt32 size, const Settings& settings); virtual ~CartridgeX07() = default; public: /** Reset device to its power-on state */ void reset() override; /** Install cartridge in the specified system. Invoked by the system when the cartridge is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install pages for the specified bank in the system. @param bank The bank that should be installed in the system */ bool bank(uInt16 bank) override; /** Get the current bank. */ uInt16 getBank() const override; /** Query the number of banks supported by the cartridge. */ uInt16 bankCount() const override; /** Patch the cartridge ROM. @param address The ROM address to patch @param value The value to place into the address @return Success or failure of the patch operation */ bool patch(uInt16 address, uInt8 value) override; /** Access the internal ROM image for this cartridge. @param size Set to the size of the internal ROM image data @return A pointer to the internal ROM image data */ const uInt8* getImage(uInt32& size) const override; /** Save the current state of this cart to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "CartridgeX07"; } #ifdef DEBUGGER_SUPPORT /** Get debugger widget responsible for accessing the inner workings of the cart. */ CartDebugWidget* debugWidget(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h) override { return new CartridgeX07Widget(boss, lfont, nfont, x, y, w, h, *this); } #endif public: /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; private: // The 64K ROM image of the cartridge uInt8 myImage[65536]; // Indicates which bank is currently active uInt16 myCurrentBank; private: // Following constructors and assignment operators not supported CartridgeX07() = delete; CartridgeX07(const CartridgeX07&) = delete; CartridgeX07(CartridgeX07&&) = delete; CartridgeX07& operator=(const CartridgeX07&) = delete; CartridgeX07& operator=(CartridgeX07&&) = delete; }; #endif stella-5.1.1/src/emucore/CompuMate.cxx000066400000000000000000000226531324334165500176640ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Control.hxx" #include "StellaKeys.hxx" #include "CompuMate.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CompuMate::CompuMate(const Console& console, const Event& event, const System& system) : myConsole(console), myEvent(event), myColumn(0), myKeyTable(nullptr) { // These controller pointers will be retrieved by the Console, which will // also take ownership of them myLeftController = make_unique(*this, Controller::Left, event, system); myRightController = make_unique(*this, Controller::Right, event, system); myLeftController->updateAnalogPin(Controller::Nine, Controller::maximumResistance); myLeftController->updateAnalogPin(Controller::Five, Controller::minimumResistance); myRightController->updateAnalogPin(Controller::Nine, Controller::minimumResistance); myRightController->updateAnalogPin(Controller::Five, Controller::maximumResistance); enableKeyHandling(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CompuMate::enableKeyHandling(bool enable) { if(enable) myKeyTable = myEvent.getKeys(); else { for(uInt32 i = 0; i < KBDK_LAST; ++i) myInternalKeyTable[i] = false; myKeyTable = myInternalKeyTable; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CompuMate::update() { // Handle SWCHA changes - the following comes almost directly from z26 Controller& lp = myConsole.leftController(); Controller& rp = myConsole.rightController(); lp.myAnalogPinValue[Controller::Nine] = Controller::maximumResistance; lp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = true; rp.myAnalogPinValue[Controller::Nine] = Controller::minimumResistance; rp.myAnalogPinValue[Controller::Five] = Controller::maximumResistance; rp.myDigitalPinState[Controller::Six] = true; if (myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT]) rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; if (myKeyTable[KBDK_LCTRL] || myKeyTable[KBDK_RCTRL]) lp.myAnalogPinValue[Controller::Nine] = Controller::minimumResistance; rp.myDigitalPinState[Controller::Three] = true; rp.myDigitalPinState[Controller::Four] = true; switch(myColumn) // This is updated inside CartCM class { case 0: if (myKeyTable[KBDK_7]) lp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_U]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_J]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_M]) rp.myDigitalPinState[Controller::Four] = false; break; case 1: if (myKeyTable[KBDK_6]) lp.myDigitalPinState[Controller::Six] = false; // Emulate the '?' character (Shift-6) with the actual question key if (myKeyTable[KBDK_SLASH] && (myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT])) { rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = false; } if (myKeyTable[KBDK_Y]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_H]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_N]) rp.myDigitalPinState[Controller::Four] = false; break; case 2: if (myKeyTable[KBDK_8]) lp.myDigitalPinState[Controller::Six] = false; // Emulate the '[' character (Shift-8) with the actual key if (myKeyTable[KBDK_LEFTBRACKET] && !(myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT])) { rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = false; } if (myKeyTable[KBDK_I]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_K]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_COMMA]) rp.myDigitalPinState[Controller::Four] = false; break; case 3: if (myKeyTable[KBDK_2]) lp.myDigitalPinState[Controller::Six] = false; // Emulate the '-' character (Shift-2) with the actual minus key if (myKeyTable[KBDK_MINUS] && !(myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT])) { rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = false; } if (myKeyTable[KBDK_W]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_S]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_X]) rp.myDigitalPinState[Controller::Four] = false; break; case 4: if (myKeyTable[KBDK_3]) lp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_E]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_D]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_C]) rp.myDigitalPinState[Controller::Four] = false; break; case 5: if (myKeyTable[KBDK_0]) lp.myDigitalPinState[Controller::Six] = false; // Emulate the quote character (Shift-0) with the actual quote key if (myKeyTable[KBDK_APOSTROPHE] && (myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT])) { rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = false; } if (myKeyTable[KBDK_P]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_RETURN] || myKeyTable[KBDK_KP_ENTER]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_SPACE]) rp.myDigitalPinState[Controller::Four] = false; // Emulate Ctrl-space (aka backspace) with the actual Backspace key if (myKeyTable[KBDK_BACKSPACE]) { lp.myAnalogPinValue[Controller::Nine] = Controller::minimumResistance; rp.myDigitalPinState[Controller::Four] = false; } break; case 6: if (myKeyTable[KBDK_9]) lp.myDigitalPinState[Controller::Six] = false; // Emulate the ']' character (Shift-9) with the actual key if (myKeyTable[KBDK_RIGHTBRACKET] && !(myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT])) { rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = false; } if (myKeyTable[KBDK_O]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_L]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_PERIOD]) rp.myDigitalPinState[Controller::Four] = false; break; case 7: if (myKeyTable[KBDK_5]) lp.myDigitalPinState[Controller::Six] = false; // Emulate the '=' character (Shift-5) with the actual equals key if (myKeyTable[KBDK_EQUALS] && !(myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT])) { rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = false; } if (myKeyTable[KBDK_T]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_G]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_B]) rp.myDigitalPinState[Controller::Four] = false; break; case 8: if (myKeyTable[KBDK_1]) lp.myDigitalPinState[Controller::Six] = false; // Emulate the '+' character (Shift-1) with the actual plus key (Shift-=) if (myKeyTable[KBDK_EQUALS] && (myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT])) { rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = false; } if (myKeyTable[KBDK_Q]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_A]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_Z]) rp.myDigitalPinState[Controller::Four] = false; break; case 9: if (myKeyTable[KBDK_4]) lp.myDigitalPinState[Controller::Six] = false; // Emulate the '/' character (Shift-4) with the actual slash key if (myKeyTable[KBDK_SLASH] && !(myKeyTable[KBDK_LSHIFT] || myKeyTable[KBDK_RSHIFT])) { rp.myAnalogPinValue[Controller::Five] = Controller::minimumResistance; lp.myDigitalPinState[Controller::Six] = false; } if (myKeyTable[KBDK_R]) rp.myDigitalPinState[Controller::Three] = false; if (myKeyTable[KBDK_F]) rp.myDigitalPinState[Controller::Six] = false; if (myKeyTable[KBDK_V]) rp.myDigitalPinState[Controller::Four] = false; break; default: break; } if (lp.myOnAnalogPinUpdateCallback) { lp.myOnAnalogPinUpdateCallback(Controller::Five); lp.myOnAnalogPinUpdateCallback(Controller::Nine); } if (rp.myOnAnalogPinUpdateCallback) { rp.myOnAnalogPinUpdateCallback(Controller::Five); rp.myOnAnalogPinUpdateCallback(Controller::Nine); } } stella-5.1.1/src/emucore/CompuMate.hxx000066400000000000000000000131661324334165500176700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef COMPUMATE_HXX #define COMPUMATE_HXX #include "bspf.hxx" #include "CartCM.hxx" #include "Control.hxx" #include "Event.hxx" #include "Console.hxx" /** Handler for SpectraVideo CompuMate bankswitched games. The specifics of the CompuMate format can be found in both the Cart side (CartCM) and the Controller side (CMControl). The CompuMate device is unique for the 2600 in that it requires close co-operation between the cartridge and the left and right controllers. This class acts as a 'parent' for cartridge and both the left and right CMControl's, taking care of their creation and communication between them. It also allows to enable/disable the users actual keyboard when required. @author Stephen Anthony */ class CompuMate { public: /** Create a new CompuMate handler for both left and right ports. Note that this class creates CMControl controllers for both ports, but does not take responsibility for their deletion. @param console The console that owns the controller @param event The event object to use for events @param system The system using this controller */ CompuMate(const Console& console, const Event& event, const System& system); virtual ~CompuMate() = default; // Controllers are deleted outside this class /** Return the left and right CompuMate controllers */ unique_ptr& leftController() { return myLeftController; } unique_ptr& rightController() { return myRightController; } /** In normal key-handling mode, the update handler receives key events from the keyboard. This is meant to be used during emulation. Otherwise, the update handler ignores keys from the keyboard and uses its own internal buffer, which essentially can only be set directly within the class itself (by the debugger). This is necessary since Stella is otherwise event-based, whereas reading from the keyboard (in the current code) bypasses the event system. This leads to issues where typing commands in the debugger would then be processed by the update handler as if they were entered on the CompuMate keyboard. */ void enableKeyHandling(bool enable); /** Needed for communication with CartCM class */ uInt8& column() { return myColumn; } private: /** Called by the controller(s) when all pins have been written This method keeps track of consecutive calls, and only updates once */ void update(); // The actual CompuMate controller // More information about these scheme can be found in CartCM.hxx class CMControl : public Controller { public: /** Create a new CMControl controller plugged into the specified jack @param handler Class which coordinates between left & right controllers @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ CMControl(class CompuMate& handler, Controller::Jack jack, const Event& event, const System& system) : Controller(jack, event, system, Controller::CompuMate), myHandler(handler) { } virtual ~CMControl() = default; public: /** Called after *all* digital pins have been written on Port A. Only update on the left controller; the right controller will happen at the same cycle and is redundant. */ void controlWrite(uInt8) override { if(myJack == Controller::Left) myHandler.update(); } /** Update the entire digital and analog pin state according to the events currently set. */ void update() override { } private: class CompuMate& myHandler; // Following constructors and assignment operators not supported CMControl() = delete; CMControl(const CMControl&) = delete; CMControl(CMControl&&) = delete; CMControl& operator=(const CMControl&) = delete; CMControl& operator=(CMControl&&) = delete; }; private: // Console and Event objects const Console& myConsole; const Event& myEvent; // Left and right controllers unique_ptr myLeftController, myRightController; // Column currently active uInt8 myColumn; // The keyboard state array (tells us the current state of the keyboard) const bool* myKeyTable; // Array of keyboard key states when in the debugger (the normal keyboard // keys are ignored in such a case) bool myInternalKeyTable[KBDK_LAST]; private: // Following constructors and assignment operators not supported CompuMate() = delete; CompuMate(const CompuMate&) = delete; CompuMate(CompuMate&&) = delete; CompuMate& operator=(const CompuMate&) = delete; CompuMate& operator=(CompuMate&&) = delete; }; #endif stella-5.1.1/src/emucore/Console.cxx000066400000000000000000001256671324334165500174050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #include "AtariVox.hxx" #include "Booster.hxx" #include "Cart.hxx" #include "Control.hxx" #include "Cart.hxx" #include "Driving.hxx" #include "Event.hxx" #include "EventHandler.hxx" #include "Joystick.hxx" #include "Keyboard.hxx" #include "KidVid.hxx" #include "Genesis.hxx" #include "MindLink.hxx" #include "CompuMate.hxx" #include "M6502.hxx" #include "M6532.hxx" #include "TIA.hxx" #include "Paddles.hxx" #include "Props.hxx" #include "PropsSet.hxx" #include "SaveKey.hxx" #include "Settings.hxx" #include "Sound.hxx" #include "Switches.hxx" #include "System.hxx" #include "AmigaMouse.hxx" #include "AtariMouse.hxx" #include "TrakBall.hxx" #include "FrameBuffer.hxx" #include "TIASurface.hxx" #include "OSystem.hxx" #include "Menu.hxx" #include "CommandMenu.hxx" #include "Serializable.hxx" #include "Version.hxx" #include "TIAConstants.hxx" #include "FrameLayout.hxx" #include "frame-manager/FrameManager.hxx" #include "frame-manager/FrameLayoutDetector.hxx" #include "frame-manager/YStartDetector.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" #endif #include "Console.hxx" namespace { constexpr uInt8 YSTART_EXTRA = 2; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console::Console(OSystem& osystem, unique_ptr& cart, const Properties& props) : myOSystem(osystem), myEvent(osystem.eventHandler().event()), myProperties(props), myCart(std::move(cart)), myDisplayFormat(""), // Unknown TV format @ start myFramerate(0.0), // Unknown framerate @ start myCurrentFormat(0), // Unknown format @ start, myAutodetectedYstart(0), myUserPaletteDefined(false), myConsoleTiming(ConsoleTiming::ntsc) { // Load user-defined palette for this ROM loadUserPalette(); // Create subsystems for the console my6502 = make_unique(myOSystem.settings()); myRiot = make_unique(*this, myOSystem.settings()); myTIA = make_unique(*this, myOSystem.sound(), myOSystem.settings()); myFrameManager = make_unique(); mySwitches = make_unique(myEvent, myProperties, myOSystem.settings()); myTIA->setFrameManager(myFrameManager.get()); // Construct the system and components mySystem = make_unique(osystem, *my6502, *myRiot, *myTIA, *myCart); // The real controllers for this console will be added later // For now, we just add dummy joystick controllers, since autodetection // runs the emulation for a while, and this may interfere with 'smart' // controllers such as the AVox and SaveKey myLeftControl = make_unique(Controller::Left, myEvent, *mySystem); myRightControl = make_unique(Controller::Right, myEvent, *mySystem); // We can only initialize after all the devices/components have been created mySystem->initialize(); // Auto-detect NTSC/PAL mode if it's requested string autodetected = ""; myDisplayFormat = myProperties.get(Display_Format); // Add the real controllers for this system // This must be done before the debugger is initialized const string& md5 = myProperties.get(Cartridge_MD5); setControllers(md5); // Mute audio and clear framebuffer while autodetection runs myOSystem.sound().mute(1); myOSystem.frameBuffer().clear(); if(myDisplayFormat == "AUTO" || myOSystem.settings().getBool("rominfo")) { autodetectFrameLayout(); if(myProperties.get(Display_Format) == "AUTO") { autodetected = "*"; myCurrentFormat = 0; } } if (atoi(myProperties.get(Display_YStart).c_str()) == 0) { autodetectYStart(); } myConsoleInfo.DisplayFormat = myDisplayFormat + autodetected; // Set up the correct properties used when toggling format // Note that this can be overridden if a format is forced // For example, if a PAL ROM is forced to be NTSC, it will use NTSC-like // properties (60Hz, 262 scanlines, etc), but likely result in flicker // The TIA will self-adjust the framerate if necessary setTIAProperties(); if(myDisplayFormat == "NTSC") { myCurrentFormat = 1; myConsoleTiming = ConsoleTiming::ntsc; } else if(myDisplayFormat == "PAL") { myCurrentFormat = 2; myConsoleTiming = ConsoleTiming::pal; } else if(myDisplayFormat == "SECAM") { myCurrentFormat = 3; myConsoleTiming = ConsoleTiming::secam; } else if(myDisplayFormat == "NTSC50") { myCurrentFormat = 4; myConsoleTiming = ConsoleTiming::ntsc; } else if(myDisplayFormat == "PAL60") { myCurrentFormat = 5; myConsoleTiming = ConsoleTiming::pal; } else if(myDisplayFormat == "SECAM60") { myCurrentFormat = 6; myConsoleTiming = ConsoleTiming::secam; } bool joyallow4 = myOSystem.settings().getBool("joyallow4"); myOSystem.eventHandler().allowAllDirections(joyallow4); // Reset the system to its power-on state mySystem->reset(); // Finally, add remaining info about the console myConsoleInfo.CartName = myProperties.get(Cartridge_Name); myConsoleInfo.CartMD5 = myProperties.get(Cartridge_MD5); bool swappedPorts = properties().get(Console_SwapPorts) == "YES"; myConsoleInfo.Control0 = myLeftControl->about(swappedPorts); myConsoleInfo.Control1 = myRightControl->about(swappedPorts); myConsoleInfo.BankSwitch = myCart->about(); myCart->setRomName(myConsoleInfo.CartName); // Let the other devices know about the new console mySystem->consoleChanged(myConsoleTiming); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Console::~Console() { // Some smart controllers need to be informed that the console is going away myLeftControl->close(); myRightControl->close(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::autodetectFrameLayout() { // Run the TIA, looking for PAL scanline patterns // We turn off the SuperCharger progress bars, otherwise the SC BIOS // will take over 250 frames! // The 'fastscbios' option must be changed before the system is reset bool fastscbios = myOSystem.settings().getBool("fastscbios"); myOSystem.settings().setValue("fastscbios", true); FrameLayoutDetector frameLayoutDetector; myTIA->setFrameManager(&frameLayoutDetector); mySystem->reset(true); for(int i = 0; i < 60; ++i) myTIA->update(); myTIA->setFrameManager(myFrameManager.get()); myDisplayFormat = frameLayoutDetector.detectedLayout() == FrameLayout::pal ? "PAL" : "NTSC"; // Don't forget to reset the SC progress bars again myOSystem.settings().setValue("fastscbios", fastscbios); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::autodetectYStart() { // We turn off the SuperCharger progress bars, otherwise the SC BIOS // will take over 250 frames! // The 'fastscbios' option must be changed before the system is reset bool fastscbios = myOSystem.settings().getBool("fastscbios"); myOSystem.settings().setValue("fastscbios", true); YStartDetector ystartDetector; ystartDetector.setLayout(myDisplayFormat == "PAL" ? FrameLayout::pal : FrameLayout::ntsc); myTIA->setFrameManager(&ystartDetector); mySystem->reset(true); for (int i = 0; i < 80; i++) myTIA->update(); myTIA->setFrameManager(myFrameManager.get()); myAutodetectedYstart = ystartDetector.detectedYStart() - YSTART_EXTRA; // Don't forget to reset the SC progress bars again myOSystem.settings().setValue("fastscbios", fastscbios); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Console::save(Serializer& out) const { try { // First save state for the system if(!mySystem->save(out)) return false; // Now save the console controllers and switches if(!(myLeftControl->save(out) && myRightControl->save(out) && mySwitches->save(out))) return false; } catch(...) { cerr << "ERROR: Console::save" << endl; return false; } return true; // success } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Console::load(Serializer& in) { try { // First load state for the system if(!mySystem->load(in)) return false; // Then load the console controllers and switches if(!(myLeftControl->load(in) && myRightControl->load(in) && mySwitches->load(in))) return false; } catch(...) { cerr << "ERROR: Console::load" << endl; return false; } return true; // success } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleFormat(int direction) { string saveformat, message; if(direction == 1) myCurrentFormat = (myCurrentFormat + 1) % 7; else if(direction == -1) myCurrentFormat = myCurrentFormat > 0 ? (myCurrentFormat - 1) : 6; switch(myCurrentFormat) { case 0: // auto-detect myTIA->update(); myDisplayFormat = myTIA->frameLayout() == FrameLayout::pal ? "PAL" : "NTSC"; message = "Auto-detect mode: " + myDisplayFormat; saveformat = "AUTO"; myConsoleTiming = myTIA->frameLayout() == FrameLayout::pal ? ConsoleTiming::pal : ConsoleTiming::ntsc; break; case 1: saveformat = myDisplayFormat = "NTSC"; myConsoleTiming = ConsoleTiming::ntsc; message = "NTSC mode"; break; case 2: saveformat = myDisplayFormat = "PAL"; myConsoleTiming = ConsoleTiming::pal; message = "PAL mode"; break; case 3: saveformat = myDisplayFormat = "SECAM"; myConsoleTiming = ConsoleTiming::secam; message = "SECAM mode"; break; case 4: saveformat = myDisplayFormat = "NTSC50"; myConsoleTiming = ConsoleTiming::ntsc; message = "NTSC50 mode"; break; case 5: saveformat = myDisplayFormat = "PAL60"; myConsoleTiming = ConsoleTiming::pal; message = "PAL60 mode"; break; case 6: saveformat = myDisplayFormat = "SECAM60"; myConsoleTiming = ConsoleTiming::secam; message = "SECAM60 mode"; break; } myProperties.set(Display_Format, saveformat); setPalette(myOSystem.settings().getString("palette")); setTIAProperties(); myTIA->frameReset(); initializeVideo(); // takes care of refreshing the screen myOSystem.frameBuffer().showMessage(message); // Let the other devices know about the console change mySystem->consoleChanged(myConsoleTiming); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleColorLoss() { bool colorloss = !myTIA->colorLossEnabled(); if(myTIA->enableColorLoss(colorloss)) { myOSystem.settings().setValue( myOSystem.settings().getBool("dev.settings") ? "dev.colorloss" : "plr.colorloss", colorloss); string message = string("PAL color-loss ") + (colorloss ? "enabled" : "disabled"); myOSystem.frameBuffer().showMessage(message); } else myOSystem.frameBuffer().showMessage( "PAL color-loss not available in non PAL modes"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::enableColorLoss(bool state) { myTIA->enableColorLoss(state); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::togglePalette() { string palette, message; palette = myOSystem.settings().getString("palette"); if(palette == "standard") // switch to z26 { palette = "z26"; message = "Z26 palette"; } else if(palette == "z26") // switch to user or standard { // If we have a user-defined palette, it will come next in // the sequence; otherwise loop back to the standard one if(myUserPaletteDefined) { palette = "user"; message = "User-defined palette"; } else { palette = "standard"; message = "Standard Stella palette"; } } else if(palette == "user") // switch to standard { palette = "standard"; message = "Standard Stella palette"; } else // switch to standard mode if we get this far { palette = "standard"; message = "Standard Stella palette"; } myOSystem.settings().setValue("palette", palette); myOSystem.frameBuffer().showMessage(message); setPalette(palette); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setPalette(const string& type) { // Look at all the palettes, since we don't know which one is // currently active static uInt32* palettes[3][3] = { { &ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0] }, { &ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0] }, { &ourUserNTSCPalette[0], &ourUserPALPalette[0], &ourUserSECAMPalette[0] } }; // See which format we should be using int paletteNum = 0; if(type == "standard") paletteNum = 0; else if(type == "z26") paletteNum = 1; else if(type == "user" && myUserPaletteDefined) paletteNum = 2; // Now consider the current display format const uInt32* palette = (myDisplayFormat.compare(0, 3, "PAL") == 0) ? palettes[paletteNum][1] : (myDisplayFormat.compare(0, 5, "SECAM") == 0) ? palettes[paletteNum][2] : palettes[paletteNum][0]; myOSystem.frameBuffer().setPalette(palette); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::togglePhosphor() { if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled()) { myProperties.set(Display_Phosphor, "No"); myOSystem.frameBuffer().tiaSurface().enablePhosphor(false); myOSystem.frameBuffer().showMessage("Phosphor effect disabled"); } else { myProperties.set(Display_Phosphor, "Yes"); myOSystem.frameBuffer().tiaSurface().enablePhosphor(true); myOSystem.frameBuffer().showMessage("Phosphor effect enabled"); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::changePhosphor(int direction) { int blend = atoi(myProperties.get(Display_PPBlend).c_str()); if(myOSystem.frameBuffer().tiaSurface().phosphorEnabled()) { if(direction == +1) // increase blend { if(blend >= 100) { myOSystem.frameBuffer().showMessage("Phosphor blend at maximum"); return; } else blend = std::min(blend+2, 100); } else if(direction == -1) // decrease blend { if(blend <= 2) { myOSystem.frameBuffer().showMessage("Phosphor blend at minimum"); return; } else blend = std::max(blend-2, 0); } else return; ostringstream val; val << blend; myProperties.set(Display_PPBlend, val.str()); myOSystem.frameBuffer().showMessage("Phosphor blend " + val.str()); myOSystem.frameBuffer().tiaSurface().enablePhosphor(true, blend); } else myOSystem.frameBuffer().showMessage("Phosphor effect disabled"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setProperties(const Properties& props) { myProperties = props; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus Console::initializeVideo(bool full) { FBInitStatus fbstatus = FBInitStatus::Success; if(full) { bool devSettings = myOSystem.settings().getBool("dev.settings"); const string& title = string("Stella ") + STELLA_VERSION + ": \"" + myProperties.get(Cartridge_Name) + "\""; fbstatus = myOSystem.frameBuffer().createDisplay(title, myTIA->width() << 1, myTIA->height()); if(fbstatus != FBInitStatus::Success) return fbstatus; myOSystem.frameBuffer().showFrameStats( myOSystem.settings().getBool(devSettings ? "dev.stats" : "plr.stats")); generateColorLossPalette(); } setPalette(myOSystem.settings().getString("palette")); // Set the correct framerate based on the format of the ROM // This can be overridden by changing the framerate in the // VideoDialog box or on the commandline, but it can't be saved // (ie, framerate is now determined based on number of scanlines). int framerate = myOSystem.settings().getInt("framerate"); if(framerate > 0) myFramerate = float(framerate); myOSystem.setFramerate(myFramerate); // Make sure auto-frame calculation is only enabled when necessary myTIA->enableAutoFrame(framerate <= 0); return fbstatus; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::initializeAudio() { // Initialize the sound interface. // The # of channels can be overridden in the AudioDialog box or on // the commandline, but it can't be saved. int framerate = myOSystem.settings().getInt("framerate"); if(framerate > 0) myFramerate = float(framerate); const string& sound = myProperties.get(Cartridge_Sound); myOSystem.sound().close(); myOSystem.sound().setChannels(sound == "STEREO" ? 2 : 1); myOSystem.sound().setFrameRate(myFramerate); myOSystem.sound().open(); // Make sure auto-frame calculation is only enabled when necessary myTIA->enableAutoFrame(framerate <= 0); } /* Original frying research and code by Fred Quimby. I've tried the following variations on this code: - Both OR and Exclusive OR instead of AND. This generally crashes the game without ever giving us realistic "fried" effects. - Loop only over the RIOT RAM. This still gave us frying-like effects, but it seemed harder to duplicate most effects. I have no idea why, but munging the TIA regs seems to have some effect (I'd think it wouldn't). Fred says he also tried mangling the PC and registers, but usually it'd just crash the game (e.g. black screen, no way out of it). It's definitely easier to get some effects (e.g. 255 lives in Battlezone) with this code than it is on a real console. My guess is that most "good" frying effects come from a RIOT location getting cleared to 0. Fred's code is more likely to accomplish this than frying a real console is... Until someone comes up with a more accurate way to emulate frying, I'm leaving this as Fred posted it. -- B. */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::fry() const { for(int i = 0; i < 0x100; i += mySystem->randGenerator().next() % 4) mySystem->poke(i, mySystem->peek(i) & mySystem->randGenerator().next()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::changeYStart(int direction) { uInt32 ystart = myTIA->ystart(); if(direction == +1) // increase YStart { if(ystart >= TIAConstants::maxYStart) { myOSystem.frameBuffer().showMessage("YStart at maximum"); return; } ystart++; } else if(direction == -1) // decrease YStart { if (ystart == TIAConstants::minYStart && myAutodetectedYstart == 0) { myOSystem.frameBuffer().showMessage("Autodetected YStart not available"); return; } if(ystart == TIAConstants::minYStart-1 && myAutodetectedYstart > 0) { myOSystem.frameBuffer().showMessage("YStart at minimum"); return; } ystart--; } else return; ostringstream val; val << ystart; if(ystart == TIAConstants::minYStart-1) myOSystem.frameBuffer().showMessage("YStart autodetected"); else { if(myAutodetectedYstart > 0 && myAutodetectedYstart == ystart) { // We've reached the auto-detect value, so reset myOSystem.frameBuffer().showMessage("YStart " + val.str() + " (Auto)"); val.str(""); val << TIAConstants::minYStart-1; } else myOSystem.frameBuffer().showMessage("YStart " + val.str()); } myProperties.set(Display_YStart, val.str()); myTIA->setYStart(ystart); myTIA->frameReset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::changeHeight(int direction) { uInt32 height = myTIA->height(); uInt32 dheight = myOSystem.frameBuffer().desktopSize().h; if(direction == +1) // increase Height { height++; if(height > TIAConstants::maxViewableHeight || height > dheight) { myOSystem.frameBuffer().showMessage("Height at maximum"); return; } } else if(direction == -1) // decrease Height { height--; if(height < TIAConstants::minViewableHeight) height = 0; } else return; myTIA->setHeight(height); myTIA->frameReset(); initializeVideo(); // takes care of refreshing the screen ostringstream val; val << height; myOSystem.frameBuffer().showMessage("Height " + val.str()); myProperties.set(Display_Height, val.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setTIAProperties() { uInt32 ystart = atoi(myProperties.get(Display_YStart).c_str()); if(ystart != 0) ystart = BSPF::clamp(ystart, TIAConstants::minYStart, TIAConstants::maxYStart); uInt32 height = atoi(myProperties.get(Display_Height).c_str()); if(height != 0) height = BSPF::clamp(height, TIAConstants::minViewableHeight, TIAConstants::maxViewableHeight); if(myDisplayFormat == "NTSC" || myDisplayFormat == "PAL60" || myDisplayFormat == "SECAM60") { // Assume we've got ~262 scanlines (NTSC-like format) myFramerate = 60.0; myConsoleInfo.InitialFrameRate = "60"; myTIA->setLayout(FrameLayout::ntsc); } else { // Assume we've got ~312 scanlines (PAL-like format) myFramerate = 50.0; myConsoleInfo.InitialFrameRate = "50"; // PAL ROMs normally need at least 250 lines if (height != 0) height = std::max(height, 250u); myTIA->setLayout(FrameLayout::pal); } myTIA->setYStart(ystart != 0 ? ystart : myAutodetectedYstart); myTIA->setHeight(height); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setControllers(const string& rommd5) { // Check for CompuMate scheme; it is special in that a handler creates both // controllers for us, and associates them with the bankswitching class if(myCart->detectedType() == "CM") { myCMHandler = make_shared(*this, myEvent, *mySystem); // A somewhat ugly bit of code that casts to CartridgeCM to // add the CompuMate, and then back again for the actual // Cartridge unique_ptr cartcm(static_cast(myCart.release())); cartcm->setCompuMate(myCMHandler); myCart = std::move(cartcm); myLeftControl = std::move(myCMHandler->leftController()); myRightControl = std::move(myCMHandler->rightController()); } else { // Setup the controllers based on properties const string& left = myProperties.get(Controller_Left); const string& right = myProperties.get(Controller_Right); unique_ptr leftC = getControllerPort(rommd5, left, Controller::Left), rightC = getControllerPort(rommd5, right, Controller::Right); // Swap the ports if necessary if(myProperties.get(Console_SwapPorts) == "NO") { myLeftControl = std::move(leftC); myRightControl = std::move(rightC); } else { myLeftControl = std::move(rightC); myRightControl = std::move(leftC); } } myTIA->bindToControllers(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unique_ptr Console::getControllerPort(const string& rommd5, const string& controllerName, Controller::Jack port) { unique_ptr controller = std::move(myLeftControl); if(controllerName == "JOYSTICK") { // Already created in c'tor // We save some time by not looking at all the other types if(!controller) controller = make_unique(port, myEvent, *mySystem); } else if(controllerName == "BOOSTERGRIP") { controller = make_unique(port, myEvent, *mySystem); } else if(controllerName == "DRIVING") { controller = make_unique(port, myEvent, *mySystem); } else if((controllerName == "KEYBOARD") || (controllerName == "KEYPAD")) { controller = make_unique(port, myEvent, *mySystem); } else if(BSPF::startsWithIgnoreCase(controllerName, "PADDLES")) { // Also check if we should swap the paddles plugged into a jack bool swapPaddles = myProperties.get(Controller_SwapPaddles) == "YES"; bool swapAxis = false, swapDir = false; if(controllerName == "PADDLES_IAXIS") swapAxis = true; else if(controllerName == "PADDLES_IDIR") swapDir = true; else if(controllerName == "PADDLES_IAXDR") swapAxis = swapDir = true; controller = make_unique(port, myEvent, *mySystem, swapPaddles, swapAxis, swapDir); } else if(controllerName == "AMIGAMOUSE") { controller = make_unique(port, myEvent, *mySystem); } else if(controllerName == "ATARIMOUSE") { controller = make_unique(port, myEvent, *mySystem); } else if(controllerName == "TRAKBALL") { controller = make_unique(port, myEvent, *mySystem); } else if(controllerName == "ATARIVOX") { const string& nvramfile = myOSystem.nvramDir() + "atarivox_eeprom.dat"; controller = make_unique(port, myEvent, *mySystem, myOSystem.serialPort(), myOSystem.settings().getString("avoxport"), nvramfile); } else if(controllerName == "SAVEKEY") { const string& nvramfile = myOSystem.nvramDir() + "savekey_eeprom.dat"; controller = make_unique(port, myEvent, *mySystem, nvramfile); } else if(controllerName == "GENESIS") { controller = make_unique(port, myEvent, *mySystem); } else if(controllerName == "KIDVID") { controller = make_unique(port, myEvent, *mySystem, rommd5); } else if(controllerName == "MINDLINK") { controller = make_unique(port, myEvent, *mySystem); } else // What else can we do? controller = make_unique(port, myEvent, *mySystem); return controller; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::loadUserPalette() { const string& palette = myOSystem.paletteFile(); ifstream in(palette, std::ios::binary); if(!in) return; // Make sure the contains enough data for the NTSC, PAL and SECAM palettes // This means 128 colours each for NTSC and PAL, at 3 bytes per pixel // and 8 colours for SECAM at 3 bytes per pixel in.seekg(0, std::ios::end); std::streampos length = in.tellg(); in.seekg(0, std::ios::beg); if(length < 128 * 3 * 2 + 8 * 3) { cerr << "ERROR: invalid palette file " << palette << endl; return; } // Now that we have valid data, create the user-defined palettes uInt8 pixbuf[3]; // Temporary buffer for one 24-bit pixel for(int i = 0; i < 128; i++) // NTSC palette { in.read(reinterpret_cast(pixbuf), 3); uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); ourUserNTSCPalette[(i<<1)] = pixel; } for(int i = 0; i < 128; i++) // PAL palette { in.read(reinterpret_cast(pixbuf), 3); uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); ourUserPALPalette[(i<<1)] = pixel; } uInt32 secam[16]; // All 8 24-bit pixels, plus 8 colorloss pixels for(int i = 0; i < 8; i++) // SECAM palette { in.read(reinterpret_cast(pixbuf), 3); uInt32 pixel = (int(pixbuf[0]) << 16) + (int(pixbuf[1]) << 8) + int(pixbuf[2]); secam[(i<<1)] = pixel; secam[(i<<1)+1] = 0; } uInt32* ptr = ourUserSECAMPalette; for(int i = 0; i < 16; ++i) { uInt32* s = secam; for(int j = 0; j < 16; ++j) *ptr++ = *s++; } myUserPaletteDefined = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::generateColorLossPalette() { // Look at all the palettes, since we don't know which one is // currently active uInt32* palette[9] = { &ourNTSCPalette[0], &ourPALPalette[0], &ourSECAMPalette[0], &ourNTSCPaletteZ26[0], &ourPALPaletteZ26[0], &ourSECAMPaletteZ26[0], nullptr, nullptr, nullptr }; if(myUserPaletteDefined) { palette[6] = &ourUserNTSCPalette[0]; palette[7] = &ourUserPALPalette[0]; palette[8] = &ourUserSECAMPalette[0]; } for(int i = 0; i < 9; ++i) { if(palette[i] == nullptr) continue; // Fill the odd numbered palette entries with gray values (calculated // using the standard RGB -> grayscale conversion formula) for(int j = 0; j < 128; ++j) { uInt32 pixel = palette[i][(j<<1)]; uInt8 r = (pixel >> 16) & 0xff; uInt8 g = (pixel >> 8) & 0xff; uInt8 b = (pixel >> 0) & 0xff; uInt8 sum = uInt8((r * 0.2989) + (g * 0.5870) + (b * 0.1140)); palette[i][(j<<1)+1] = (sum << 16) + (sum << 8) + sum; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::setFramerate(float framerate) { myFramerate = framerate; myOSystem.setFramerate(framerate); myOSystem.sound().setFrameRate(framerate); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleTIABit(TIABit bit, const string& bitname, bool show) const { bool result = myTIA->toggleBit(bit); string message = bitname + (result ? " enabled" : " disabled"); myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleBits() const { bool enabled = myTIA->toggleBits(); string message = string("TIA bits") + (enabled ? " enabled" : " disabled"); myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleTIACollision(TIABit bit, const string& bitname, bool show) const { bool result = myTIA->toggleCollision(bit); string message = bitname + (result ? " collision enabled" : " collision disabled"); myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleCollisions() const { bool enabled = myTIA->toggleCollisions(); string message = string("TIA collisions") + (enabled ? " enabled" : " disabled"); myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleFixedColors() const { if(myTIA->toggleFixedColors()) myOSystem.frameBuffer().showMessage("Fixed debug colors enabled"); else myOSystem.frameBuffer().showMessage("Fixed debug colors disabled"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::toggleJitter() const { bool enabled = myTIA->toggleJitter(); string message = string("TV scanline jitter") + (enabled ? " enabled" : " disabled"); myOSystem.frameBuffer().showMessage(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::attachDebugger(Debugger& dbg) { #ifdef DEBUGGER_SUPPORT // myOSystem.createDebugger(*this); mySystem->m6502().attach(dbg); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Console::stateChanged(EventHandlerState state) { // For now, only the CompuMate cares about state changes if(myCMHandler) myCMHandler->enableKeyHandling(state == EventHandlerState::EMULATION); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourNTSCPalette[256] = { 0x000000, 0, 0x4a4a4a, 0, 0x6f6f6f, 0, 0x8e8e8e, 0, 0xaaaaaa, 0, 0xc0c0c0, 0, 0xd6d6d6, 0, 0xececec, 0, 0x484800, 0, 0x69690f, 0, 0x86861d, 0, 0xa2a22a, 0, 0xbbbb35, 0, 0xd2d240, 0, 0xe8e84a, 0, 0xfcfc54, 0, 0x7c2c00, 0, 0x904811, 0, 0xa26221, 0, 0xb47a30, 0, 0xc3903d, 0, 0xd2a44a, 0, 0xdfb755, 0, 0xecc860, 0, 0x901c00, 0, 0xa33915, 0, 0xb55328, 0, 0xc66c3a, 0, 0xd5824a, 0, 0xe39759, 0, 0xf0aa67, 0, 0xfcbc74, 0, 0x940000, 0, 0xa71a1a, 0, 0xb83232, 0, 0xc84848, 0, 0xd65c5c, 0, 0xe46f6f, 0, 0xf08080, 0, 0xfc9090, 0, 0x840064, 0, 0x97197a, 0, 0xa8308f, 0, 0xb846a2, 0, 0xc659b3, 0, 0xd46cc3, 0, 0xe07cd2, 0, 0xec8ce0, 0, 0x500084, 0, 0x68199a, 0, 0x7d30ad, 0, 0x9246c0, 0, 0xa459d0, 0, 0xb56ce0, 0, 0xc57cee, 0, 0xd48cfc, 0, 0x140090, 0, 0x331aa3, 0, 0x4e32b5, 0, 0x6848c6, 0, 0x7f5cd5, 0, 0x956fe3, 0, 0xa980f0, 0, 0xbc90fc, 0, 0x000094, 0, 0x181aa7, 0, 0x2d32b8, 0, 0x4248c8, 0, 0x545cd6, 0, 0x656fe4, 0, 0x7580f0, 0, 0x8490fc, 0, 0x001c88, 0, 0x183b9d, 0, 0x2d57b0, 0, 0x4272c2, 0, 0x548ad2, 0, 0x65a0e1, 0, 0x75b5ef, 0, 0x84c8fc, 0, 0x003064, 0, 0x185080, 0, 0x2d6d98, 0, 0x4288b0, 0, 0x54a0c5, 0, 0x65b7d9, 0, 0x75cceb, 0, 0x84e0fc, 0, 0x004030, 0, 0x18624e, 0, 0x2d8169, 0, 0x429e82, 0, 0x54b899, 0, 0x65d1ae, 0, 0x75e7c2, 0, 0x84fcd4, 0, 0x004400, 0, 0x1a661a, 0, 0x328432, 0, 0x48a048, 0, 0x5cba5c, 0, 0x6fd26f, 0, 0x80e880, 0, 0x90fc90, 0, 0x143c00, 0, 0x355f18, 0, 0x527e2d, 0, 0x6e9c42, 0, 0x87b754, 0, 0x9ed065, 0, 0xb4e775, 0, 0xc8fc84, 0, 0x303800, 0, 0x505916, 0, 0x6d762b, 0, 0x88923e, 0, 0xa0ab4f, 0, 0xb7c25f, 0, 0xccd86e, 0, 0xe0ec7c, 0, 0x482c00, 0, 0x694d14, 0, 0x866a26, 0, 0xa28638, 0, 0xbb9f47, 0, 0xd2b656, 0, 0xe8cc63, 0, 0xfce070, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourPALPalette[256] = { 0x000000, 0, 0x2b2b2b, 0, 0x525252, 0, 0x767676, 0, 0x979797, 0, 0xb6b6b6, 0, 0xd2d2d2, 0, 0xececec, 0, 0x000000, 0, 0x2b2b2b, 0, 0x525252, 0, 0x767676, 0, 0x979797, 0, 0xb6b6b6, 0, 0xd2d2d2, 0, 0xececec, 0, 0x805800, 0, 0x96711a, 0, 0xab8732, 0, 0xbe9c48, 0, 0xcfaf5c, 0, 0xdfc06f, 0, 0xeed180, 0, 0xfce090, 0, 0x445c00, 0, 0x5e791a, 0, 0x769332, 0, 0x8cac48, 0, 0xa0c25c, 0, 0xb3d76f, 0, 0xc4ea80, 0, 0xd4fc90, 0, 0x703400, 0, 0x89511a, 0, 0xa06b32, 0, 0xb68448, 0, 0xc99a5c, 0, 0xdcaf6f, 0, 0xecc280, 0, 0xfcd490, 0, 0x006414, 0, 0x1a8035, 0, 0x329852, 0, 0x48b06e, 0, 0x5cc587, 0, 0x6fd99e, 0, 0x80ebb4, 0, 0x90fcc8, 0, 0x700014, 0, 0x891a35, 0, 0xa03252, 0, 0xb6486e, 0, 0xc95c87, 0, 0xdc6f9e, 0, 0xec80b4, 0, 0xfc90c8, 0, 0x005c5c, 0, 0x1a7676, 0, 0x328e8e, 0, 0x48a4a4, 0, 0x5cb8b8, 0, 0x6fcbcb, 0, 0x80dcdc, 0, 0x90ecec, 0, 0x70005c, 0, 0x841a74, 0, 0x963289, 0, 0xa8489e, 0, 0xb75cb0, 0, 0xc66fc1, 0, 0xd380d1, 0, 0xe090e0, 0, 0x003c70, 0, 0x195a89, 0, 0x2f75a0, 0, 0x448eb6, 0, 0x57a5c9, 0, 0x68badc, 0, 0x79ceec, 0, 0x88e0fc, 0, 0x580070, 0, 0x6e1a89, 0, 0x8332a0, 0, 0x9648b6, 0, 0xa75cc9, 0, 0xb76fdc, 0, 0xc680ec, 0, 0xd490fc, 0, 0x002070, 0, 0x193f89, 0, 0x2f5aa0, 0, 0x4474b6, 0, 0x578bc9, 0, 0x68a1dc, 0, 0x79b5ec, 0, 0x88c8fc, 0, 0x340080, 0, 0x4a1a96, 0, 0x5f32ab, 0, 0x7248be, 0, 0x835ccf, 0, 0x936fdf, 0, 0xa280ee, 0, 0xb090fc, 0, 0x000088, 0, 0x1a1a9d, 0, 0x3232b0, 0, 0x4848c2, 0, 0x5c5cd2, 0, 0x6f6fe1, 0, 0x8080ef, 0, 0x9090fc, 0, 0x000000, 0, 0x2b2b2b, 0, 0x525252, 0, 0x767676, 0, 0x979797, 0, 0xb6b6b6, 0, 0xd2d2d2, 0, 0xececec, 0, 0x000000, 0, 0x2b2b2b, 0, 0x525252, 0, 0x767676, 0, 0x979797, 0, 0xb6b6b6, 0, 0xd2d2d2, 0, 0xececec, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourSECAMPalette[256] = { 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff50ff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourNTSCPaletteZ26[256] = { 0x000000, 0, 0x505050, 0, 0x646464, 0, 0x787878, 0, 0x8c8c8c, 0, 0xa0a0a0, 0, 0xb4b4b4, 0, 0xc8c8c8, 0, 0x445400, 0, 0x586800, 0, 0x6c7c00, 0, 0x809000, 0, 0x94a414, 0, 0xa8b828, 0, 0xbccc3c, 0, 0xd0e050, 0, 0x673900, 0, 0x7b4d00, 0, 0x8f6100, 0, 0xa37513, 0, 0xb78927, 0, 0xcb9d3b, 0, 0xdfb14f, 0, 0xf3c563, 0, 0x7b2504, 0, 0x8f3918, 0, 0xa34d2c, 0, 0xb76140, 0, 0xcb7554, 0, 0xdf8968, 0, 0xf39d7c, 0, 0xffb190, 0, 0x7d122c, 0, 0x912640, 0, 0xa53a54, 0, 0xb94e68, 0, 0xcd627c, 0, 0xe17690, 0, 0xf58aa4, 0, 0xff9eb8, 0, 0x730871, 0, 0x871c85, 0, 0x9b3099, 0, 0xaf44ad, 0, 0xc358c1, 0, 0xd76cd5, 0, 0xeb80e9, 0, 0xff94fd, 0, 0x5d0b92, 0, 0x711fa6, 0, 0x8533ba, 0, 0x9947ce, 0, 0xad5be2, 0, 0xc16ff6, 0, 0xd583ff, 0, 0xe997ff, 0, 0x401599, 0, 0x5429ad, 0, 0x683dc1, 0, 0x7c51d5, 0, 0x9065e9, 0, 0xa479fd, 0, 0xb88dff, 0, 0xcca1ff, 0, 0x252593, 0, 0x3939a7, 0, 0x4d4dbb, 0, 0x6161cf, 0, 0x7575e3, 0, 0x8989f7, 0, 0x9d9dff, 0, 0xb1b1ff, 0, 0x0f3480, 0, 0x234894, 0, 0x375ca8, 0, 0x4b70bc, 0, 0x5f84d0, 0, 0x7398e4, 0, 0x87acf8, 0, 0x9bc0ff, 0, 0x04425a, 0, 0x18566e, 0, 0x2c6a82, 0, 0x407e96, 0, 0x5492aa, 0, 0x68a6be, 0, 0x7cbad2, 0, 0x90cee6, 0, 0x044f30, 0, 0x186344, 0, 0x2c7758, 0, 0x408b6c, 0, 0x549f80, 0, 0x68b394, 0, 0x7cc7a8, 0, 0x90dbbc, 0, 0x0f550a, 0, 0x23691e, 0, 0x377d32, 0, 0x4b9146, 0, 0x5fa55a, 0, 0x73b96e, 0, 0x87cd82, 0, 0x9be196, 0, 0x1f5100, 0, 0x336505, 0, 0x477919, 0, 0x5b8d2d, 0, 0x6fa141, 0, 0x83b555, 0, 0x97c969, 0, 0xabdd7d, 0, 0x344600, 0, 0x485a00, 0, 0x5c6e14, 0, 0x708228, 0, 0x84963c, 0, 0x98aa50, 0, 0xacbe64, 0, 0xc0d278, 0, 0x463e00, 0, 0x5a5205, 0, 0x6e6619, 0, 0x827a2d, 0, 0x968e41, 0, 0xaaa255, 0, 0xbeb669, 0, 0xd2ca7d, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourPALPaletteZ26[256] = { 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, 0x533a00, 0, 0x674e00, 0, 0x7b6203, 0, 0x8f7617, 0, 0xa38a2b, 0, 0xb79e3f, 0, 0xcbb253, 0, 0xdfc667, 0, 0x1b5800, 0, 0x2f6c00, 0, 0x438001, 0, 0x579415, 0, 0x6ba829, 0, 0x7fbc3d, 0, 0x93d051, 0, 0xa7e465, 0, 0x6a2900, 0, 0x7e3d12, 0, 0x925126, 0, 0xa6653a, 0, 0xba794e, 0, 0xce8d62, 0, 0xe2a176, 0, 0xf6b58a, 0, 0x075b00, 0, 0x1b6f11, 0, 0x2f8325, 0, 0x439739, 0, 0x57ab4d, 0, 0x6bbf61, 0, 0x7fd375, 0, 0x93e789, 0, 0x741b2f, 0, 0x882f43, 0, 0x9c4357, 0, 0xb0576b, 0, 0xc46b7f, 0, 0xd87f93, 0, 0xec93a7, 0, 0xffa7bb, 0, 0x00572e, 0, 0x106b42, 0, 0x247f56, 0, 0x38936a, 0, 0x4ca77e, 0, 0x60bb92, 0, 0x74cfa6, 0, 0x88e3ba, 0, 0x6d165f, 0, 0x812a73, 0, 0x953e87, 0, 0xa9529b, 0, 0xbd66af, 0, 0xd17ac3, 0, 0xe58ed7, 0, 0xf9a2eb, 0, 0x014c5e, 0, 0x156072, 0, 0x297486, 0, 0x3d889a, 0, 0x519cae, 0, 0x65b0c2, 0, 0x79c4d6, 0, 0x8dd8ea, 0, 0x5f1588, 0, 0x73299c, 0, 0x873db0, 0, 0x9b51c4, 0, 0xaf65d8, 0, 0xc379ec, 0, 0xd78dff, 0, 0xeba1ff, 0, 0x123b87, 0, 0x264f9b, 0, 0x3a63af, 0, 0x4e77c3, 0, 0x628bd7, 0, 0x769feb, 0, 0x8ab3ff, 0, 0x9ec7ff, 0, 0x451e9d, 0, 0x5932b1, 0, 0x6d46c5, 0, 0x815ad9, 0, 0x956eed, 0, 0xa982ff, 0, 0xbd96ff, 0, 0xd1aaff, 0, 0x2a2b9e, 0, 0x3e3fb2, 0, 0x5253c6, 0, 0x6667da, 0, 0x7a7bee, 0, 0x8e8fff, 0, 0xa2a3ff, 0, 0xb6b7ff, 0, 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0, 0x000000, 0, 0x4c4c4c, 0, 0x606060, 0, 0x747474, 0, 0x888888, 0, 0x9c9c9c, 0, 0xb0b0b0, 0, 0xc4c4c4, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourSECAMPaletteZ26[256] = { 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0, 0x000000, 0, 0x2121ff, 0, 0xf03c79, 0, 0xff3cff, 0, 0x7fff00, 0, 0x7fffff, 0, 0xffff3f, 0, 0xffffff, 0 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourUserNTSCPalette[256] = { 0 }; // filled from external file // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourUserPALPalette[256] = { 0 }; // filled from external file // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Console::ourUserSECAMPalette[256] = { 0 }; // filled from external file stella-5.1.1/src/emucore/Console.hxx000066400000000000000000000275361324334165500174060ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CONSOLE_HXX #define CONSOLE_HXX class Event; class Switches; class System; class TIA; class M6502; class M6532; class Cartridge; class CompuMate; class Debugger; #include "bspf.hxx" #include "Control.hxx" #include "Props.hxx" #include "TIAConstants.hxx" #include "FrameBuffer.hxx" #include "Serializable.hxx" #include "EventHandlerConstants.hxx" #include "NTSCFilter.hxx" #include "frame-manager/AbstractFrameManager.hxx" /** Contains detailed info about a console. */ struct ConsoleInfo { string BankSwitch; string CartName; string CartMD5; string Control0; string Control1; string DisplayFormat; string InitialFrameRate; }; /** Contains timing information about the specified console. */ enum class ConsoleTiming { ntsc, // console with CPU running at 1.193182 MHz, NTSC colours pal, // console with CPU running at 1.182298 MHz, PAL colours secam // console with CPU running at 1.187500 MHz, SECAM colours }; /** This class represents the entire game console. @author Bradford W. Mott */ class Console : public Serializable { public: /** Create a new console for emulating the specified game using the given game image and operating system. @param osystem The OSystem object to use @param cart The cartridge to use with this console @param props The properties for the cartridge */ Console(OSystem& osystem, unique_ptr& cart, const Properties& props); /** Destructor */ virtual ~Console(); public: /** Get the controller plugged into the specified jack @return The specified controller */ Controller& leftController() const { return *myLeftControl; } Controller& rightController() const { return *myRightControl; } /** Get the TIA for this console @return The TIA */ TIA& tia() const { return *myTIA; } /** Get the properties being used by the game @return The properties being used by the game */ const Properties& properties() const { return myProperties; } /** Get the console switches @return The console switches */ Switches& switches() const { return *mySwitches; } /** Get the 6502 based system used by the console to emulate the game @return The 6502 based system */ System& system() const { return *mySystem; } /** Get the cartridge used by the console which contains the ROM code @return The cartridge for this console */ Cartridge& cartridge() const { return *myCart; } /** Get the 6532 used by the console @return The 6532 for this console */ M6532& riot() const { return *myRiot; } /** Saves the current state of this console class to the given Serializer. @param out The serializer device to save to. @return The result of the save. True on success, false on failure. */ bool save(Serializer& out) const override; /** Loads the current state of this console class from the given Serializer. @param in The Serializer device to load from. @return The result of the load. True on success, false on failure. */ bool load(Serializer& in) override; /** Get a descriptor for this console class (used in error checking). @return The name of the object */ string name() const override { return "Console"; } /** Set the properties to those given @param props The properties to use for the current game */ void setProperties(const Properties& props); /** Query detailed information about this console. */ const ConsoleInfo& about() const { return myConsoleInfo; } /** Timing information for this console. */ ConsoleTiming timing() const { return myConsoleTiming; } /** Set up the console to use the debugger. */ void attachDebugger(Debugger& dbg); /** Informs the Console of a change in EventHandler state. */ void stateChanged(EventHandlerState state); public: /** Toggle between NTSC/PAL/SECAM (and variants) display format. @param direction +1 indicates increase, -1 indicates decrease. */ void toggleFormat(int direction = 1); /** Toggle between the available palettes. */ void togglePalette(); /** Sets the palette according to the given palette name. @param palette The palette to switch to. */ void setPalette(const string& palette); /** Toggles phosphor effect. */ void togglePhosphor(); /** Change the "Display.PPBlend" variable. @param direction +1 indicates increase, -1 indicates decrease. */ void changePhosphor(int direction); /** Toggles the PAL color-loss effect. */ void toggleColorLoss(); void enableColorLoss(bool state); /** Initialize the video subsystem wrt this class. This is required for changing window size, title, etc. @param full Whether we want a full initialization, or only reset certain attributes. @return The results from FrameBuffer::initialize() */ FBInitStatus initializeVideo(bool full = true); /** Initialize the audio subsystem wrt this class. This is required any time the sound settings change. */ void initializeAudio(); /** "Fry" the Atari (mangle memory/TIA contents) */ void fry() const; /** Change the "Display.YStart" variable. @param direction +1 indicates increase, -1 indicates decrease. */ void changeYStart(int direction); /** Change the "Display.Height" variable. @param direction +1 indicates increase, -1 indicates decrease. */ void changeHeight(int direction); /** Sets the framerate of the console, which in turn communicates this to all applicable subsystems. */ void setFramerate(float framerate); /** Returns the framerate based on a number of factors (whether 'framerate' is set, what display format is in use, etc) */ float getFramerate() const { return myFramerate; } /** Toggles the TIA bit specified in the method name. */ void toggleP0Bit() const { toggleTIABit(P0Bit, "P0"); } void toggleP1Bit() const { toggleTIABit(P1Bit, "P1"); } void toggleM0Bit() const { toggleTIABit(M0Bit, "M0"); } void toggleM1Bit() const { toggleTIABit(M1Bit, "M1"); } void toggleBLBit() const { toggleTIABit(BLBit, "BL"); } void togglePFBit() const { toggleTIABit(PFBit, "PF"); } void toggleBits() const; /** Toggles the TIA collisions specified in the method name. */ void toggleP0Collision() const { toggleTIACollision(P0Bit, "P0"); } void toggleP1Collision() const { toggleTIACollision(P1Bit, "P1"); } void toggleM0Collision() const { toggleTIACollision(M0Bit, "M0"); } void toggleM1Collision() const { toggleTIACollision(M1Bit, "M1"); } void toggleBLCollision() const { toggleTIACollision(BLBit, "BL"); } void togglePFCollision() const { toggleTIACollision(PFBit, "PF"); } void toggleCollisions() const; /** Toggles the TIA 'fixed debug colors' mode. */ void toggleFixedColors() const; /** Toggles the TIA 'scanline jitter' mode. */ void toggleJitter() const; private: /** * Dry-run the emulation and detect the frame layout (PAL / NTSC). */ void autodetectFrameLayout(); /** * Dryrun the emulation and detect ystart (the first visible scanline). */ void autodetectYStart(); /** Sets various properties of the TIA (YStart, Height, etc) based on the current display format. */ void setTIAProperties(); /** Adds the left and right controllers to the console. */ void setControllers(const string& rommd5); /** Selects the left or right controller depending on ROM properties */ unique_ptr getControllerPort(const string& rommd5, const string& controllerName, Controller::Jack port); /** Loads a user-defined palette file (from OSystem::paletteFile), filling the appropriate user-defined palette arrays. */ void loadUserPalette(); /** Loads all defined palettes with PAL color-loss data, even those that normally can't have it enabled (NTSC), since it's also used for 'greying out' the frame in the debugger. */ void generateColorLossPalette(); /** Returns a pointer to the palette data for the palette currently defined by the ROM properties. */ const uInt32* getPalette(int direction) const; void toggleTIABit(TIABit bit, const string& bitname, bool show = true) const; void toggleTIACollision(TIABit bit, const string& bitname, bool show = true) const; private: // Reference to the osystem object OSystem& myOSystem; // Reference to the event object to use const Event& myEvent; // Properties for the game Properties myProperties; // Pointer to the 6502 based system being emulated unique_ptr mySystem; // Pointer to the M6502 CPU unique_ptr my6502; // Pointer to the 6532 (aka RIOT) (the debugger needs it) // A RIOT of my own! (...with apologies to The Clash...) unique_ptr myRiot; // Pointer to the TIA object unique_ptr myTIA; // The frame manager instance that is used during emulation. unique_ptr myFrameManager; // Pointer to the Cartridge (the debugger needs it) unique_ptr myCart; // Pointer to the switches on the front of the console unique_ptr mySwitches; // Pointers to the left and right controllers unique_ptr myLeftControl, myRightControl; // Pointer to CompuMate handler (only used in CompuMate ROMs) shared_ptr myCMHandler; // The currently defined display format (NTSC/PAL/SECAM) string myDisplayFormat; // The currently defined display framerate float myFramerate; // Display format currently in use uInt32 myCurrentFormat; // Autodetected ystart. uInt32 myAutodetectedYstart; // Indicates whether an external palette was found and // successfully loaded bool myUserPaletteDefined; // Contains detailed info about this console ConsoleInfo myConsoleInfo; // Contains timing information for this console ConsoleTiming myConsoleTiming; // Table of RGB values for NTSC, PAL and SECAM static uInt32 ourNTSCPalette[256]; static uInt32 ourPALPalette[256]; static uInt32 ourSECAMPalette[256]; // Table of RGB values for NTSC, PAL and SECAM - Z26 version static uInt32 ourNTSCPaletteZ26[256]; static uInt32 ourPALPaletteZ26[256]; static uInt32 ourSECAMPaletteZ26[256]; // Table of RGB values for NTSC, PAL and SECAM - user-defined static uInt32 ourUserNTSCPalette[256]; static uInt32 ourUserPALPalette[256]; static uInt32 ourUserSECAMPalette[256]; private: // Following constructors and assignment operators not supported Console() = delete; Console(const Console&) = delete; Console(Console&&) = delete; Console& operator=(const Console&) = delete; Console& operator=(Console&&) = delete; }; #endif stella-5.1.1/src/emucore/Control.cxx000066400000000000000000000107071324334165500174070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "System.hxx" #include "Control.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Controller::Controller(Jack jack, const Event& event, const System& system, Type type) : myJack(jack), myEvent(event), mySystem(system), myType(type), myOnAnalogPinUpdateCallback(nullptr) { myDigitalPinState[One] = myDigitalPinState[Two] = myDigitalPinState[Three] = myDigitalPinState[Four] = myDigitalPinState[Six] = true; myAnalogPinValue[Five] = myAnalogPinValue[Nine] = maximumResistance; switch(myType) { case Joystick: myName = "Joystick"; break; case Paddles: myName = "Paddles"; break; case BoosterGrip: myName = "BoosterGrip"; break; case Driving: myName = "Driving"; break; case Keyboard: myName = "Keyboard"; break; case AmigaMouse: myName = "AmigaMouse"; break; case AtariMouse: myName = "AtariMouse"; break; case TrakBall: myName = "TrakBall"; break; case AtariVox: myName = "AtariVox"; break; case SaveKey: myName = "SaveKey"; break; case KidVid: myName = "KidVid"; break; case Genesis: myName = "Genesis"; break; case MindLink: myName = "MindLink"; break; case CompuMate: myName = "CompuMate"; break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Controller::read() { uInt8 ioport = 0x00; if(read(One)) ioport |= 0x01; if(read(Two)) ioport |= 0x02; if(read(Three)) ioport |= 0x04; if(read(Four)) ioport |= 0x08; return ioport; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Controller::read(DigitalPin pin) { return myDigitalPinState[pin]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int32 Controller::read(AnalogPin pin) { return myAnalogPinValue[pin]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Controller::set(DigitalPin pin, bool value) { myDigitalPinState[pin] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Controller::set(AnalogPin pin, Int32 value) { updateAnalogPin(pin, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Controller::updateAnalogPin(AnalogPin pin, Int32 value) { myAnalogPinValue[pin] = value; if (myOnAnalogPinUpdateCallback) { myOnAnalogPinUpdateCallback(pin); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Controller::save(Serializer& out) const { try { // Output the digital pins out.putBool(myDigitalPinState[One]); out.putBool(myDigitalPinState[Two]); out.putBool(myDigitalPinState[Three]); out.putBool(myDigitalPinState[Four]); out.putBool(myDigitalPinState[Six]); // Output the analog pins out.putInt(myAnalogPinValue[Five]); out.putInt(myAnalogPinValue[Nine]); } catch(...) { cerr << "ERROR: Controller::save() exception\n"; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Controller::load(Serializer& in) { try { // Input the digital pins myDigitalPinState[One] = in.getBool(); myDigitalPinState[Two] = in.getBool(); myDigitalPinState[Three] = in.getBool(); myDigitalPinState[Four] = in.getBool(); myDigitalPinState[Six] = in.getBool(); // Input the analog pins myAnalogPinValue[Five] = in.getInt(); myAnalogPinValue[Nine] = in.getInt(); } catch(...) { cerr << "ERROR: Controller::load() exception\n"; return false; } return true; } stella-5.1.1/src/emucore/Control.hxx000066400000000000000000000225011324334165500174070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CONTROLLER_HXX #define CONTROLLER_HXX class Controller; class Event; class System; #include #include "Serializable.hxx" #include "bspf.hxx" /** A controller is a device that plugs into either the left or right controller jack of the Video Computer System (VCS). The pins of the controller jacks are mapped as follows: ------------- \ 1 2 3 4 5 / \ 6 7 8 9 / --------- Left Controller Right Controller pin 1 D4 PIA SWCHA D0 PIA SWCHA pin 2 D5 PIA SWCHA D1 PIA SWCHA pin 3 D6 PIA SWCHA D2 PIA SWCHA pin 4 D7 PIA SWCHA D3 PIA SWCHA pin 5 D7 TIA INPT1 (Dumped) D7 TIA INPT3 (Dumped) pin 6 D7 TIA INPT4 (Latched) D7 TIA INPT5 (Latched) pin 7 +5 +5 pin 8 GND GND pin 9 D7 TIA INPT0 (Dumped) D7 TIA INPT2 (Dumped) Each of the pins connected to the PIA can be configured as an input or output pin. The "dumped" TIA pins are used to charge a capacitor. A potentiometer is sometimes connected to these pins for analog input. This is a base class for all controllers. It provides a view of the controller from the perspective of the controller's jack. @author Bradford W. Mott */ class Controller : public Serializable { /** Riot debug class needs special access to the underlying controller state */ friend class M6532; friend class RiotDebug; friend class CompuMate; public: /** Enumeration of the controller jacks */ enum Jack { Left = 0, Right = 1 }; /** Enumeration of the digital pins of a controller port */ enum DigitalPin { One, Two, Three, Four, Six }; /** Enumeration of the analog pins of a controller port */ enum AnalogPin { Five, Nine }; /** Enumeration of the controller types */ enum Type { AmigaMouse, AtariMouse, AtariVox, BoosterGrip, CompuMate, Driving, Genesis, Joystick, Keyboard, KidVid, MindLink, Paddles, SaveKey, TrakBall }; /** Callback type for analog pin updates */ using onAnalogPinUpdateCallback = std::function; public: /** Create a new controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller @param type The type for this controller */ Controller(Jack jack, const Event& event, const System& system, Type type); virtual ~Controller() = default; /** Returns the jack that this controller is plugged into. */ Jack jack() const { return myJack; } /** Returns the type of this controller. */ Type type() const { return myType; } /** Read the entire state of all digital pins for this controller. Note that this method must use the lower 4 bits, and zero the upper bits. @return The state of all digital pins */ virtual uInt8 read(); /** Read the value of the specified digital pin for this controller. @param pin The pin of the controller jack to read @return The state of the pin */ virtual bool read(DigitalPin pin); /** Read the resistance at the specified analog pin for this controller. The returned value is the resistance measured in ohms. @param pin The pin of the controller jack to read @return The resistance at the specified pin */ virtual Int32 read(AnalogPin pin); /** Write the given value to the specified digital pin for this controller. Writing is only allowed to the pins associated with the PIA. Therefore you cannot write to pin six. @param pin The pin of the controller jack to write to @param value The value to write to the pin */ virtual void write(DigitalPin pin, bool value) { } /** Called after *all* digital pins have been written on Port A. Most controllers don't do anything in this case. @param value The entire contents of the SWCHA register */ virtual void controlWrite(uInt8 value) { } /** Update the entire digital and analog pin state according to the events currently set. */ virtual void update() = 0; /** Notification method invoked by the system after its reset method has been called. It may be necessary to override this method for controllers that need to know a reset has occurred. */ virtual void reset() { } /** Notification method invoked by the system indicating that the console is about to be destroyed. It may be necessary to override this method for controllers that need cleanup before exiting. */ virtual void close() { } /** Determines how this controller will treat values received from the X/Y axis and left/right buttons of the mouse. Since not all controllers use the mouse the same way (or at all), it's up to the specific class to decide how to use this data. In the current implementation, the left button is tied to the X axis, and the right one tied to the Y axis. @param xtype The controller to use for x-axis data @param xid The controller ID to use for x-axis data (-1 for no id) @param ytype The controller to use for y-axis data @param yid The controller ID to use for y-axis data (-1 for no id) @return Whether the controller supports using the mouse */ virtual bool setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { return false; } /** Returns more detailed information about this controller. */ virtual string about(bool swappedPorts) const { return name() + " in " + ((myJack == Left) ^ swappedPorts ? "left port" : "right port"); } /** The following two functions are used by the debugger to set the specified pins to the given value. Note that this isn't the same as a write; the debugger is allowed special access and is actually 'below' the controller level. @param pin The pin of the controller jack to modify @param value The value to set on the pin */ void set(DigitalPin pin, bool value); void set(AnalogPin pin, Int32 value); /** Saves the current state of this controller to the given Serializer. @param out The serializer device to save to. @return The result of the save. True on success, false on failure. */ bool save(Serializer& out) const override; /** Loads the current state of this controller from the given Serializer. @param in The serializer device to load from. @return The result of the load. True on success, false on failure. */ bool load(Serializer& in) override; /** Returns the name of this controller. */ string name() const override { return myName; } /** Inject a callback to be notified on analog pin updates. */ void setOnAnalogPinUpdateCallback(onAnalogPinUpdateCallback callback) { myOnAnalogPinUpdateCallback = callback; } public: /// Constant which represents maximum resistance for analog pins static constexpr Int32 maximumResistance = 0x7FFFFFFF; /// Constant which represents minimum resistance for analog pins static constexpr Int32 minimumResistance = 0x00000000; protected: void updateAnalogPin(AnalogPin, Int32 value); protected: /// Specifies which jack the controller is plugged in const Jack myJack; /// Reference to the event object this controller uses const Event& myEvent; /// Pointer to the System object (used for timing purposes) const System& mySystem; /// Specifies which type of controller this is (defined by child classes) const Type myType; /// Specifies the name of this controller based on type string myName; /// The boolean value on each digital pin bool myDigitalPinState[5]; /// The callback that is dispatched whenver an analog pin has changed onAnalogPinUpdateCallback myOnAnalogPinUpdateCallback; private: /// The analog value on each analog pin Int32 myAnalogPinValue[2]; private: // Following constructors and assignment operators not supported Controller() = delete; Controller(const Controller&) = delete; Controller(Controller&&) = delete; Controller& operator=(const Controller&) = delete; Controller& operator=(Controller&&) = delete; }; #endif stella-5.1.1/src/emucore/DefProps.hxx000066400000000000000000023246621324334165500175300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DEF_PROPS_HXX #define DEF_PROPS_HXX /** This code is generated using the 'create_props.pl' script, located in the src/tools directory. All properties changes should be made in stella.pro, and then this file should be regenerated and the application recompiled. */ #define DEF_PROPS_SIZE 3316 static const char* const DefProps[DEF_PROPS_SIZE][21] = { { "000509d1ed2b8d30a9d94be1b3b5febb", "Greg Zumwalt", "", "Jungle Jane (2003) (Greg Zumwalt) (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0060a89b4c956b9c703a59b181cb3018", "CommaVid, Irwin Gaines - Ariola", "CM-008 - 712 008-720", "Cakewalk (1983) (CommaVid) (PAL)", "AKA Alarm in der Backstube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "007d18dedc1f0565f09c42aa61a6f585", "CCE", "C-843", "Worm War I (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "008543ae43497af015e9428a5e3e874e", "Retroactive", "", "Qb (V2.09) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "00b7b4cbec81570642283e7fc1ef17af", "Sega - Beck-Tech, Steve Beck, Phat Ho", "006-01", "Congo Bongo (1983) (Sega)", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "220", "", "" }, { "00ce0bdd43aed84a983bef38fe7f5ee3", "20th Century Fox, Bill Aspromonte", "11012", "Bank Heist (1983) (20th Century Fox)", "AKA Bonnie and Clyde, Cops 'n' Robbers, Holdup, Rooring 20's", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "00ce76ad69cdc2fa36ada01ae092d5a6", "Bit Corporation", "PGP214", "Cosmic Avenger (4 Game in One) (1983) (BitCorp) (PAL)", "AKA StarMaster", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "00dc28b881989c39a6cf87a892bd3c6b", "CCE", "", "Krull (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "00e19ebf9d0817ccfb057e262be1e5af", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL) [no grid markers]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "00e55b27fe2e96354cd21b8b698d1e31", "", "", "Phoenix (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "00eaee22034aff602f899b684c107d77", "Rainbow Vision - Suntek - Sunteck Corp", "SS-001", "Time Race (Rainbow Vision) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "240", "", "" }, { "00f7985c20b8bdf3c557fac4d3f26775", "Aaron Curtis", "", "AStar (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "012020625a3227815e47b37fd025e480", "Rob Kudla", "", "Better Space Invaders (1999) (Rob Kudla) (Hack) [a]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "01293bd90a4579abb7aed2f7d440681f", "Century", "", "Snoopy (1983) (Century) (PAL)", "AKA Snoopy and the Red Baron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "01297d9b450455dd716db9658efb2fae", "TechnoVision - Video Technology", "TVS1002", "Save Our Ship (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "45", "", "", "" }, { "012b8e6ef3b5fd5aabc94075c527709d", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (1983) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 56", "", "", "", "", "" }, { "0164f26f6b38a34208cd4a2d0212afc3", "Coleco, Ed English", "2656", "Mr. Do! (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0173675d40a8d975763ee493377ca87d", "CBS Electronics, Ed English", "4L1751", "Roc 'n Rope (1984) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "01abcc1d2d3cba87a3aa0eb97a9d7b9c", "Jone Yuan Telephonic Enterprise Co", "", "Topy (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "01b09872dcd9556427761f0ed64aa42a", "Galaga Games", "", "River Raid (1984) (Galaga Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "01cb3e8dfab7203a9c62ba3b94b4e59f", "Atari, Mimi Nyden, Scott Smith, Robert Vieira", "CX26127", "Gremlins (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "01e5c81258860dd82f77339d58bc5f5c", "CCE", "", "Corrida da Matematica (CCE)", "AKA Math Gran Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "01e60a109a6a67c70d3c0528381d0187", "ITT Family Games, Perry Rhodan-Serie", "554-33 383", "Fire Birds (1983) (ITT Family Games) (PAL)", "AKA Sky Alien", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "01f584bf67b0e464014a8c8b5ea470e3", "Arcadia Corporation, Dennis Caswell", "5 AR-4200", "Labyrinth (Escape from the Mindmaster Beta) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "02066b17f29082412c6754c1a2d6302e", "", "", "Demo Image Series #3 - Baboon (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "024365007a87f213cbe8ef5f2e8e1333", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "025668e36a788e8af8ac4f1be7e72043", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (06-14-82) (Atari) (Prototype)", "Console ports are swapped", "Prototype", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "026180bf641ff17d8577c33facf0edea", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0277c449fae63f6f1c8f94dedfcf0058", "", "", "Laser Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "027a59a575b78860aed780b2ae7d001d", "CCE", "", "Pressure Cooker (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "028024fb8e5e5f18ea586652f9799c96", "Coleco - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "2468", "Carnival (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "02811151906e477d47c135db5b1699c6", "", "", "FlickerSort Demo (Updated) (20-04-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "02a5fc90a0d183f870e8eebac1f16591", "HES", "771-422", "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "02ab2c47bc21e7feafa015f90d7df776", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "02ced7ea2b7cb509748db6bfa227ebec", "Parker Brothers, Ed English, David Lamkins", "931502", "Frogger (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "02cee0b140d2f1a1efcfb1d482a5c392", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "02dcba28c614fec7ca25955327128abb", "Andrew Wallace", "", "Laseresal 2002 (PAL) (PD) [a]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "02e3f4ba156fb578bef7d7a0bf3400c1", "", "", "Booster (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "033e21521e0bf4e54e8816873943406d", "20th Century Fox Video Games - Sirius Software, Dan Thompson", "11020", "Earth Dies Screaming, The (1983) (20th Century Fox)", "The Day the Earth Stood Still", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "034c1434280b0f2c9f229777d790d1e1", "Telegames", "5665 A016", "Baseball (1988) (Telegames) (PAL)", "AKA Super Challenge Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0375f589f7da06d2d2be532e0d4d4b94", "", "", "Push (V0.04) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0383dc02cb82302da3d155fd108bfe3a", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug) (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "YES", "" }, { "038e1e79c3d4410defde4bfe0b99cc32", "Atari, Tod Frye, Gary Shannon", "", "Aquaventure (08-12-1983) (Atari) (Prototype)", "AKA Sea Sentinel", "Unbelievably Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "039cf18b459d33b8a8fca31d06c4c244", "", "", "Demo Image Series #0 (12-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "03b1051c9374678363c899914412cfc5", "", "", "Incoming (30-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "03c3f7ba4585e349dd12bfa7b34b7729", "Sega, Jeff Lorenz", "004-01", "Star Trek - Strategic Operations Simulator (1983) (Sega)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "03ff9e8a7af437f16447fe88cea3226c", "Bomb - Onbase", "CA285", "Wall-Defender (1983) (Bomb)", "AKA Wall Break", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "04014d563b094e79ac8974366f616308", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "041b5e56bbc650db574bd8db3fae2696", "", "", "Thrust (V1.0) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "043f165f384fbea3ea89393597951512", "Spectravision - Spectravideo", "SA-202", "Planet Patrol (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0443cfa9872cdb49069186413275fa21", "M Network, Patricia Lewis Du Long, Ron Surratt - INTV", "MT4518", "BurgerTime (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "045035f995272eb2deb8820111745a07", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia)", "AKA Jungle Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "047ac3b9faea64522b7a23c4465a7aa8", "", "", "Defender (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "04856e3006a4f5f7b4638da71dad3d88", "Atari, Douglas Neubauer", "CX26176", "Radar Lock (1989) (Atari) (PAL)", "AKA Dog Fight", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "049626cbfb1a5f7a5dc885a0c4bb758e", "", "", "MegaMania (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "04b488d4eef622d022a0021375e7e339", "Home Vision - Gem International Corp. - VDI", "VCS83107", "Tennis (1983) (Home Vision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "04dfb4acac1d0909e4c360fd2ac04480", "", "", "Jammed (2001) (XYPE) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "04e737c9d53cd84bfd5ee679954e4706", "Jone Yuan Telephonic Enterprise Co", "", "Checkers (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "04fccc7735155a6c1373d453b110c640", "HES - Imagineering, David Lubar", "535", "My Golf (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0519f395d5f7d76be813b834aa51c0be", "Atari, Ian Shepard", "CX2604", "Space War (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0546f4e6b946f38956799dd00caab3b1", "Thomas Jentzsch", "", "My Golf (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "056f5d886a4e7e6fdd83650554997d0d", "Parker Brothers, Ed Temple", "931504", "Amidar (1982) (Parker Bros) (PAL)", "", "Uncommon", "", "", "A", "A", "", "", "", "", "", "", "", "", "", "", "" }, { "056ff67dd9715fafa91fb8b0ddcc4a46", "", "", "Frisco (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05824fcbe615dbca836d061a140a50e0", "Jeffry Johnston", "", "Radial Pong - Version 9 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05aedf04803c43eb5e09dfd098d3fd01", "", "", "Keystone Kapers (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05aff8f626ef870432ae3b3d9d5aa301", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05b45ba09c05befa75ac70476829eda0", "Parker Brothers, Rex Bradford", "931507", "Star Wars - Jedi Arena (1983) (Parker Bros) (PAL)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 50", "", "", "", "", "" }, { "05c60458ec69e7fe8b1be973852d84f1", "", "", "Test (1996) (J.V. Matthews) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05ccf96247af12eef59698f1a060a54f", "Otto Versand", "600273", "King Arthur (1983) (Otto Versand) (PAL)", "AKA Dragonfire (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05d61b925d3d2474bab83f0a79bb5df1", "Eckhard Stolberg", "", "Cosmic Ark Stars (1997) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05eb4347f0ec8f4783983ca35ffd8d1b", "", "", "Qb (2.06) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "05ebd183ea854c0a1b56c218246fbbae", "Atari, Dan Hitchens", "CX2656", "SwordQuest - EarthWorld (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "05f11fb2e45c4e47424d3cb25414d278", "", "", "Boring (NTSC) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "060c865c782debb047e6fd101c8923fc", "Atari", "CX26163P", "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0614ed51acd027d531e7c85c4f435292", "", "", "Narnia (Glenn Saunders) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0651216c4a4a9c9ac5ada3013a317c72", "Jone Yuan Telephonic Enterprise Co", "", "Fishing Derby (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06742cf522f23797157f215a1dc8a1a9", "", "", "Healthbars (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0685bd0bcb975ceef7041749a5454a48", "Piero Cavina", "", "11 Sprite Demo (Piero Cavina) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06953ed762220dba63d63930d4ad0cc3", "", "", "Star Fire - Eckhard WIP (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "069c17beb1e8e0557adb8539fdcf6cba", "", "", "Phantom II & Pirate (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "06b0194ce992584c365278e0d7323279", "Activision", "", "Unknown Activision Game #2 (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06b6c5031b8353f3a424a5b86b8fe409", "Activision, Mike Lorenzen - Ariola", "EAX-023 - 711 023-720", "Oink! (1983) (Activision) (PAL)", "AKA Das Schweinchen und der Wolf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06cfd57f0559f38b9293adae9128ff88", "Telegames", "4317 A009", "Adventures on GX-12 (1988) (Telegames) (PAL)", "AKA Adventures of Tron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06db908011065e5ebb37f4e253c2a0b0", "", "", "Gopher (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "06e5dc181a8eda1c31cc7c581c68b6ef", "", "", "Tac-Scan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "071f84d10b343c7c05ce3e32af631687", "Videospielkassette - Ariola", "PGP233", "Krieg der Sterne (Ariola) (PAL)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "072a6ea2181ca0df88ac0dedc67b239d", "", "", "Multiple Missiles Demo (19-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "073cb76b006af034fd150be3f5e0e7e6", "", "", "Mobile 48 Sprite Kernel (Bug Fixed) (10-01-2003) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "073d7aff37b7601431e4f742c36c0dc1", "", "", "Bermuda (Unknown) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "074ec425ec20579e64a7ded592155d48", "Atari - Sculptured Software, Steve Aguirre", "CX26162", "Fatal Run (Ultimate Driving) (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "075069ad80cde15eca69e3c98bd66714", "CCE", "C-803", "Bobby Is Going Home (1983) (CCE)", "AKA Bobby Vai Para Casa", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0751f342ee4cf28f2c9a6e8467c901be", "Atari, Mimi Nyden, Joseph Tung", "CX26152", "Super Baseball (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "07973be3ecfd55235bf59aa56bdef28c", "Quelle", "732.052 6", "Eddy Langfinger, der Museumsdieb (1983) (Quelle) (PAL)", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "079fe9103515d15bc108577e234a484d", "", "", "Multi-Color Demo 0 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "07a3af1e18b63765b6807876366f5e8a", "Joe Grand", "", "SCSIcide Pre-release 2 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "07c76f2d88552d20ad2c0ed7aef406c6", "Cody Pittman", "", "Blob (Cody Pittman) (Hack)", "Hack of Halloween", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "07f42847a79e4f5ae55cc03304b18c25", "Zellers", "", "Sea Hawk (Zellers)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "07f84db31e97ef8d08dc9fa8a5250755", "Supergame", "", "Enduro (1984) (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "07f91e33e76f53bb9d2731fd5d8a35a5", "Atari", "CX2632", "Space Invaders (1978) (Atari) [t1]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0805366f1b165a64b6d4df20d2c39d25", "Atari, Dan Hitchens", "CX2650", "Berzerk (1982) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08188785e2b8300983529946dbeff4d2", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari) (4K)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "28", "", "", "" }, { "081e2c114c9c20b61acf25fc95c71bf4", "Parker Brothers, Ed English, David Lamkins", "PB5300", "Frogger (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "082fdc8bd47fef01482ce5883c4ffdb8", "Charles Morgan", "", "Tanks DX (Charles Morgan) (Hack)", "Hack of Tanks But No Tanks", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0832fb2ee654bf9382bc57d2b16d2ffc", "Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "083e7cae41a874b2f9b61736c37d2ffe", "Imagic, Rob Fulop, Bob Smith", "720106-2A, IA3600P, EIX-009-04I", "Riddle of the Sphinx (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "085322bae40d904f53bdcc56df0593fc", "Parker Brothers, Dave Engman, Dawn Stockbridge", "PB5340", "Tutankham (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0856f202b18cd46e44fd1dc3b42e9bfb", "", "", "Frame Counter 1 (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0866e22f6f56f92ea1a14c8d8d01d29c", "Androbot - Western Technologies, Michael Case, Lenny Carlson", "", "AndroMan on the Moon (1984) (Western Tech) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0890a5b089191f45d0f08dd1e3235687", "", "", "Star Fire - 4K Version (25-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0894aa7be77521f9df562be8d9555fe6", "CBS Electronics, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1982) (CBS Electronics) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08989fa4ff537f5dbd611aff4019521a", "Atari, Gary Palmer", "CX26163P", "Fun with Numbers (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08bd4c1dcc843f6a0b563d9fd80b3b11", "Quelle", "343.273 9", "Phantompanzer II (1983) (Quelle) (PAL)", "AKA Thunderground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08bf437d012db07b05ff57a0c745c49e", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Meteoroids (1982) (Arcadia) (Prototype)", "Suicide Mission Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "08d1b6d75206edb999252caf542a2c7f", "Larry Petit", "", "Super Home Run (2003) (Larry Petit) (Hack)", "Hack of Home Run", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08d60a58a691c7f690162850302dc0e1", "", "", "Poker Squares (V0.27) (PAL) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "08e5960bb52d9a3e2c9954677b5e4472", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (10-20-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "34", "", "", "" }, { "08f4dc6f118f7c98e2406c180c08e78e", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Tug of War (2 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "02", "", "", "", "", "" }, { "08f853e8e01e711919e734d85349220d", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0906c6e0e4bda9c10cfa4c5fc64d2f4b", "Retroactive", "", "Qb (V0.12) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "090f0a7ef8a3f885048d213faa59b2f8", "Carrere Video - Western Technologies - Teldec - Prism", "USC1012", "M.A.D. (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "09274c3fc1c43bf1e362fda436651fd8", "Thomas Jentzsch", "", "Acid Drop (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "6", "240", "", "" }, { "09388bf390cd9a86dc0849697b96c7dc", "Absolute Entertainment, Alex DeMeo", "AG-045-04, AK-045-04", "Pete Rose Baseball (1988) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0945081a6bd00345ff3d58eb7a07330a", "", "", "Stampede (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0956285e24a18efa10c68a33846ca84d", "Dismac", "", "Viagem Espacial (Dismac)", "AKA Star Voyager", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0963aa9f7f6cf5a36ff700001583624e", "Franklin Cruz", "", "Space Invaders 2 (Hack) [o1]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "096649575e451508006b17e0353259a5", "Justin J. Scott", "", "Yar Vs. Yar (2002) (Justin J. Scott) (Hack)", "Hack of Yars' Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "097074f24cde141fe6a0f26a10333265", "", "", "Marble Craze (V0.90) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "097936b07e0e0117b9026ae6835eb168", "Imagic, Dennis Koble", "720100-2B, IA3000P", "Trick Shot (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "09abfe9a312ce7c9f661582fdf12eab6", "Atari, Douglas Neubauer", "CX26154", "Super Football (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "09d19274c20768f842e8fae84b766abe", "", "", "Star Fire - Animated Patricles (06-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "09e1ecf9bd2a3030d5670dba7a65e78d", "Atari, James Andreasen", "CX2654", "Haunted House (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "09f89bbfa2ab00f1964d200e12d7ced0", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0a1b98937911d621b004b1617446d124", "", "", "Hangman Pac-Man Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0a981c03204ac2b278ba392674682560", "Atari, Bob Whitehead - Sears", "CX2651 - 99805, 49-75602", "Blackjack (1977) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "" }, { "0aa208060d7c140f20571e3341f5a3f8", "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper", "VC1009", "Towering Inferno (1982) (U.S. Games)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "220", "YES", "" }, { "0abf64ca504a116adca80f77f85e00fb", "", "", "Cube Conquest (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0ac0d491763153fac75f5337ce32a9d6", "", "", "SPAM Image Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0acaf71e60b89f6b6eab63db6ab84510", "", "", "This Planet Sucks (Greg Troutman) [a2]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "0aceb7c3bd13fe048b77a1928ed4267d", "Imagic, Bob Smith", "720102-2B, IA3201P, EIX-011-04I", "Star Voyager (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0ad9a358e361256b94f3fb4f2fa5a3b1", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner - Sears", "CX2608 - 49-75165", "Super Breakout (1982 - 1981) (Atari) [a]", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 45", "", "", "", "", "" }, { "0adb21206de92e8aec5ef295805ebb90", "", "", "Solaris (Genesis)", "Genesis controller (C switches to map mode)", "Hack of Solaris", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "0ae3497e731ca0bf6a77b23441d9d9f9", "", "", "Analog Clock (V0.0) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0af51ceb4aecc7a8fc89781ac44a1973", "Barry Laws Jr.", "", "Face Invaders Deluxe (Barry Laws Jr.) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0afe6ae18966795b89314c3797dd2b1e", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692, CX2692P", "Moon Patrol (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0b01909ba84512fdaf224d3c3fd0cf8d", "", "", "Revenge of the Apes (Hack)", "Hack of Planet of the Apes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0b1056f1091cfdc5eb0e2301f47ac6c3", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001 - 3.60001 VE", "King Kong (1982) (Tigervision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0b17ed42984000da8b727ca46143f87a", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (05-17-1983) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, { "0b24658714f8dff110a693a2052cc207", "CCE", "C-815", "Seaquest (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0b33252b680b65001e91a411e56e72e9", "CCE", "C-832", "Atlantis (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0b4e793c9425175498f5a65a3e960086", "CCE", "", "Kung Fu Master (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0b55399cf640a2a00ba72dd155a0c140", "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop", "720111-1A, 03205", "Fathom (1983) (Imagic)", "AKA Scuba", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0b577e63b0c64f9779f315dca8967587", "Videospielkassette - Ariola", "PGP236", "Raketen-Angriff (Ariola) (PAL)", "AKA Missile Control", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0b8d3002d8f744a753ba434a4d39249a", "Sears Tele-Games, Robert Zdybel", "CX2619 - 49-75159", "Stellar Track (1981) (Sears)", "AKA Stella Trak", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0bf19e40d5cd8aa5afb33b16569313e6", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0bf1e354304f46c0caf8fc0f6f5e9525", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "0bfabf1e98bdb180643f35f2165995d0", "Atari, Bob Whitehead - Sears", "CX2623 - 6-99819, 49-75108, 49-75125", "Home Run (1978) (Atari)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "0c0392db94a20e4d006d885abbe60d8e", "", "", "Dodge Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c35806ff0019a270a7acae68de89d28", "Froggo", "FG1003", "Task Force (1987) (Froggo)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c48e820301251fbb6bcdc89bd3555d9", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c54811cf3b1f1573c9164d5f19eca65", "Activision, David Crane - Ariola", "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715", "Dragster (1980) (Activision) (PAL)", "AKA Dragster Rennen, Drag Strip", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0c7926d660f903a2d6910c254660c32c", "Atari, Larry Kaplan", "CX2602, CX2602P", "Air-Sea Battle (1977) (Atari) (PAL)", "AKA Anti-Aircraft", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "0c7bd935d9a7f2522155e48315f44fa0", "Carrere Video - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper - Teldec - Prism", "USC1009", "Infernal Tower (1983) (Carrere Video) (PAL)", "AKA Towering Inferno", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "YES", "" }, { "0c80751f6f7a3b370cc9e9f39ad533a7", "Atari, Carla Meninsky", "CX2610", "Warlords (1981) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 50", "", "", "", "", "" }, { "0cb7af80fd0ddef84844481d85e5d29b", "", "", "Mr. Pac-Man (El Destructo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0cc8224ff1edfe458e8629e9e5fe3f5b", "", "", "Trick 12 (2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0cdd9cc692e8b04ba8eb31fc31d72e5e", "Thomas Jentzsch", "", "Wing War (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0cebb0bb45a856b23f56d21ce7d1bc34", "20th Century Fox Video Games, Bill Aspromonte", "11131", "Crash Dive (1983) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0cfdd2f3b243cac21f38a0f09f54bead", "", "", "Overhead Adventure Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d07d2c1be1a5eaaea235a533bcda781", "", "", "Scrolling Playfield 1 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d09cff0d28033c02c3290edfc3a5cea", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d1b3abf681a2fc9a6aa31a9b0e8b445", "Atari", "CX26163P", "Laser Blast (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d27c7f5db349b592f70f68daf5e8f3b", "", "", "Space Instigators (21-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d35618b6d76ddd46d2626e9e3e40db5", "", "", "X-Doom V.26 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d5af65ad3f19558e6f8e29bf2a9d0f8", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dark Chambers (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0d6b974fe58a1bdd453600401c407856", "Atari", "", "128-in-1 Junior Console (Chip 3 or 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d786a41695e5fc8cffd05a6dbb3f659", "", "", "Scrolling Playfield With Score (10-02-2003) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d7e630a14856f4d52c9666040961d4d", "", "", "Wavy Line Test (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0d90a0ee73d55539b7def24c88caa651", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0db4f4150fecf77e4ce72ca4d04c052f", "Atari, Carol Shaw - Sears", "CX2618 - 49-75123", "3-D Tic-Tac-Toe (1980) (Atari)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0dd4c69b5f9a7ae96a7a08329496779a", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001 - 3.60001 VE", "King Kong (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0de53160a8b54c3aa5aed8d68c970b62", "Quelle", "806.174 9", "Fuchs & Schweinchen Schlau (1983) (Quelle) (PAL)", "AKA Oink!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0dfbdadf8f1bc718e7e1bb3ccd5fef3d", "", "", "Mr. Pac-Man (New start tune) (El Destructo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e0808227ef41f6825c06f25082c2e56", "", "", "Candi (Hack) [a]", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e08cd2c5bcf11c6a7e5a009a7715b6a", "", "", "Boing! (PD) [a1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e224ea74310da4e7e2103400eb1b4bf", "Atari, Gary Shannon, Howard Scott Warshaw", "", "Mind Maze (10-10-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "" }, { "0e4b2b6e014a93ef8be896823da0d4ec", "", "", "Skiing (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0e713d4e272ea7322c5b27d645f56dd0", "Home Vision - Gem International Corp. - VDI", "VCS83105", "Panda Chase (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "0e7e73421606873b544e858c59dc283e", "Digivision", "", "Super Soccer (Digivision)", "AKA RealSports Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0e86470791b26292abe1c64545c47985", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Down on the Line (3 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "01 70", "", "", "", "", "" }, { "0ec93f519bb769e0d9f80e61f6cc8023", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (02-25-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0eebfb60d437796d536039701ec43845", "Fabrizio Zavagli", "", "Cakewalk (Fabrizio Zavagli)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0eecb5f58f55de9db4eedb3a0f6b74a8", "Xonox - Beck-Tech", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "0ef64cdbecccb7049752a3de0b7ade14", "Atari, Joe Decuir, Larry Caplan, Steve Mayer, Larry Wagner", "CX26163P", "Combat (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "0f14c03050b35d6b1d8850b07578722d", "Jeffry Johnston", "", "Radial Pong - Version 10 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0f24ca5668b4ab5dfaf217933c505926", "", "", "Fantastic Voyage (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0f2e09c71cc216f79d22a804152ba24b", "Bob Colbert", "", "Scroller Demo (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0f341d1f4e144e3163d9a5fc5a662b79", "", "", "RUN Platform Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "0f39fc03d579d0d93a6b729a3746843e", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (05-27-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0f643c34e40e3f1daafd9c524d3ffe64", "Atari, Robert C. Polaro, Alan J. Murphy - Sears", "CX2609 - 49-75186", "Defender (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0f6676b05621f80c670966e2995b227a", "", "", "Globe Trotter Demo 1 (24-03-2003) (Weston)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0f738dc44437557624eb277ed7ad91c9", "", "", "Grand Prix (Unknown) (PAL)", "AKA Grand Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0f8043715d66a4bbed394ef801d99862", "Quelle", "684.733 9", "Robin Hood (1983) (Quelle) (PAL)", "AKA Save Our Ship", "", "", "", "", "", "", "", "", "", "", "", "", "45", "", "", "" }, { "0f95264089c99fc2a839a19872552004", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0fba7d8c3520bdb681f75494e498ec36", "", "", "Gunfight 2600 - Final Run (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0fbf618be43d4396856d4244126fe7dc", "Quelle", "805.784 6", "Labyrinth (1983) (Quelle) (PAL)", "AKA Maze Craze", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "", "" }, { "0fc161704c46e16f7483f92b06c1558d", "CCE", "C-853", "Spider Fighter (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "0fcff6fe3b0769ad5d0cf82814d2a6d9", "Suntek", "SS-027", "Zoo Fun (Suntek) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "0fd72a13b3b6103fc825a692c71963b4", "Imagic, Rob Fulop", "720104-2A, IA3204P, EIX-008-04I", "Cosmic Ark (1982) (Imagic) (PAL) [selectable starfield]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "101ab60f4000a5d13792ef0abad5f74b", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "102672bbd7e25cd79f4384dd7214c32b", "Atari, Alan Miller - Sears", "CX2642 - 6-99814", "Hunt & Score - Memory Match (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "103d4c890c2108cb536372c98d093e5f", "", "", "Star Fire - Star Background (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "103e9d616328969f5d7b4e0a381b25d5", "", "", "Playfield Illustration and Logo Demo (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "103f1756d9dc0dd2b16b53ad0f0f1859", "Home Vision, Gem International Corp.", "", "Go Go Home Monster (1983) (Home Vision) (PAL)", "AKA Go Go Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "104468e44898b8e9fa4a1500fde8d4cb", "AtariAge, Chris Spry", "CX26200", "Princess Rescue (2013) (Sprybug)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "106326c262dfd3e8eaeabd961d2a0519", "", "", "PAL-NTSC Detector (15-11-2002) (CT)[a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "106855474c69d08c8ffa308d47337269", "Atari - Sculptured Software, Adam Clayton", "CX26151", "Dark Chambers (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "107cc025334211e6d29da0b6be46aec7", "Atari, Bob Smith - Sears", "CX2648 - 49-75161", "Video Pinball (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1086ff69f82b68d6776634f336fb4857", "Activision, David Crane", "AG-009", "Bloody Human Freeway (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "10958cd0a1a81d599005f1797ab0e51d", "", "", "Centipede 2k (2000) (PD) (Hack)", "Hack of Centipede", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "10a3cd14e5dcfdde6ff216a14ce7b7dd", "Atari", "CX262, CX2627P", "Human Cannonball (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "10af8728f975aa35a99d0965de8f714c", "Dinatronic", "", "Seaquest (Dinatronic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "10c8cfd8c37522f11d47540ff024e5f9", "Canal 3 - Intellivision", "C 3016", "Demon Attack (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "10eae73a07b3da044b72473d8d366267", "Funvision - Fund. Int'l Co.", "", "Karate (1982) (Funvision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "10f0ecaf962aef1fc28abed870b01b65", "Atari, Paul Donaldson", "", "Bionic Breakthrough (06-22-1984) (Atari) (Prototype)", "Uses the Mindlink Controller", "Prototype", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "", "" }, { "10f62443f1ae087dc588a77f9e8f43e9", "Atari, Carla Meninsky", "CX2637, CX2637P", "Dodge 'Em (1980) (Atari) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "110ac8ecaf1b69f41bc94c59dfcb8b2d", "", "", "Demon Attack (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "111029770226b319524134193886a10e", "Hozer Video Games", "", "Gunfight 2600 - One Limit Reached! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "11330eaa5dd2629052fac37cfe1a0b7d", "128-in-1 Junior Console", "", "Human Cannonball (128-in-1 Junior Console) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "113cd09c9771ac278544b7e90efe7df2", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari) [no grid markers]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "114c599454d32f74c728a6e1f71012ba", "Activision, Bob Whitehead - Ariola", "EAX-015, EAX-015-04I - 711 015-725", "Chopper Command (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "11bcf5c752088b5aaf86d6c7a6a11e8d", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "11cf751bc8173db105eabd119c5844ba", "", "", "Star Fire - Crosshair (12-02-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "11e7e0d9437ec98fa085284cf16d0eb4", "", "", "Bowling (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "11f9532557e4c9569f4b242164006161", "Chris Walton, Justin Hairgrove, Tony Morse", "", "Hunchy II (2005) (PAL)", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1201c18cf00d2c236f42e4d7d8c86aa1", "", "", "Nick Bensema Demo (Nick Bensema)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "12123b534bdee79ed7563b9ad74f1cbd", "Absolute Entertainment, Alex DeMeo", "AG-041-04", "Title Match Pro Wrestling (1987) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1228c01cd3c4b9c477540c5adb306d2a", "Atari, Alan Miller", "CX26163P", "Basketball (32 in 1) (1988) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "1266b3fd632c981f3ef9bdbf9f86ce9a", "Activision, Bob Whitehead", "EAZ-034-04, EAZ-034-04I", "Private Eye (1984) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1267e3c6ca951ff1df6f222c8f813d97", "", "", "Dragonfire (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1278f74ca1dfaa9122df3eca3c5bcaad", "Quelle", "719.013 5", "Ungeheuer der Tiefe (Quelle) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1287535256bf5dff404839ac9e25c3e7", "PacManPlus", "Rev 2", "Alien Pac-Man (PacManPlus) (Hack)", "Hack of Alien", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "12937db3d4a80da5c4452b752891252d", "Digitel", "", "Megamania (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "12bca8305d5ab8ea51fe1cfd95d7ab0e", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00250", "Summer Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "12d7e0d6b187889f8d150bf7034d1db2", "", "", "Poker Squares (V0.0e) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "130c5742cd6cbe4877704d733d5b08ca", "Home Vision - Gem International Corp. - VDI", "VCS83109", "World End (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1323c45d660f5a5b6d5ea45c6c4cbe4a", "Canal 3 - Intellivision", "", "Enduro (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "133456269a03e3fdae6cddd65754c50d", "Tigervision - Software Electronics Corporation - Teldec", "7-006 - 3.60008 VG", "Springer (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "133a4234512e8c4e9e8c5651469d4a09", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "133b56de011d562cbab665968bde352b", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1343de49c2a50d99176255f99f0d0234", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "24", "280", "YES", "55" }, { "13448eb5ba575e8d7b8d5b280ea6788f", "Digivision", "", "Crackpots (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1345e972dbe08ea3e70850902e20e1a5", "Greg Troutman", "", "Dark Mage (rough beta) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1351c67b42770c1bd758c3e42f553fea", "Digivision", "", "Keystone Kapers (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "135708b9a7dd20576c1b66ab2a41860d", "", "", "Hangman Man Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13584411da0a8d431991035423fdc0dc", "Jone Yuan Telephonic Enterprise Co", "", "Skiing (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1367e41858be525710eb04d0dab53505", "Kyle Pittman", "", "Zelda (2003) (Kyle Pittman) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "136f75c4dd02c29283752b7e5799f978", "Atari, Dan Hitchens - Sears", "CX2650 - 49-75168", "Berzerk (1982) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13895ef15610af0d0f89d588f376b3fe", "Tigervision, Rorke Weigandt", "7-005", "Marauder (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13a37cf8170a3a34ce311b89bde82032", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13a991bc9c2ff03753aeb322d3e3e2e5", "Funvision - Fund. International Co.", "", "Galactic (Funvision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13aa1f9ac4249947e4af61319d9a08f2", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13abc32f803165c458bb086fa57195fb", "Christian Samuel", "", "E.T. The Extra-Testical (Christian Samuel) (Hack)", "Hack of E.T. The Extra-Terrestrial", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13ccc692f111d52fec75d83df16192e2", "Canal 3 - Intellivision", "", "Fishing Derby (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13d8326bf5648db4dafce45d25e62ddd", "", "", "Atari Logo Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "13dfb095e519a555a5b60b7d9d7169f9", "", "", "Red Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "140909d204abd6841c64cdad4d7765b4", "", "", "Moving Blue Ladder Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "14163eb2a3ddd35576bd8527eae3b45e", "", "", "Multi-Color Demo 6 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1423f560062c4f3c669d55891a2bcbe7", "CCE", "C-859", "MASH (1983) (CCE) [a]", "AKA M.A.S.H", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1428029e762797069ad795ce7c6a1a93", "", "", "Thunderground (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "143918368f4f4dfff90999188c0197c9", "", "", "Unknown Title (bin00016 (200110)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1442d1b35a6478fba22ae7dd1fcb5634", "", "", "Thrust (V0.2) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "148471144ccebd7f6aa9aa9215896533", "Parker Brothers - JWDA, Todd Marshall", "PB5550", "Q-bert's Qubes (1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "149b543c917c180a1b02d33c12415206", "CCE", "C-857", "Superman (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "14a56b493a8d9d10e94a3e100362e3a2", "Hozer Video Games", "", "Gunfight 2600 - Early Play-kernel (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "14b1e30982962c72f426e2e763eb4274", "Atari, Carol Shaw - Ralph Lauren", "", "Polo (1978) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "14c2548712099c220964d7f044c59fd9", "First Star Software, Alex Leavens, Shirley Ann Russell", "", "Boing! (1983) (First Star Software)", "AKA Bubbles, Soap Suds, The Emphysema Game", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "14d365bbfaac3d20c6119591f57acca4", "", "", "Video Life (Unknown) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "14dbb3686dd31964332dc2ef0c55cad0", "", "", "Demo Image Series #15 - Three Marios (PAL) (Non-Interleave) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "151c33a71b99e6bcffb34b43c6f0ec23", "Parker Brothers, Laura Nikolich", "", "Care Bears (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "151fa3218d8d7600114eb5bcd79c85cb", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (05-02-1983) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, { "152c253478b009c275e18cd731b48561", "", "", "Quest (11-10-2002) (Chris Larkin)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "153f40e335e5cb90f5ce02e54934ab62", "Absolute Entertainment, Alex DeMeo", "EAZ-041-04I", "Title Match Pro Wrestling (1987) (Absolute) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1542662f665d2ffaa77b4b897dd2e2af", "", "", "Starfield (V1.0) (2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "155fa7f479dcba3b10b1494e236d6010", "Skyworks", "", "Tomcat (2002) (Skyworks) (PAL)", "AKA The F-14 Flight Simulator", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "157356f80c709ab675961d8b8b207e20", "", "", "Multi-Sprite Game V2.5 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "157bddb7192754a45372be196797f284", "Atari, Warren Robinett - Sears", "CX2613, 49-75154", "Adventure (1980) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "159e5cd6ccb968015f49aed5adbc91eb", "Justin J. Scott", "", "Yar's Defeat (2002) (Justin J. Scott) (Hack)", "Hack of Yars' Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "15b498199ed0ed28057bf0dbdce9b8d8", "Hozer Video Games", "", "Jammed (V0.2) (Demo) (2001) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "15bcd74f2f1f2a63e1aa93e90d2c0555", "", "", "Incoming (22-08-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "15bf2ef7583bfcbbba630847a1dc5539", "Erik Eid", "", "Euchre (Jul 15) (2002) (Eric Eid) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "15c11ab6e4502b2010b18366133fc322", "Atari - Axlon, Tod Frye - Heuristica, Augustin Ortiz", "CX26169", "Shooting Arcade (09-19-1989) (Atari) (Prototype)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "15dd21c2608e0d7d9f54c0d3f08cca1f", "Data Age, J. Ray Dettling", "112-008", "Frankenstein's Monster (1983) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "15fe28d0c8893be9223e8cb2d032e557", "", "", "Towering Inferno (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1619bc27632f9148d8480cd813aa74c3", "Thomas Jentzsch", "", "Steeple Chase (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "", "220", "YES", "" }, { "161ded4a85d3c78e44fffd40426f537f", "", "", "JtzBall (Alpha) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "163e7e757e2dc44469123ff0e5daec5e", "", "", "Many Blue Bars and Text Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "169d4c7bd3a4d09e184a3b993823d048", "", "", "Superman (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "16cb43492987d2f32b423817cdaaf7c4", "Atari, Larry Kaplan - Sears", "CX2602 - 99802, 6-99802, 49-75102", "Air-Sea Battle (1977) (Atari)", "AKA Target Fun (Anti-Aircraft)", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "16cc6d1b4ddce51c767a1ba8e5ff196c", "", "", "Big - Move This Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "16e04823887c547dc24bc70dff693df4", "Atari", "CX26163P", "Tennis (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "16ee443c990215f61f7dd1e55a0d2256", "Spectravideo, David Lubar", "SA-218, SA-218C", "Bumper Bash (1983) (Spectravideo) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "54", "", "", "" }, { "16f494f20af5dc803bc35939ef924020", "Mark De Smet", "", "Video Simon (Mark De Smet)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "16fbb36a6124567405a235821e8f69ee", "", "", "Star Fire (28-11-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "170e7589a48739cfb9cc782cbb0fe25a", "M Network - APh Technological Consulting, Hal Finney - INTV", "MT5666", "Astroblast (1982) (M Network) [fixed]", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "PADDLES", "", "YES", "AUTO 55", "", "", "", "", "" }, { "171cd6b55267573e6a9c2921fb720794", "Kurt Howe", "", "Adventure 34 (Kurt Howe) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1733772165d7b886a94e2b4ed0f74ccd", "", "", "Boring Journey Escape (Hack)", "Hack of Journey - Escape", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "230", "", "" }, { "1738b2e3f25ab3eef3cecb95e1d0d957", "", "", "Hangman Monkey Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "17512d0c38f448712f49f36f9d185c4e", "Retroactive", "", "Qb (Release Candidate #1) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "17515a4d0b7ea5029ffff7dfa8456671", "Piero Cavina", "", "Multi-Sprite Demo V1.1 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "176d3fba7d687f2b23158098e103c34a", "Zach Matley", "", "Combat AI (16-02-2003) (Zach Matley)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "34", "", "", "" }, { "177504abd4260c4265e1338955e9fa47", "HCC Software", "", "Pitfall! (Steroids Hack)", "Hack of Pitfall! (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1782929e1c214b70fb6884f77c207a55", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (Prototype)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "17ba72433dd41383065d4aa6dedb3d91", "", "", "SCSIcide (09-06-2001) (Joe Grand)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "17badbb3f54d1fc01ee68726882f26a6", "M Network - APh Technological Consulting, Hal Finney, Bruce Pedersen - INTV", "MT5659", "Space Attack (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "17bbe288c3855c235950fea91c9504e9", "Dismac", "", "Pega Ladrao (Dismac)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "17c0a63f9a680e7a61beba81692d9297", "U.S. Games Corporation - Western Technologies, Tom Sloper", "VC2004", "Picnic (1983) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 45", "", "", "", "", "" }, { "17d000a2882f9fdaa8b4a391ad367f00", "Atari - GCC", "CX2676", "Centipede (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "17ee158d15e4a34f57a837bc1ce2b0ce", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691, CX2691P", "Joust (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "17ee23e5da931be82f733917adcb6386", "Salu, Dennis M. Kiss", "460758", "Acid Drop (1992) (Salu) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "50", "256", "", "" }, { "1802cc46b879b229272501998c5de04f", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (1983) (Atari)", "Uses Kids/Keypad Controllers", "Rare", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "183020a80848e06a1238a1ab74079d52", "Thomas Jentzsch", "", "Missile Command (Amiga Mouse) (2002) (TJ) (PAL)", "Uses Amiga Mouse Controller", "Homebrew", "", "", "", "", "", "", "AMIGAMOUSE", "", "", "", "", "", "", "YES", "" }, { "1862fca4f98e66f363308b859b5863af", "Atari", "", "128-in-1 Junior Console (Chip 1 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18760f1f9ca5e18610115cf7b815b824", "", "", "Star Fire (23-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18a970bea7ac4d29707c8d5cd559d03a", "", "", "Bridge (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18b28b386abdadb3a700ac8fb68e639a", "Manuel Polik", "", "Gunfight 2600 (MP) (PAL)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18bebbbd41c234f82b1717b1905e6027", "", "", "Space Instigators (Public Release) (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18d26111cef66dff0c8af8cf0e117843", "", "", "Tunnel Demo (Cycling Colours 2) (29-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18dc28bc22402f21e1c9b81344b3b8c5", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "18ed63e3ce5bc3dd2d8bd188b807f1a2", "", "", "Stell-A-Sketch (Bob Colbert) (PD) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "18f299edb5ba709a64c80c8c9cec24f2", "Home Vision - Gem International Corp. - VDI", "VCS83111", "Asteroid Fire (1983) (Home Vision) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "19098c46da0640f2b5763167dea6c716", "Andrew Wallace", "", "Laseresal 2002 (NTSC) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "191449e40b0c56411c70772706f79224", "", "", "Multi-Color Demo 2 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "19162393786098d50587827588198a86", "Jone Yuan Telephonic Enterprise Co", "", "Flag Capture (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "191ac4eec767358ee3ec3756c120423a", "", "", "Checkers (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "192aa2e8c795c9e10a7913e5d41feb81", "Atari - GCC, Jaques Hugon, Seth Lipkin", "CX26125", "Los Angeles 1984 Games (1984) (Atari) (Prototype) (PAL)", "AKA Track and Field (Uses Track & Field Controller)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "193f060553ba0a2a2676f91d9ec0c555", "Atari, Carol Shaw", "CX2636, CX2636P", "Video Checkers (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "199985cae1c0123ab1aef921daace8be", "", "", "Euchre (Release Candidate 2) (PAL) (01-10-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "199eb0b8dce1408f3f7d46411b715ca9", "Parker Brothers, David Lamkins, Laura Nikolich", "PB5900", "Spider-Man (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "19a9d3f9fa1b1358fb53009444247aaf", "", "", "Blackjack (Unknown) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "56", "", "", "" }, { "19abaf2144b6a7b281c4112cff154904", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "19d6956ff17a959c48fcd8f4706a848d", "PlayAround - J.H.M.", "202", "Burning Desire (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "19d9b5f8428947eae6f8e97c7f33bf44", "", "", "Fortress (Dual Version) (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "19e739c2764a5ab9ed08f9095aa2af0b", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "19e761e53e5ec8e9f2fceea62715ca06", "Panda", "104", "Scuba Diver (1983) (Panda)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1a23540d91f87584a04f184304a00648", "", "", "Race Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1a613ce60fc834d4970e1e674b9196b3", "Home Vision - Gem International Corp. - VDI", "VCS83135", "Tanks War (1983) (Home Vision) (PAL)", "AKA Tanks But No Tanks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1a624e236526c4c8f31175e9c89b2a22", "Rainbow Vision - Suntek", "SS-007", "Space Raid (Rainbow Vision) (PAL) [a]", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1a8204a2bcd793f539168773d9ad6230", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari) [no initials]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1aa7344b563c597eecfbfcf8e7093c27", "David Marli", "", "Slot Invaders (David Marli) (Hack)", "Hack of Slot Machine", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b0f3d7af668eeea38ddd6182d8f48fb", "Jone Yuan Telephonic Enterprise Co", "", "Cosmic Swarm (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "YES", "" }, { "1b1daaa9aa5cded3d633bfcbeb06479c", "", "", "Ship Demo (V 1502) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b22a3d79ddd79335b69c94dd9b3e44e", "Tron", "", "Moon Patrol (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b4b06c2a14ed3ee73b7d0fd61b6aaf5", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b8c3c0bfb815b2a1010bba95998b66e", "Telegames", "", "Frogs and Flies (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1b8d35d93697450ea26ebf7ff17bd4d1", "Quelle - Otto Versand", "176.764 9 - 781644", "Marineflieger (1983) (Quelle) (PAL)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1bb91bae919ddbd655fa25c54ea6f532", "Suntek", "SS-026", "Treasure Island (Suntek) (PAL)", "AKA Treasure Discovery", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1bc2427ac9b032a52fe527c7b26ce22c", "Intellivision Productions - M Network - APh Technological Consulting, Bruce Pedersen, Larry Zwick", "MT5860", "Sea Battle (1983) (M Network)", "High Seas", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1bef389e3dd2d4ca4f2f60d42c932509", "Dimax - Sinmax", "SM8001", "Space Robot (1983) (Dimax - Sinmax) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1bf503c724001b09be79c515ecfcbd03", "", "", "Bumper Bash (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "54", "", "", "" }, { "1c3f3133a3e5b023c77ecba94fd65995", "CCE", "C-830", "Planet Patrol (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c5796d277d9e4df3f6648f7012884c4", "Quelle", "715.853 5", "Wachroboter jagt Jupy (Quelle) (PAL)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c6eb740d3c485766cade566abab8208", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c85c0fc480bbd69dc301591b6ecb422", "CCE", "", "Super Box (CCE)", "AKA RealSports Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1c8c42d1aee5010b30e7f1992d69216e", "PlayAround - J.H.M.", "205", "Gigolo (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1cad3b56cc0e6e858554e46d08952861", "Jone Yuan Telephonic Enterprise Co", "", "Chopper Command (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1cafa9f3f9a2fce4af6e4b85a2bbd254", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (1982) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "1cca2197d95c5a41f2add49a13738055", "Atari, Larry Kaplan - Sears", "CX2664 - 6-99818", "Brain Games (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "1cf59fc7b11cdbcefe931e41641772f6", "Sega", "005-01", "Buck Rogers - Planet of Zoom (1983) (Sega)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1d1d2603ec139867c1d1f5ddf83093f1", "Atari, Larry Kaplan - Sears", "CX2602 - 99802, 6-99802, 49-75102", "Air-Sea Battle (1977) (Atari) (4K)", "AKA Target Fun (Anti-Aircraft)", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1d284d6a3f850bafb25635a12b316f3d", "CCE", "", "H.E.R.O. (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1d2a28eb8c95da0d6d6b18294211839f", "", "", "Fishing Derby (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1d4e0a034ad1275bc4d75165ae236105", "20th Century Fox Video Games, Mark Klein", "11034", "Pick Up (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1d5eac85e67b8cff1377c8dba1136929", "", "", "Chronocolor Donkey Kong Sideways (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1d6ed6fe9dfbde32708e8353548cbb80", "Jone Yuan Telephonic Enterprise Co", "", "Super Challenge Baseball (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1da2da7974d2ca73a823523f82f517b3", "Spectravision - Spectravideo - Sirius Software, David Lubar", "SA-206", "Challenge of.... Nexar, The (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1db3bc4601f22cf43be7ce015d74f59a", "", "", "Ship Demo (V 10) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1e060a8025512ad2127e3da11e212ccc", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (3 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "1e0ef01e330e5b91387f75f700ccaf8f", "Quelle - Otto Versand", "686.561 2 - 781627", "Mein Weg (1983) (Quelle) (PAL)", "AKA Challenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1e1290ea102e12d7ac52820961457e2b", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-15-1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1e1817d9cbcc3ba75043b7db4e6c228f", "", "", "Star Fire (07-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1e272d09c0e55f5ef14fcb76a735f6d7", "Atari, David Crane", "CX26163P", "Slot Machine (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1e587ca91518a47753a28217cd4fd586", "Telesys, Jim Rupp, Jack Woodman", "1001", "Coco Nuts (1982) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1e750000af77cc76232f4d040f4ab060", "Jone Yuan Telephonic Enterprise Co", "", "Raft Rider (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1e85f8bccb4b866d4daa9fcf89306474", "Atari, Lou Harp", "CX26122", "Sinistar (02-13-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1e89f722494608d6ea15a00d99f81337", "", "", "River Raid (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC50", "", "", "", "" }, { "1ea1abcd2d3d3d628f59a99a9d41b13b", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1ea980574416bfd504f62575ba524005", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675", "Ms. Pac-Man (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1ec57bbd27bdbd08b60c391c4895c1cf", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (09-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1ec5bef77b91e59313cba205f15b06d7", "", "", "Overhead Adventure Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "60", "", "", "" }, { "1ede4f365ce1386d58f121b15a775e24", "Parker Brothers, Dave Hampton, Tom Sloper", "931517", "Q-bert (1983) (Parker Bros) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1ee2cfc7d0333b96bd11f7f3ec8ce8bc", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (4 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1ee9c1ba95cef2cf987d63f176c54ac3", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675, CX2675P", "Ms. Pac-Man (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1ef04e7e508296a8d9eb61cc7dae2e5d", "SOLID Corp. (D. Scott Williamson)", "CX2655-069", "Star Castle 2600 (SolidCorp) [069]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "1f21666b8f78b65051b7a609f1d48608", "K-Tel Vision", "", "Vulture Attack (1982) (K-Tel Vision)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1f2ae0c70a04c980c838c2cdc412cf45", "Atari - GCC", "CX2698", "Rubik's Cube (1984) (Atari)", "AKA Atari Video Cube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1f349dd41c3f93c4214e5e308dccb056", "", "", "Virtual Pet Demo 2 (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1f40eefc7447336ae6cd8ffa5eb325be", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) (4K) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1f562b89d081e36d58e6fc943512ec05", "", "", "Hangman Man Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1f5a2927a0b2faf87540b01d9d7d7fd1", "Pet Boat", "", "Tennis (Pet Boat) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1f60e48ad98b659a05ce0c1a8e999ad9", "", "", "Mondo Pong V2 (Piero Cavina) (PD)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "01", "", "", "", "", "" }, { "1f773a94d919b2a3c647172bbb97f6b4", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (07-11-1983) (Atari) (Prototype) (PAL)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1fa58679d4a39052bd9db059e8cda4ad", "Imagic, Dan Oliver", "720118-1A, 03208", "Laser Gates (1983) (Imagic)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1fa7a42c2c7d6b7a0c6a05d38c7508f4", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-04-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "1fa86282403fa35d103ab88a9d603c31", "SpiceWare - Darrell Spice Jr.", "", "Stay Frosty (SpiceWare) (PAL60)", "Part of Stella's Stocking 2007 Xmas compilation", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "YES", "" }, { "1fab68fd67fe5a86b2c0a9227a59bb95", "20th Century Fox Video Games - Videa, Lee Actor", "", "Lasercade (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "200309c8fba0f248c13751ed4fc69bab", "Jeffry Johnston", "", "Radial Pong - Version 1 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2008c76deba5953201ef75a09b2ff7dc", "", "", "Fortress (21-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "200a9d2a7cb4441ce4f002df6aa47e38", "", "", "Doomzerk (PD) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2016726db38ad6a68b4c48ba6fe51557", "Piero Cavina, Erik Mooney", "", "INV 2 (Piero Cavina, Erik Mooney)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "203049f4d8290bb4521cc4402415e737", "Tigervision, Robert H. O'Neil - Teldec", "7-007 - 3.60005 VG", "Polaris (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "203abb713c00b0884206dcc656caa48f", "Imagic, Bob Smith", "720114-1A, 03207, IZ-001-04", "Moonsweeper (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "203b1efc6101d4b9d83bb6cc1c71f67f", "Quelle", "685.996 1", "Teller-Jonglieren! (1983) (Quelle) (PAL)", "AKA Dishaster", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "205070b6a0d454961dd9196a8e81d877", "", "", "Hangman Monkey Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2091af29b4e7b86914d79d9aaa4cbd20", "CBS Electronics - Woodside Design Associates, Harley H. Puthuff Jr.", "4L1802", "Donkey Kong Junior (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "251", "", "" }, { "20ae62fb69c6cc6e8098cca8cd080487", "Zirok", "", "Tennis (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "20d4457ba22517253fcb62967af11b37", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "20dca534b997bf607d658e77fbb3c0ee", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1002", "Fire Fly (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "20edcc3aa6c189259fa7e2f044a99c49", "Spectravision - Spectravideo", "SA-201", "Gangster Alley (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "211774f4c5739042618be8ff67351177", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "211f76dff0b7dad3f6fcac9d938ee61a", "JSK", "", "Custer's Viagra (JSK) (Hack) [a]", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "211fbbdbbca1102dc5b43dc8157c09b3", "Apollo", "AP-2009", "Final Approach (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2124cf92978c46684b6c39ccc2e33713", "", "", "Sea Monster (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "21299c8c3ac1d54f8289d88702a738fd", "K-Tel Vision", "", "Spider Maze (1982) (K-Tel Vision)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "212d0b200ed8b45d8795ad899734d7d7", "Atari, Richard Maurer, Christopher H. Omarzu - Coca Cola", "", "Pepsi Invaders (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "213e5e82ecb42af237cfed8612c128ac", "Sancho - Tang's Electronic Co.", "TEC006", "Forest (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "YES", "" }, { "2162266b906c939b35c84ff9a0f50ad1", "Atari, Larry Kaplan", "CX2664, CX2664P", "Brain Games (1978) (Atari) (PAL) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "2179dfd7edee76efafe698c1bc763735", "", "", "Yellow Submarine (Cody Pittman) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "218b76f5a4142dc2ea9051a768583d70", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2684, CX2684P", "Galaxian (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "218c0fe53dfaaa37f3c823f66eafd3fc", "Atari, Alan Miller", "CX2624, CX2624P", "Basketball (1978) (Atari) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "21a96301bb0df27fde2e7eefa49e0397", "Data Age", "DA1003", "Sssnake (1982) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "21b09c40295c2d7074a83ae040f22edf", "", "", "Marble Craze (V0.90) (Easy Version) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "21d2c435bcccde7792d82844b3cf60f4", "Atari - GCC, Doug Macrae", "CX2677, CX2677P", "Dig Dug (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "21d7334e406c2407e69dbddd7cec3583", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2228c67d25e507603d4873d3934f0757", "", "", "Fu Kung! (V0.10) (28-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "22319be7a640af5314ec3c482cceb676", "", "", "Joustpong (05-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2240655247d6de1c585564004a853ab7", "", "", "Fu Kung! (V0.17) (07-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "225522777dc7155627808bde0c1d0ef0", "", "", "This Planet Sucks Demo 1 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "22675cacd9b71dea21800cbf8597f000", "Atari, David Crane", "CX2605, CX2605P", "Outlaw (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "227532d82505c3c185a878273c285d5f", "", "", "Hangman Man Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "22abbdcb094d014388d529352abe9b4b", "Apollo", "AP-2012", "Squoosh (1983) (Apollo) (Prototype) [a]", "AKA Vat's Incredible!, The Grape Escape", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "22b22c4ce240303012e8a9596ae8d189", "", "", "Skeleton+ (03-05-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "22f6b40fc82110d68e50a1208ae0bb97", "", "", "Purple Bar Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2319922df4d0c820b3e5f15faa870cc3", "Atari - GCC, Mike Feinstein", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2327456f86d7e0deda94758c518d05b3", "Digitel", "", "Mr. Postman (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2351d26d0bfdee3095bec9c05cbcf7b0", "", "", "Warring Worms (19-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2353725ec98e0f0073462109e886efd7", "Champ Games", "CG-03-P", "Scramble (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "YES", "" }, { "235436ab0832370e73677c9c6f0c8b06", "", "", "Beast Invaders (Double Shot) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2365e1534d67f94d8670394ab99150ce", "Thomas Jentzsch", "", "Missile Command (Atari Mouse) (2002) (TJ)", "Uses Atari ST Mouse Controller", "Homebrew", "", "", "", "", "", "", "ATARIMOUSE", "", "", "", "", "", "", "YES", "" }, { "23d445ea19a18fb78d5035878d9fb649", "CBS Electronics - JWDA, Sylvia Day, Todd Marshall, Henry Will IV", "4L1818, 4L1819, 4L1820, 4L1821", "Mouse Trap (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "23e4ca038aba11982e1694559f3be10f", "", "", "Big Dig (V3) (20-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "23fad5a125bcd4463701c8ad8a0043a9", "CCE", "C-840", "Stone Age (1983) (CCE)", "Uses the Joystick Controllers (swapped)", "", "", "", "A", "A", "", "YES", "", "", "", "", "", "", "220", "YES", "" }, { "240bfbac5163af4df5ae713985386f92", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2432f33fd278dea5fe6ae94073627fcc", "CBS Electronics, Tom DiDomenico", "4L2477, 4L2482, 4L2485, 4L4171", "Blueprint (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "24385ba7f5109fbe76aadc0a375de573", "CCE", "", "Xevious (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2447e17a4e18e6b609de498fe4ab52ba", "CCE", "", "Super Futebol (CCE)", "AKA RealSports Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "244c6de27faff527886fc7699a41c3be", "", "", "Matt Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2450dfa1df70d12b60683185775efed8", "Jeffry Johnston", "", "Radial Pong - Version 7 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "24544ee5d76f579992d9522e9b238955", "Carrere Video - Western Technologies, Tom Sloper - Teldec - Prism", "USC2004", "Picnic (1983) (Carrere Video) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 45", "", "", "", "", "" }, { "245f07c8603077a0caf5f83ee6cf8b43", "Home Vision - Thomas Jentzsch", "", "Parachute (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "240", "", "" }, { "24759be31e8fe55d2829fd86bdf3181f", "Hozer Video Games", "", "Gunfight 2600 - Worst Nightmare... (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "247fa1a29ad90e64069ee13d96fea6d6", "CCE", "C-867", "Radar (1983) (CCE)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2496d404bfc561a40a80bea6a69695c3", "CCE", "C-1007", "Jungle Hunt (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "24ad538291eb5f5cac4b9998f3b851c3", "", "", "Gunfight 2600 - This time it's your decission! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "24aff972d58990f9b88a6d787c796f1e", "CBS Electronics", "4L1767, 4L1768, 4L1769, 4L1770", "Smurf (1982) (CBS Electronics) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "24b5f4bbdb853eca38ea0cae2dfe73a1", "", "", "Home Run (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "24b9adac1b4f85b0bac9bf9b9e180906", "Angelino", "", "Space 2002 (Angelino) (Hack)", "Hack of Space Jockey", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "24d018c4a6de7e5bd19a36f2b879b335", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "24d9a55d8f0633e886a1b33ee1e0e797", "Thomas Jentzsch", "", "Dragon Defender (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "15", "240", "YES", "" }, { "24df052902aa9de21c2b2525eb84a255", "Imagic, Dennis Koble", "720000-100, 720100-1B, IA3000, IA3000C", "Trick Shot (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "24fbf8250a71611e40ef18552e61b009", "", "", "Movable Grid Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2516f4f4b811ede4ecf6fbeb5d54a299", "Quelle", "701.134 9", "Schiessbude (1983) (Quelle) (PAL)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2517827950fee41a3b9de60275c8aa6a", "Atari", "CX26163P", "Fishing (32 in 1) (1988) (Atari) (PAL)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25265d0e7f88b3026003809f25ee025e", "Atari - GCC, Ava-Robin Cohen", "CX26123", "Jr. Pac-Man (1984) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25472dfdeef6a42581a231d631d6b04d", "", "", "Gunfight 2600 - Design thoughts (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25710bde8fa181b0c5cf0846b983bec1", "", "", "Demo Image Series #15 - Three Marios (NTSC) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "257bc3b72a6b5db3fd0d47619125b387", "CBS Electronics", "4L 2737 0000", "Omega Race (1983) (CBS Electronics) [a]", "Set right difficulty to 'A' for BoosterGrip in both ports", "", "", "", "", "", "", "", "BOOSTERGRIP", "BOOSTERGRIP", "", "", "", "", "", "", "" }, { "25a21c47afe925a3ca0806876a2b4f3f", "Quelle", "685.640 5", "Der kleine Baer (1983) (Quelle) (PAL)", "AKA Frostbite", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25b52bf8dd215bcbd59c9abdb55c44f8", "Atari - GCC, Betty Ryan Tylko, Doug Macrae", "CX2694, CX2694P", "Pole Position (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25b6dc012cdba63704ea9535c6987beb", "Avalon Hill, Jean Baer, Bill Hood", "5004002", "Shuttle Orbiter (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25bb080457351be724aac8a02021aa92", "CBS Electronics", "4L1784, 4L1786, 4L1787, 4L2277", "Zaxxon (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25d4be3309b89583c6b39d9f93bf654f", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25e73efb9a6edf119114718bd2f646ba", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (1983) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "25f2e760cd7f56b88aac88d63757d41b", "Activision, Bob Whitehead - Ariola", "EAG-002, EAG-002-04I, PAG-002 - 711 002-715", "Boxing (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "25f879ff678130fea615ac418e7943f1", "Activision, Garry Kitchen", "EAX-025", "Keystone Kapers (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "SECAM", "", "", "", "" }, { "25f9cf703575c5d63048c222f5463758", "", "", "Multi-Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "260c787e8925bf3649c8aeae5b97dcc0", "Thomas Jentzsch", "", "Hell Driver (Thomas Jentzsch)", "NTSC Conversion, joystick ports swapped", "Homebrew", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "262ccb882ff617d9b4b51f24aee02cbe", "Atari, Douglas Neubauer", "CX26154, CX26154P", "Super Football (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "265a85f66544eaf95fda06c3d9e48abf", "", "", "Tunnel Demo (Cycling Colours) (29-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "265c74a956500bd31efd24adc6d5ccf6", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2683d29a282dd059535ac3bb250f540d", "", "", "Space Treat (12-01-2003) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "268f46038e29301568fa9e443e16e960", "Atarius Maximum", "", "Pitfall Unlimited (Atarius Maximus) (Hack)", "Hack of Pitfall", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "26bc2bdf447a17376aea7ef187ff6e44", "", "", "Amanda Invaders (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "26f4f8b098609164effef7809e0121e1", "", "", "Oystron (V2.7) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "270229c6d5578446e6a588492e4e5910", "", "", "Space Invaders 2 (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "271bfd5dc2673d382019f1fb6cab9332", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (Preview) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "273ce50db5a0d6da7ea827a54f44dee9", "", "", "Island Flyer Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "274d17ccd825ef9c728d68394b4569d2", "Playaround - J.H.M.", "202", "Bachelorette Party (1982) (Playaround)", "AKA Bachelor Party, Uses the paddle controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "AUTO 65", "", "22", "222", "YES", "" }, { "277c7281ac945b8331e2e6fcad560c11", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (2 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "277cca62014fceebb46c549bac25a2e3", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "277fa4b9a6bb7a8dcea2c5f38a4c25f0", "Atari, Alan J. Murphy, Robert Zdybel", "CX2668", "RealSports Football (1982) (Atari) (Prototype)", "AKA Football II", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "278155fc9956e9b6ef2359eb238f7c7f", "", "", "Donkey Kong Junior (Unknown) (Hack)", "Hack of Donkey Kong Junior", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2783006ee6519f15cbc96adae031c9a9", "Telegames", "", "Night Stalker (1989) (Telegames) (PAL) [a]", "AKA Dark Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "278531cc31915747018d22145823d2c9", "", "", "Defender MegaDrive (PAL) (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "278f14887d601b5e5b620f1870bc09f6", "Thomas Jentzsch", "", "SWOOPS! (v0.96) (TJ)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "PADDLES", "", "", "", "28", "", "", "" }, { "27c4c2af4b46394bb98638af8e0f6e9d", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "27c6a2ca16ad7d814626ceea62fa8fb4", "Parker Brothers, Mark Lesser", "PB5590", "Frogger II (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "27f9e2e1b92af9dc17c6155605c38e49", "CCE", "", "Nightmare (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2808dc745ff4321dc5c8122abef6711f", "Retroactive", "", "Qb (2.11) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "28148a52b1955ce12c7a74d3a3e620a4", "CCE", "", "Freeway (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "281ff9bd0470643853de5cbd6d9e17f5", "Eckhard Stolberg", "", "Cubis (EM) (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2823364702595feea24a3fbee138a243", "Bit Corporation", "PG206", "Bobby Is Going Home (1983) (BitCorp) (PAL)", "AKA Bobby geht Heim", "Rare", "", "", "", "", "", "", "", "", "", "", "", "42", "", "", "" }, { "2825f4d068feba6973e61c84649489fe", "", "", "Boom Bang (Unknown) (PAL)", "AKA Crackpots", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "282a77841cb3d33af5b56151acba770e", "Otto Versand", "311388", "Black Hole (1983) (Otto Versand) (PAL)", "AKA Cosmic Ark (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "283dee88f295834c4c077d788f151125", "Retroactive", "", "Qb (2.11) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "284ca61b2407bdba3938048b0a559015", "Atari, Tod Frye", "CX2695", "Xevious (05-25-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2854e5dfb84173fafc5bf485c3e69d5a", "Canal 3 - Intellivision", "C 3004", "Moon Patrol (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2880c6b59bd54b153174676e465167c7", "Tron", "", "Donkey Kong Jr. (Tron)", "AKA Donkey Kong Junior", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "28a2bea8f84936cb2e063f857414cda0", "Thiago Paiva", "", "Mega Mania Raid (1999) (Thiago Paiva) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "28a4cd87fb9de4ee91693a38611cb53c", "", "", "Skeleton (V1.1) (NTSC) (24-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "28d5df3ed036ed63d33a31d0d8b85c47", "Bit Corporation", "PG204", "Open, Sesame! (1983) (BitCorp) (PAL) [a]", "AKA I Want My Mommy", "", "", "", "", "", "", "", "", "", "", "", "", "38", "256", "YES", "" }, { "2903896d88a341511586d69fcfc20f7d", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "291bcdb05f2b37cdf9452d2bf08e0321", "Atari", "CX26163P", "32 in 1 Game Cartridge (1988) (Atari) (Prototype) (PAL)", "", "Prototype", "", "32IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "291cc37604bc899e8e065c30153fc4b9", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "291dd47588b9158beebe4accc3a093a6", "Atari", "", "32 in 1 Console ROM (02-10-1989) (Atari) (Prototype) (PAL)", "", "Prototype", "", "32IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "292a0bb975b2587f9ac784c960e1b453", "", "", "Qb (05-02-2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "292f2446a0325b7b423e88a2ebfeb5a0", "", "", "Cube Conquest (Non Interlaced) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "29396db58406084e416032c372734a3e", "", "", "Gunfight 2600 - Fixed Beta Release! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2942680c47beb9bf713a910706ffabfe", "", "", "Blue Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "294762000e853b4319f9991c1ced5dfc", "", "", "T.F. Space Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "295f3679bdf91ca5e37da3f787b29997", "", "", "Exorcise (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "29630a20d356fb58685b150bfa8f00c3", "M Network, Kevin Miller", "MT5687", "International Soccer (1982) (Mattel) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "297236cb9156be35679f83c4e38ee169", "Exus Corporation", "", "Video Reflex (1983) (Exus) [no roman numbers]", "AKA Foot Craz (no roman numbers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "297c405afd01f3ac48cdb67b00d273fe", "Atari - GCC, Ava-Robin Cohen", "CX26123, CX26123P", "Jr. Pac-Man (1986) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2982e655dffc89d218a0a3072cfc6811", "", "", "Mini Golf 812631 (Hack)", "Hack of Miniature Golf", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "298387b0637173d2002770a649b4fbca", "", "", "S.I.PLIX 2 (Hack) [a]", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "29843f43b81f3736bf35c00b1bb88fb2", "Gray Games & AtariAge", "", "E.T. Book Cart (NTSC)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "", "15", "240", "YES", "55" }, { "29949f893ef6cb9e8ecb368b9e99eee4", "Erik Eid", "", "Euchre (Alpha) (NTSC) (31-08-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "29dfa26b7988af9984d617708e4fc6e2", "", "", "Boulderdash Demo (05-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2a0ba55e56e7a596146fa729acf0e109", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2a10053fd08664c7cfbbb104386ed77f", "", "", "Alpha Demo - The Beta Demo (2000) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2a1b454a5c3832b0240111e7fd73de8a", "Tigervision, Bill Hogue", "7-011", "Miner 2049er Volume II (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2a2f46b3f4000495239cbdad70f17c59", "CommaVid, John Bronstein - Ariola", "CM-003 - 712 003-720", "Cosmic Swarm (1982) (CommaVid) (PAL)", "AKA Angriff der Termiten", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2a33e21447bf9e13dcfed85077ff6b40", "", "", "Backwards Cannonball v2 (Hack)", "Hack of Human Cannonball", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2a360bc85bf22de438651cf92ffda1de", "Bit Corporation", "PGP213", "Spy Vs. Spy (4 Game in One) (1983) (BitCorp) (PAL)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2a9f9001540c55a302befd8e9d54b47b", "Atari, Dan Hitchens", "CX2697, CX2697P", "Mario Bros. (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2aa5e56d36c2e58b6f2856109f2099a9", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2aba6a1b01a5859e96d6a66d2286772f", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2abc3d46b3f2140160759e2e10bc86d9", "", "", "Gunfight 2600 - Beta Release! (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2ac3a08cfbf1942ba169c3e9e6c47e09", "Activision, Dan Kitchen", "EAK-046-04B", "Fighter Pilot (1988) (Activision) (PAL)", "AKA Tomcat - The F-14 Fighter Simulator", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2ae700c9dba843a68dfdca40d7d86bd6", "TechnoVision - Thomas Jentzsch", "", "Pharaoh's Curse (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "40", "240", "YES", "" }, { "2aeedcc6eb1602efb77161b0cef832ab", "SOLID Corp. (D. Scott Williamson)", "CX2655-025", "Star Castle 2600 (SolidCorp) [025]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2b1589c7e1f394ae6a1c046944f06688", "Carrere Video - JWDA, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV - Teldec - Prism", "USC2003", "Eggomania (1983) (Carrere Video) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 60", "", "", "", "", "" }, { "2b27eb194e13f3b38d23c879cc1e3abf", "Quelle", "402.272 9", "Super-Ferrari (1983) (Quelle) (PAL)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2b42da79a682ed6e2d735facbf70107e", "", "", "DKjr Improved (Hack)", "Hack of Donkey Kong Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2b430c00dc79e495762ac59b2f9b4fcd", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2b71a59a53be5883399917bf582b7772", "Greg Troutman", "", "Dark Mage (final beta) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2ba02f509a4991aa176ba8d9e540df3d", "Atari, Mark R. Hahn", "CX2678", "Dukes of Hazzard (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2bb0a1f1dee5226de648eb5f1c97f067", "Robby", "", "Enduro (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2bb9f4686f7e08c5fcc69ec1a1c66fe7", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2bc26619e31710a9884c110d8430c1da", "Atari, Bob Whitehead", "CX2652, CX2652P", "Casino (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "" }, { "2bc6c53b19e0097a242f22375a6a60ff", "", "", "Droid Demo 2 (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2bee7f226d506c217163bad4ab1768c0", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2bf34b6ad7d2317a2d0808b3fb93571b", "", "", "Easy Playfield Graphics (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c0dc885d5ede94aa664bf3081add34e", "", "", "Earth Dies Screaming, The (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c29182edf0965a7f56fe0897d2f84ba", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (08-18-1990) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c2aea31b01c6126c1a43e10cacbfd58", "Paul Slocum", "", "Synthcart (2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "YES", "" }, { "2c3b2843295c9d6b16996971180a3fe9", "HES - Activision", "", "Sports Action Pak - Enduro, Ice Hockey, Fishing Derby, Dragster (1988) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c3b9c171e214e9e46bbaa12bdf8977e", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c45c3eb819a797237820a1816c532eb", "Atari", "CX26163P", "Boxing (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c8835aed7f52a0da9ade5226ee5aa75", "Arcadia Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2c8c11295d8613f875b7bcf5253ab9bb", "Fabrizio Zavagli", "", "Kool Aid Man (PAL Conversion) (16-11-2002) (Fabrizio Zavagli) (PAL60)", "PAL60 Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "2c9fadd510509cc7f28f1ccba931855f", "", "", "Hangman Invader Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2ca6445204ffb7686ddee3e33ba64d5b", "Alex Herbert", "", "AtariVox Test ROM", "Uses the AtariVox controller", "", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "", "" }, { "2cb42cf62b2f25f59f909b5447821b14", "Atari, Christopher H. Omarzu - Children's Computer Workshop", "CX26104", "Big Bird's Egg Catch (1983) (Atari) (PAL) [a]", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "2cccc079c15e9af94246f867ffc7e9bf", "PlayAround - J.H.M.", "203", "Jungle Fever (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2cefa695df2ed020899a7df7bb1e3a95", "Manuel Polik, Fabrizio Zavagli", "", "A-Team (2002) (Manuel Polik) (Hack)", "Hack of A-Team", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2cf20f82abcae2decff88db99331e071", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2cfb188c1091cc7ec2a7e60064d2a758", "", "", "Space Invaders Hack Demo (2003) (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d15b092e8350912ec4b2e5e750fa1c6", "Wizard Video Games, Bob Davis, Robert H. O'Neil", "", "Texas Chainsaw Massacre, The (1982) (Wizard Video Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d16a8b59a225ea551667be45f554652", "Quelle", "802.744 3", "Der Geheimkurier (1983) (Quelle) (PAL)", "AKA Mr. Postman", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d1cf85fbc732856bf76470cd4060f4a", "", "", "Daredevil (V1) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "216", "", "" }, { "2d2c5f0761e609e3c5228766f446f7f8", "Atari - Axlon, Steve DeFrisco", "CX26170, CX26170P", "Secret Quest (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d405da70af82b20a6b3ecc3d1d2c4ec", "Genus", "", "Pitfall (Genus)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d6741cda3000230f6bbdd5e31941c01", "CBS Electronics - VSS", "80110", "Targ (1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d69a5f23784f1c2230143292a073b53", "", "", "Qb (Fixed background animation) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2d6da0eb85eabc93270e5bb8a466ca51", "", "", "Sprite Demo 7 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d76c5d1aad506442b9e9fb67765e051", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo", "AP-2004", "Lost Luggage (1982) (Apollo) [no opening scene]", "AKA Airport Mayhem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d9e5d8d083b6367eda880e80dfdfaeb", "QDI, Mike Montana, Rich Montana - Selchow & Righter", "87", "Glib (1983) (QDI)", "AKA Video Word Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2d9e65959808a6098c16c82a59c9d9dc", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2dbc92688f9ba92a7e086d62be9df79d", "", "", "How to Draw a Playfield (1997) (Jim Crawford) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2dbdca3058035d2b40c734dcf06a86d9", "Thomas Jentzsch", "", "Asteroids DC+ (Thomas Jentzsch) (Hack)", "Uses the Joystick (left) or Steering (right) Controller", "Hack", "", "", "", "", "", "", "", "DRIVING", "", "58", "", "", "", "YES", "" }, { "2dcf9ce486393cd36ca0928cd53b96cb", "Atari - GCC, Mike Feinstein, John Allred", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2de41a11c6767e54a5ee9ebaffec72af", "Gray Games & AtariAge", "", "E.T. Book Cart (PAL60)", "Charles F. Gray & Michael Rideout", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "15", "240", "YES", "55" }, { "2dfec1615c49501fefc02165c81955e6", "", "", "Song (05-11-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2e0aed5bb619edcefa3fafb4fbe7c551", "", "", "Qb (2.06) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2e2885e68fa1045871ce1382b68f6efc", "", "", "Star Fire - Return of the Crosshair (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2e2acef8513edcca991e7e5149412e11", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (16K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2e3728f3086dc3e71047ffd6b2d9f015", "Atari, David Crane", "CX26163P", "Outlaw (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2e5b184da8a27c4d362b5a81f0b4a68f", "Atari", "", "Rabbit Transit (08-29-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2e663eaa0d6b723b645e643750b942fd", "Atari, Tom Rudadahl - Sears", "CX2634 - 49-75121", "Golf (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2e7e9c6dcfcceaffc6fa73f0d08a402a", "CCE", "C-818", "Star Voyager (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2e82a1628ef6c735c0ab8fa92927e9b0", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2e842c2ee22e9dad9df16eed091315c4", "HES", "701-157", "2 Pak Special - Motocross, Boom Bang (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2eaf8fa9e9fdf1fcfc896926a4bdbf85", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur Version 39 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2ec6b045cfd7bc52d9cdfd1b1447d1e5", "Activision, David Crane - Ariola", "EAG-009, PAG-009 - 711 009-720", "Freeway (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2eda6a49a49fcb2b674ea9e160b6a617", "Kyle Pittman", "", "Rambo in Afghanistan (Kyle Pittman) (Hack)", "Hack of Riddle of the Sphinx", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2ef36341d1bf42e02c7ea2f71e024982", "", "", "Space Invaders (Explosion Hack)", "Hack of Space Invaders (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2f0546c4d238551c7d64d884b618100c", "Sega, Jeff Lorenz", "", "Ixion (1984) (Sega) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2f0a8bb4e18839f9b1dcaa2f5d02fd1d", "CCE", "", "Super Futebol (CCE) [a]", "AKA RealSports Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "2f11ba54609777e2c6a5da9b302c98e8", "Atari - GCC", "CX2676", "Centipede (1982) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2f16663b01591539624d0ef52934a17d", "M Network", "", "Rocky and Bullwinkle", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2f2f9061398a74c80420b99ddecf6448", "Rentacom - Brazil", "", "Bobby Is Going Home (Rentacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2f66ebf037321ed0442ac4b89ce22633", "Baroque Gaming (Brian Eno)", "", "Warring Worms (Beta 2) (2002) (Baroque Gaming)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2f7772879a1ed04f660aa9d77a86a4bd", "", "", "Yars' Revenge (Genesis)", "Genesis controller (C is zorlon cannon)", "Hack of Yars' Revenge", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "YES", "" }, { "2f77f015fc880b05f28e84156f989a0c", "", "", "Plane Demo (Gonzalo) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2f7949f71076db42480d3f5036b4a332", "", "", "Name This Game (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "2facd460a6828e0e476d3ac4b8c5f4f7", "Sancho - Tang's Electronic Co.", "", "Words-Attack (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3025bdc30b5aec9fb40668787f67d24c", "", "", "Demo Image Series #14 - Two Marios (4K Interleaved Chronocolour Vertical Movement) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "303242c239474f2d7763b843de58c1c3", "CCE", "", "Laser Blast (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "304512528a5530a9361e8a231ed9a6de", "Thomas Jentzsch", "", "River Raid Plus (Thomas Jentzsch) (Hack)", "Hack of River Raid", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "30512e0e83903fc05541d2f6a6a62654", "Atari, Jim Huether - Sears", "CX2644 - 6-99824", "Flag Capture (1978) (Atari)", "AKA Capture the Flag", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "30516cfbaa1bc3b5335ee53ad811f17a", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3051b6071cb26377cd428af155e1bfc4", "Atari, David Crane - Sears", "CX2607 - 6-99828, 49-75115", "Canyon Bomber (1979) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "10", "", "42", "", "", "" }, { "30685b9b6ebd9ba71536dd7632a1e3b6", "Dactari - Milmar", "", "Tennis (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3091af0ef1a61e801f4867783c21d45c", "CCE", "C-862", "Crackpots (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "30997031b668e37168d4d0e299ccc46f", "", "", "John K Harvey's Equalizer (PAL) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "30c92c685224dc7a72b9bbe5eb62d004", "", "", "Hangman Monkey Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "30e012e8d50330c8972f126b8e913bc4", "", "", "Indy 500 (Hack) [a2]", "Hack of Indy 500", "Hack", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "", "", "", "" }, { "30e0ab8be713208ae9a978b34e9e8e8c", "Atari, Mike Lorenzen", "CX2630, CX2630P", "Circus Atari (1980) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01 55", "", "", "", "", "" }, { "30f0b49661cfcfd4ec63395fab837dc3", "Sega, Jeff Lorenz - Teldec", "004-01", "Star Trek - Strategic Operations Simulator (1983) (Sega) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3105967f7222cc36a5ac6e5f6e89a0b4", "Sega, Jeff Lorenz", "011-01, 011-02", "Spy Hunter (1984) (Sega)", "Uses Joystick Coupler (Dual Control Module)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "310ba30e25ea8957e58180b663503c0c", "Ed Federmeyer", "", "Sound X6 (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "313243fc41e49ef6bd3aa9ebc0d372dd", "", "", "Fast Food (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "31512cdfadfd82bfb6f196e3b0fd83cd", "Tigervision", "7-004", "River Patrol (1984) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3177cc5c04c1a4080a927dfa4099482b", "Atari - Imagineering, Alex DeMeo", "CX26135", "RealSports Boxing (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "317a4cdbab090dcc996833d07cb40165", "Goliath - Hot Shot", "83-312", "Missile War (1983) (Goliath) (PAL)", "AKA Astrowar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "318046ae3711c05fd16e479b298e5fcc", "Retroactive", "", "Qb (V2.08) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "318a9d6dda791268df92d72679914ac3", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "319a142aab6260842ab616382848c204", "", "", "Marble Craze (05-02-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "31bb9b8ceed46cb3e506777a9e65f3ce", "Bit Corporation", "", "4 Game in One Light Green (1983) (BitCorp) (PAL)", "Phantom UFO, Ice Hockey, Cosmic Avenger, Spy Vs. Spy", "", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "31c5fd55a39db5ff30a0da065f86c140", "Dactari - Milmar", "", "Enduro (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "31d08cb465965f80d3541a57ec82c625", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "31df1c50c4351e144c9a378adb8c10ba", "Quelle", "687.463 0", "Die Ratte und die Karotten (1983) (Quelle) (PAL)", "AKA Gopher", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "31e518debba46df6226b535fa8bd2543", "Atari, Douglas 'Solaris' Neubauer, Mimi Nyden", "CX26134", "Last Starfighter (1984) (Atari) (Prototype)", "Solaris Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "31f4692ee2ca07a7ce1f7a6a1dab4ac9", "Atari, Alan Miller", "CX2642", "Game of Concentration (1980) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "31fcbce1cfa6ec9f5b6de318e1f57647", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (1983) (Atari) (Prototype) (PAL)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32199271dc980eb31a2cc96e10a9e244", "", "", "Radial Pong - Version 12 (Jeffry Johnston) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "321c3451129357af42a375d12afd4450", "Atari - Imagineering, Dan Kitchen", "CX26177", "Ikari Warriors (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32244e55ce6ec6bfbd763f33384bdc2e", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3225676f5c0c577aeccfaa7e6bedd765", "CCE", "C-1002", "Pole Position (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "322b29e84455aa41e7cc9af463bffa89", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (06-25-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "324cb4a749bcac4f3db9da842b85d2f7", "Dennis Debro", "", "Climber 5 (01-05-2003) (Dennis Debro)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "327468d6c19697e65ab702f06502c7ed", "Charles Morgan", "", "Aster-Hawk (2002) (Charles Morgan) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3276c777cbe97cdd2b4a63ffc16b7151", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691", "Joust (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3278158e5c1f7eb5c5d28ccfd7285250", "Dactari - Milmar", "", "Megamania (Dactari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "327fe8cf94f3a45c35a840a453df1235", "", "", "Spice Girls Rule Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "328949872e454181223a80389d03c122", "", "", "Home Run (Unknown) (PAL)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "32ae78abbb5e677e2aabae5cc86cec29", "Atari, Christopher H. Omarzu, Courtney Granner", "CX26112", "Good Luck, Charlie Brown (04-18-1984) (Atari) (Prototype)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32d1260ea682e1bb10850fa94c04ec5f", "Atari, Alan Miller", "CX26163P", "Basketball (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32dcd1b535f564ee38143a70a8146efe", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox)", "AKA Thundarr the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32e65d1e4dfcbcd9b57fee72cafe074c", "", "", "Eckhard Stolberg's Scrolling Text Demo 3 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32ecb5a652eb73d287e883eea751d99c", "Dactar - Milmar", "", "Bowling (Dactar - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "32f4e47a71601ab06cfb59e1c6a0b846", "Ed Federmeyer", "", "Sound X (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3316ee2f887e9cb9b54dd23c5b98c3e2", "", "", "Texas Golf (miniature Gold Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "331938989f0f33ca39c10af4c09ff640", "Zach Matley", "", "Combat - Tank AI (19-04-2003) (Zach Matley)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "332f01fd18e99c6584f61aa45ee7791e", "", "", "X'Mission (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3347a6dd59049b15a38394aa2dafa585", "Parker Brothers - JWDA, Henry Will IV", "PB5760", "Montezuma's Revenge (1984) (Parker Bros)", "Featuring Panama Joe", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "335793736cbf6fc99c9359ed2a32a49d", "", "", "Analog Clock (V0.0) (20-01-2003) (AD) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "335a7c5cfa6fee0f35f5824d1fa09aed", "Sega - Beck-Tech, Steve Beck, Phat Ho - Teldec", "006-01 - 3.60105 VG", "Congo Bongo (1983) (Sega) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3367eeba3269aa04720abe6169767502", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3391f7c4c656793f92299f4187e139f7", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a4]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "33cac5e767a534c95d292b04f439dc37", "Jone Yuan Telephonic Enterprise Co", "", "Tapeworm (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "33d68c3cd74e5bc4cf0df3716c5848bc", "CBS Electronics, Tom DiDomenico", "4L 2486 5000", "Blueprint (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "33ed6dfac4b9ea2f81f778ceddbb4a75", "Activision", "", "River Raid (1982) (SpkSoft) [t1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "340f546d59e72fb358c49ac2ca8482bb", "Sancho - Tang's Electronic Co.", "TEC003", "Skindiver (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "34340c8eecd1e557314789cc6477e650", "Joe Grand", "", "SCSIcide Pre-release 4 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "345488d3b014b684a181108f0ef823cb", "CBS Electronics, Tom DiDomenico", "4L 2486 5000", "Blueprint (1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "345758747b893e4c9bdde8877de47788", "CBS Electronics, Joseph Biel", "4L1802, 4L1803, 4L1804, 4L2278", "Venture (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "345769d085113d57937198262af52298", "Rainbow Vision - Suntek", "SS-007", "Space Raid (Rainbow Vision) (PAL)", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "346555779a2d51b48833463b5433472f", "", "", "Thrust (V0.1) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "348615ffa30fab3cec1441b5a76e9460", "Activision, Alan Miller - Ariola", "EAX-016, PAX-016 - 711 016-725", "StarMaster (1982) (Activision) (PAL) [fixed]", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "34b269387fa1aa5a396636f5ecdd63dd", "", "", "Marble Craze (mc7_23) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "34c808ad6577dbfa46169b73171585a3", "Apollo", "AP-2012", "Squoosh (1983) (Apollo) (Prototype)", "AKA Vat's Incredible!, The Grape Escape", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "34ca2fcbc8ba4a0b544acd94991cfb50", "Atari, Robert C. Polaro", "", "Dukes of Hazzard (1980) (Atari) (Prototype) (4K)", "AKA Stunt Cycle", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "34e37eaffc0d34e05e40ed883f848b40", "Retroactive", "", "Qb (2.15) (Retroactive) (Stella)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "34f4b1d809aa705ace6e46b13253fd3b", "Aaron Bergstrom", "", "Nothern Alliance (Aaron Bergstrom) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "34fd4fcb40ff5babce67f8b806d5969c", "", "", "Boxing (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "350e0f7b562ec5e457b3f5af013648db", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (06-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "35156407e54f67eb1f625450d5c093e1", "", "", "Mouse Trap (Genesis)", "Genesis controller (C changes to dog)", "Hack of Mouse Trap", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "35163b56f4a692a232ae96ad3e23310f", "Retroactive", "", "Qb (2.12) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3556e125681aea864e17b09f3f3b2a75", "", "", "Incoming (2 Player Demo) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3576037c9281656655fa114a835be553", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3577e19714921912685bb0e32ddf943c", "TechnoVision - Video Technology", "TVS1003", "Pharaoh's Curse (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "34", "", "YES", "" }, { "35ae903dff7389755ad4a07f2fb7400c", "", "", "Colored Wall Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "35b10a248a7e67493ec43aeb9743538c", "Dor-x", "", "Defender (Dor-x) (Hack)", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "35b43b54e83403bb3d71f519739a9549", "Parker Brothers, Dave Engman, Isabel Garret", "", "McDonald's (06-06-1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "35be55426c1fec32dfb503b4f0651572", "Men-A-Vision", "", "Air Raid (Men-A-Vision) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "35fa32256982774a4f134c3347882dff", "Retroactive", "", "Qb (V0.05) (Macintosh) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "360ba640f6810ec902b01a09cc8ab556", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (06-15-1983) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "360c0dcb11506e73bd0b77207c81bc62", "Digitel", "", "Enduro (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3619786f6a32efc1e4a262d5aca8a070", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3624e5568368929fabb55d7f9df1022e", "Activision - Imagineering, Dan Kitchen", "EAK-050-04", "Double Dragon (1989) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36306070f0c90a72461551a7a4f3a209", "U.S. Games Corporation - JWDA, Roger Booth, Sylvia Day, Ron Dubren, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV", "VC1007", "Name This Game (1983) (U.S. Games)", "AKA Octopussy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36547bc6faa5132b87504e18d088e1d7", "", "", "Cosmic Swarm (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "367411b78119299234772c08df10e134", "Atari", "CX26163P", "Skiing (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3685060707df27d4091ba0ea2dc4b059", "", "", "PezZerk - PezMan in Ghost Manor (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "368d88a6c071caba60b4f778615aae94", "Atari, Matthew L. Hubbard", "CX26159", "Double Dunk (1989) (Atari)", "AKA Super Basketball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36a701c60a9f9768d057bc2a83526a80", "", "", "Cube Conquest (Interlaced) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "36b20c427975760cb9cf4a47e41369e4", "Atari", "CX26143", "Donkey Kong (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36c29ceee2c151b23a1ad7aa04bd529d", "Atari - GCC, Ava-Robin Cohen", "CX26123", "Jr. Pac-Man (1986) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36c31bb5daeb103f488c66de67ac5075", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 56", "", "", "", "", "" }, { "36c993dc328933e4dd6374a8ffe224f4", "Gameworld, J. Ray Dettling", "133-007", "Bermuda Triangle (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36e47ed74968c365121eab60f48c6517", "Quelle", "343.373 7", "Master Builder (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36edef446ab4c2395666efc672b92ed0", "Atari - Axlon, John Vifian", "CX26168", "Off the Wall (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "36f9a953ebdd9a8be97ccf27a2041903", "", "", "Chinese Character Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "37252757a79dc5b174e3c03d6ea0bdcb", "", "", "Sky Diver (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "372bddf113d088bc572f94e98d8249f5", "Bomb - Onbase", "CA285", "Wall-Defender (1983) (Bomb) (PAL)", "AKA Wall Break", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "373b8a081acd98a895db0cb02df35673", "", "", "Demo Image Series #5 - Boofly (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3750f2375252b6a20e4628692e94e8b1", "Dismac", "", "Ases do Ar (Dismac)", "AKA Sky Jinks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "37527966823ee9243d34c7da8302774f", "", "", "Word Zapper (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "376944889dcfa96c73d3079f308e3d32", "Retroactive", "", "Qb (0.11) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3783f12821b88b08814da8adb1a9f220", "", "", "Mission Survive (PAL) (Genesis)", "Genesis controller (C is vertical fire)", "Hack of Mission Survive)", "", "", "", "A", "", "", "GENESIS", "", "", "", "", "", "", "YES", "" }, { "378a62af6e9c12a760795ff4fc939656", "Atari - Axlon, Steve DeFrisco", "CX26171", "MotoRodeo (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "378c118b3bda502c73e76190ca089eef", "Atari, Alan Miller", "CX2662P", "Hangman (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "37ab3affc7987995784b59fcd3fcbd31", "", "", "Sprite Test (29-11-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "37b98344c8e0746c486caf5aaeec892a", "K-Tel Vision", "6", "Spider Maze (1982) (K-Tel Vision) (PAL)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "37e828675d556775ae8285c0caf7d11c", "AtariAge - Fred Quimby", "", "Gingerbread Man (Fred Quimby) (Genesis)", "Genesis controller (C throws cookie)", "New Release", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "37f42ab50018497114f6b0f4f01aa9a1", "", "", "Droid Demo 2-M (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "37fd7fa52d358f66984948999f1213c5", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (Rainbow Vision) (PAL) [a2]", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "384db97670817103dd8c0bbdef132445", "Atari - Sears", "CX2626 - 6-99829, 49-75116", "Miniature Golf (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "384f5fbf57b5e92ed708935ebf8a8610", "20th Century Fox Video Games, John W.S. Marvin", "11009", "Crypts of Chaos (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3856b9425cc0185ed770376a62af0282", "Kyle Pittman", "", "Yellow Submarine (Kyle Pittman) (Hack)", "Hack of Bermuda Triangle", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "386ff28ac5e254ba1b1bac6916bcc93a", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "3882224adbd0ca7c748b2a1c9b87263e", "Atari, Tod Frye", "CX2657", "SwordQuest - FireWorld (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3889351c6c2100b9f3aef817a7e17a7a", "CCE", "", "Dolphin (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3897744dd3c756ea4b1542e5e181e02a", "Atari, Jerome Domurat, Peter C. Niday", "CX26115", "Dumbo's Flying Circus (05-05-1983) (Atari) (Prototype)", "AKA Dumbo Flies Home", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "38bd172da8b2a3a176e517c213fcd5a6", "Atari", "MA017600", "Diagnostic Test Cartridge 2.6 (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "38c362dcd5cad5a62e73ae52631bd9d8", "Jake Patterson", "", "Baubles (14-11-2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "38cf93eacfb2fa9a2c5e39059ff35a74", "Greg Zumwalt", "", "WacMan (2003) (Greg Zumwalt) (Hack)", "Hack of Ms. Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "38de7b68379770b9bd3f7bf000136eb0", "Imagic, Mark Klein", "EIZ-003-04I", "Subterranea (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "391764720140c432aec454a468f77a40", "Video Game Program", "", "Miss Pack Man (Video Game Program) (PAL)", "AKA Ms. Pac-Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "392d34c0498075dd58df0ce7cd491ea2", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "392f00fd1a074a3c15bc96b0a57d52a1", "Atari, Rob Fulop - Sears", "CX2633 - 49-75119", "Night Driver (1980) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 65", "", "", "", "YES", "" }, { "393948436d1f4cc3192410bb918f9724", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "393e41ca8bdd35b52bf6256a968a9b89", "U.S. Games Corporation - Western Technologies", "VC1012", "M.A.D. (1983) (U.S. Games)", "AKA Missile Intercept", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3947eb7305b0c904256cdbc5c5956c0f", "Jone Yuan Telephonic Enterprise Co", "", "Lilly Adventure (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "230", "", "" }, { "396f7bc90ab4fa4975f8c74abe4e81f0", "Atari, Larry Kaplan - Sears", "CX2612 - 99804, 49-75103", "Street Racer (1977) (Atari)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 60", "", "", "", "", "" }, { "39790a2e9030751d7db414e13f1b6960", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "39a6a5a2e1f6297cceaa48bb03af02e9", "", "", "Pitfall 2 Plus (Hack)", "Hack of Pitfall 2", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "39b94d41bd3b01c12b4054c1a8733783", "SOLID Corp. (D. Scott Williamson)", "CX2655-016", "Star Castle 2600 (SolidCorp) [016]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "39c78d682516d79130b379fa9deb8d1c", "Apollo - Games by Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "39d36366ae7e6dfd53393fb9ebab02a0", "CCE", "C-811", "River Raid (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "39da69ff9833f8c143f03b6e0e7a996b", "Charles Morgan", "", "Ventrra Invaders 2002 (Charles Morgan) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "39fe316952134b1277b6a81af8e05776", "Robby", "18", "River Raid (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3a2e2d0c6892aa14544083dfb7762782", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3a35d7f1dc2a33565c8dca52baa86bc4", "", "", "Rubik's Cube Demo 2 (23-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3a51a6860848e36e6d06ffe01b71fb13", "Retroactive", "", "Qb (2.07) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3a526e6a1f9fe918af0f2ce997dfea73", "CBS Electronics, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1982) (CBS Electronics) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3a53963f053b22599db6ac9686f7722f", "", "", "Word Zapper (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3a771876e4b61d42e3a3892ad885d889", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Defender II (1987) (Atari)", "AKA Stargate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3aad0ef62885736a5b8c6ccac0dbe00c", "Dynacom", "", "Atlantis (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3ab5d138e26d88c8190e7cc629a89493", "", "", "Phased Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3ac6c50a8e62d4ce71595134cbd8035e", "Absolute Entertainment, Dan Kitchen", "AK-046-04", "Tomcat (1988) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3ad3dc799211ccd424d7c6d454401436", "Probe 2000 - North American Philips Consumer Electronics Corporation", "", "Power Lords (1983) (Probe) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3ad58b53a1e972396890bd86c735e78d", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur Version 36 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b040ed7d1ef8acb4efdeebebdaa2052", "Tigervision", "7-008", "Miner 2049er (1983) (Tigervision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "214", "", "" }, { "3b097a7ed5bd2a84dc3d3ed361e9c31c", "", "", "Interleaved ChronoColour Demo (PAL) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b10106836565e5db28c7823c0898fbb", "Xonox - Beck-Tech", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "3b2c32fcd331664d037952bcaa62df94", "Xonox", "6230, 6250", "Super Kung-Fu (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b5751a8d20f7de41eb069f76fecd5d7", "", "", "Eckhard Stolberg's Scrolling Text Demo 4 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b64a00ce147c3c29f7f8f8e531d08d8", "", "", "This Planet Sucks (16K) (Greg Troutman)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "3b69f8929373598e1752f43f8da61aa4", "Apollo - Games by Apollo - RCA Video Jeux", "AP-2006", "Infiltrate (1921) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3b6dba1a24bb2893bd3bd0593f92016b", "CBS Electronics / Thomas Jentzsch", "", "Omega Race JS (TJ)", "Hack of Omega Race (CBS Electronics)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b76242691730b2dd22ec0ceab351bc6", "M Network, Connie Goldman, Joe King, Patricia Lewis Du Long, Gerald Moore, Mike Sanders, Jossef Wagner - INTV", "MT4319", "Masters of the Universe (1983) (M Network)", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3b80b8f52a0939e16b5059f93a3fc19a", "V007", "", "Virtual Pet (V007) (after Demo 2) (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b86a27132fb74d9b35d4783605a1bcb", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b8aacf5f5638492b926b5124de19f18", "Atari, Tod Frye - Sears", "CX2646 - 49-75185", "Pac-Man (1981) (Atari) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b91c347d8e6427edbe942a7a405290d", "Parker Brothers", "PB5350", "Sky Skipper (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b9480bb6fb1e358c9c0a64e86945aee", "", "", "Title Match Pro Wrestling (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3b966bf3c2ca34ac6ca1de4cf6383582", "", "", "Double-Height 6-Digit Score Display (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3bb9793c60c92911895cf44530846136", "Jone Yuan Telephonic Enterprise Co", "", "Dragster (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3c21a89bc38d8cd0b010a2916bcff5c2", "", "", "Colony 7 - CX-22 Hack v0.4 (NTSC)", "", "", "", "", "", "", "", "", "TRAKBALL", "", "", "", "", "", "", "YES", "50" }, { "3c3a2bb776dec245c7d6678b5a56ac10", "", "", "Unknown Title (bin00003) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3c4223316c835ceaad619651e25df0f9", "", "", "Defender (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "3c4a6f613ca8ba27ce9e43c6c92a3128", "", "", "Qb (V0.04) (Non-Lax Version) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3c57748c8286cf9e821ecd064f21aaa9", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118", "Millipede (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3c72ddaf41158fdd66e4f1cb90d4fd29", "Dismac", "", "Comando Suicida (Dismac)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3c7a7b3a0a7e6319b2fa0f923ef6c9af", "Atari - Roklan, Joe Gaucher", "", "Racer (1982) (Atari) (Prototype)", "ROM must be started in bank 0", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3c7a96978f52b2b15426cdd50f2c4048", "", "", "Overhead Adventure Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3c82e808fe0e6a006dc0c4e714d36209", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3c853d864a1d5534ed0d4b325347f131", "Telesys, Don 'Donyo' Ruffcorn", "1002", "Cosmic Creeps (1982) (Telesys)", "AKA Space Maze, Spaze Maze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3c8e57a246742fa5d59e517134c0b4e6", "Parker Brothers, Rex Bradford, Sam Kjellman", "PB5050", "Star Wars - The Empire Strikes Back (1982) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3ca51b5c08f5a0ecfb17d0c1ec6d0942", "Atari, James Andreasen - Sears", "CX2654 - 49-75141", "Haunted House (09-28-81) (Atari) (Prototype)", "AKA Mystery Mansion, Graves' Manor, Nightmare Manor", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3caa902ac0ce4509308990645876426a", "Atari - GCC, Dave Payne", "CX2669, CX2669P", "Vanguard (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3cbdf71bb9fd261fbc433717f547d738", "CCE", "C-803", "Bobby Is Going Home (1983) (CCE) (PAL)", "AKA Bobby Vai Para Casa", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3cdd91e1c28d28e856c0063d602da166", "", "", "Stell-A-Sketch (03-11-1997) (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3d1e83afdb4265fa2fb84819c9cfd39c", "Coleco - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "2465", "Smurf - Rescue in Gargamel's Castle (1983) (Coleco)", "AKA Smurf, Smurf Action", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3d2367b2b09c28f1659c082bb46a7334", "Imagic, Dennis Koble", "720103-2A, IA3203P, EIX-010-04I", "Atlantis (1982) (Imagic) (PAL)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3d2652cbea462a886a41791dd7c8d073", "", "", "Ritorno dei frattelli di Mario (Mario Bros Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3d48b8b586a09bdbf49f1a016bf4d29a", "Video Game Cartridge - Ariola", "TP-606", "Hole Hunter (Video Game Cartridge)", "AKA Topy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3d6fc7a19be76d808aa233415cb583fc", "CCE", "C-833", "Target Practice (1983) (CCE)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "214", "", "" }, { "3d7749fb9c2f91a276dfe494495234c5", "Jone Yuan Telephonic Enterprise Co", "", "Checkers (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3d7aad37c55692814211c8b590a0334c", "Atari, Dan Oliver", "", "Telepathy (1983) (Atari) (Prototype)", "Uses both left joystick and right Mindlink controllers (press Fire on respective controller to begin)", "Prototype", "", "", "", "", "", "", "", "MINDLINK", "", "78", "", "", "215", "", "" }, { "3d8a2d6493123a53ade45e3e2c5cafa0", "Atari, Jim Huether - Sears", "CX2629 - 6-99843, 49-75118", "Sky Diver (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3d934bb980e2e63e1ead3e7756928ccd", "Activision, Steve Cartwright - Ariola", "EAX-017, EAX-017-04I - 711 017-720", "MegaMania (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3d9c2fccf8b11630762ff00811c19277", "", "", "Challenge of.... Nexar, The (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3da7cc7049d73d34920bb73817bd05a9", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3dfb7c1803f937fadc652a3e95ff7dc6", "Dimax - Sinmax", "SM8001", "Space Robot (Dimax - Sinmax)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3e03086da53ecc29d855d8edf10962cb", "CBS Electronics - Roklan, Joe Gaucher, Alex Leavens", "4L1751, 4L1752, 4L1753, 4L2275", "Gorf (1982) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3e1682ddaec486d8b6b90b527aaa0fc4", "Thomas Jentzsch", "", "Robot City (V0.12) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3e22c7eaf6459b67388602e4bebbb3a8", "CommaVid, John Bronstein - Ariola", "CM-003 - 712 003-720", "Cosmic Swarm (1982) (CommaVid) (PAL) (4K)", "AKA Angriff der Termiten", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3e33ac10dcf2dff014bc1decf8a9aea4", "Spectravideo - Video Games Industries Corporation, Mike Schwartz - Ralston Purina", "", "Chase the Chuckwagon (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "22", "", "YES", "" }, { "3e49da621193d2611a4ea152d5d5ca3a", "", "", "Atari Logo Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3e4b1137433cc1e617b5508619e13063", "", "", "Asteroids (Genesis)", "Genesis controller (C is hyperspace)", "Hack of Asteroids", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "YES", "" }, { "3e5ca1afaa27c5da3c54c9942fec528b", "", "", "2600 Digital Clock (Demo 2) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3e6dab92009d6034618cb6b7844c5216", "", "", "Ed Invaders (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3e7d10d0a911afc4b492d06c99863e65", "VGS", "", "Super Tenis (VGS)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3e88cca5b860d0bd8947479e74c44284", "Atari, Lou Harp", "CX26122", "Sinistar (01-23-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3e899eba0ca8cd2972da1ae5479b4f0d", "Coleco, Joseph Biel", "2457", "Venture (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3e90cf23106f2e08b2781e41299de556", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3eae062a9b722bda1255d474a87eca5c", "Atari, David Crane", "CX2605, CX2605P", "Outlaw (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3eb1e34a4f0eec36f12e7336badcecf2", "Jake Patterson", "", "Baubles (V0.001) (2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3eb21313ea5d5764c5ed9160a5a55a83", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3ec12372ca3e870b11ca70edc7ec26a4", "CommaVid, John Bronstein", "CM-002", "Video Life (1981) (CommaVid) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3eccf9f363f5c5de0c8b174a535dc83b", "", "", "Plaque Attack (Unknown) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3ef9573536730dcd6d9c20b6822dbdc4", "Atari, Larry Wagner, Bob Whitehead", "CX2645, CX2645P", "Video Chess (1979) (Atari) (PAL)", "AKA Computer Chess", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f01bd6d059396f495a4cde7de0ab180", "", "", "Qb (Special Edition) (NTSC) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "3f039981255691d3859d04ef813a1264", "Xonox, John Perkins", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) [a]", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "3f251c50aa7237e61a38ab42315ebed4", "Thomas Jentzsch", "", "Ikari Warriors (1990) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f3ad2765c874ca13c015ca6a44a40a1", "CCE", "C-862", "Crackpots (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f540a30fdee0b20aed7288e4a5ea528", "Atari - GCC", "CX2670", "Atari Video Cube (1983) (Atari)", "AKA Atari Cube, Video Cube", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f58f972276d1e4e0e09582521ed7a5b", "Telegames", "6082 A145", "Kung Fu Superkicks (1988) (Telegames)", "AKA Chuck Norris Superkicks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f5a43602f960ede330cd2f43a25139e", "Activision, Alan Miller", "AG-003", "Checkers (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f6938aa6ce66e6f42e582c1eb19b18c", "Jone Yuan Telephonic Enterprise Co", "", "Laser Blast (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "3f6dbf448f25e2bd06dea44248eb122d", "", "5687 A279", "Soccer (1988) (Telegames)", "AKA International Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f75a5da3e40d486b21dfc1c8517adc0", "Atari, Jim Huether", "CX26163P", "Sky Diver (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f9431cc8c5e2f220b2ac14bbc8231f4", "", "", "Colors Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f96eb711928a6fac667c04ecd41f59f", "Bit Corporation", "PGP218", "Rodeo Champ (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3f9cb1aba8ec20e2c243ae642f9942bf", "", "", "New Questions (1998) (John K. Harvey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3fd1f9d66a418c9f787fc5799174ddb7", "Aaron Curtis", "", "AStar (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3fd53bfeee39064c945a769f17815a7f", "CCE", "", "Sea Hawk (CCE)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3fe43915e5655cf69485364e9f464097", "CCE", "C-863", "Fisher Price (1983) (CCE)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "3ff5165378213dab531ffa4f1a41ae45", "Otto Versand", "311377", "Pygmy (1983) (Otto Versand) (PAL)", "AKA Lock 'n' Chase (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "402b1ca3c230a60fb279d4a2a10fa677", "", "", "3-D Tic-Tac-Toe (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "62", "", "", "" }, { "402d876ec4a73f9e3133f8f7f7992a1e", "Alex Herbert", "", "Man Goes Down (2006) (A. Herbert) (Prototype)", "Uses AtariVox controller", "Homebrew", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "", "" }, { "405f8591b6941cff56c9b392c2d5e4e5", "Telegames", "", "Star Strike (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4066309eb3fa3e7a725585b9814bc375", "", "", "Multi Ball Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4066d7d88ec4a2c656127a67fa52dcf1", "", "", "Overhead Adventure Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "64", "", "", "" }, { "407a0c6cc0ff777f67b669440d68a242", "Erik Eid", "", "Euchre (Alpha) (PAL) (31-08-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4093382187f8387e6d011883e8ea519b", "", "", "Go Go Home (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "40aa851e8d0f1c555176a5e209a5fabb", "", "", "Euchre (More for less) (NTSC) (22-08-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "40b1832177c63ebf81e6c5b61aaffd3a", "Atari, Peter C. Niday", "", "Rubik's Cube 3-D (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "40b59249e05135bca33861e383735e9e", "Atari", "CX26163P", "Skiing (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "40d7ccd460c9b1198238af6ceea1737d", "", "", "Star Fire - Enemy Mine (2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "40d8ed6a5106245aa79f05642a961485", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 06002, 06004, 99002", "Ghost Manor (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "40d9f5709877ecf3dd1184f9791dd35e", "Dactari - Milmar", "", "Skiing (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "40e12c008037a323a1290c8fa4d2fe7f", "", "", "Skeleton (NTSC) (06-09-2002) (Eric Ball)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "40eb4e263581b3dfec6dd8920b68e00f", "Sears Tele-Games, Marilyn Churchill, Matthew L. Hubbard", "CX2647 - 49-75142", "Seawolf 3 (03-23-1981) (Sears) (Prototype) (PAL)", "Submarine Commander Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "413c925c5fdcea62842a63a4c671a5f2", "Activision, Larry Kaplan", "AX-006", "Bridge (1980) (Activision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4153dd2beed648e9dc082140ebe8e836", "", "", "Coke Zero (v1.0) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "415c11fcac66bbd2ace2096687774b5a", "", "", "Fu Kung! (V0.00) (07-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4181087389a79c7f59611fb51c263137", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (06-24-1983) (Atari) (Prototype) (8K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "41810dd94bd0de1110bedc5092bef5b0", "Funvision - Fund. International Co.", "", "Dragon Treasure (Funvision)", "AKA Dragonfire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "41818738ab1745e879024a17784d71f5", "CCE", "C-832", "Atlantis (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4189adfc1b30c121248876e3a1a3ac7e", "Eric Ball", "", "Skeleton (Complete) (06-09-2002) (Eric Ball)", "", "New Release", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4191b671bcd8237fc8e297b4947f2990", "Exus Corporation", "", "Video Jogger (1983) (Exus)", "AKA Foot Craz", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "41c4e3d45a06df9d21b7aae6ae7e9912", "CCE", "C-826", "Grand Prix (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "41f252a66c6301f1e8ab3612c19bc5d4", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (1983) (Atari)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4209e9dcdf05614e290167a1c033cfd2", "CommaVid, John Bronstein", "CM-002", "Video Life (1984) (CommaVid) [higher sounds]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "42249ec8043a9a0203dde0b5bb46d8c4", "CCE", "", "Resgate Espacial (CCE)", "AKA Moonsweeper", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4233eb824c2b4811abef9b6d00355ae9", "Retroactive", "", "Qb (V0.10) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4251b4557ea6953e88afb22a3a868724", "", "", "Robot City (V1.1) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "425ee444a41d218598893d6b6e03431a", "", "", "Invaders Demo (2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4279485e922b34f127a88904b31ce9fa", "", "", "Enduro (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "428b2d36f5d716765460701f7016ac91", "Andrew Wallace", "", "Brooni (2001) (Andrew Wallace) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "42ae81ae8ac51e5c238639f9f77d91ae", "", "", "Multi-Sprite Demo 2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "42b2c3b4545f1499a083cfbc4a3b7640", "U.S. Games Corporation - JWDA, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV", "VC2003", "Eggomania (1982) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 60", "", "26", "", "", "" }, { "42b3ab3cf661929bdc77b621a8c37574", "Robby", "", "Volleyball (Robby)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "42b5e3a35b032f033809afb0ea28802d", "Atari, Mimi Nyden, Scott Smith, Robert Vieira", "CX26127", "Gremlins (03-12-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "42cdd6a9e42a3639e190722b8ea3fc51", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "42dcc02777b0bcfacd85aeb61d33558a", "", "", "Human Cannonball (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "42e0ec5ab8f5deba53e4169ff2a5efbe", "", "", "Atari Logo Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4311a4115fb7bc68477c96cf44cebacf", "", "", "Challenge (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "14", "240", "", "" }, { "4326edb70ff20d0ee5ba58fa5cb09d60", "Atari - GCC, Kevin Osborn", "CX2689", "Kangaroo (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "435fd469f088468c4d66be6b5204d887", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "438968a26b7cfe14a499f5bbbbf844db", "", "", "Raft Rider (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "43adf60ebdd6b5a0fae21594ecf17154", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "43c6cfffeddab6b3787357fed9d44529", "20th Century Fox Video Games, Frank Cohen, Douglas 'Dallas North' Neubauer", "11111", "M.A.S.H (1983) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "43e6c5159c3a093fca88656628c6ef34", "", "", "Star Fire (17-02-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "43f33c6dfdeaf5138ce6e6968ad7c5ce", "Jeffry Johnston", "", "Radial Pong - Version 11 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "43f8459d39fb4eddf9186d62722ff795", "", "", "Skeleton+ (17-04-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "442602713cb45b9321ee93c6ea28a5d0", "", "", "Demon Attack (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "442b7863683e5f084716fda050474feb", "Eckhard Stolberg", "", "Frame Timed Sound Effects-EM (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4431428a7500c96fc0e2798a5dbd36d6", "", "", "Kangaroo (Genesis)", "Genesis controller (B is punch, C is jump)", "Hack of Kangaroo", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "44560e324ffb30741a483218ba5b4342", "", "", "Star Fire - Faster Skipping 2 (24-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4474b3ad3bf6aabe719a2d7f1d1fb4cc", "Activision, Dan Kitchen", "EAX-039-04B, EAX-039-04I", "Kung-Fu Master (1987) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4476c39736090dabac09f6caf835fc49", "", "", "Text Screen (25-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "448c2a175afc8df174d6ff4cce12c794", "Activision, David Crane", "AB-035-04", "Pitfall II (1983) (Activision) [a2]", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "44e9c4a047c348dbeb7ace60f45484b4", "", "", "Moon Patrol Arcade (Genesis)", "Genesis controller (C is jump)", "Hack of Moon Patrol", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "44f71e70b89dcc7cf39dfd622cfb9a27", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45027dde2be5bdd0cab522b80632717d", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00250", "Summer Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45040679d72b101189c298a864a5b5ba", "20th Century Fox Video Games - Sirius Software, David Lubar", "11022", "SpaceMaster X-7 (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4543b7691914dfd69c3755a5287a95e1", "CommaVid, Irwin Gaines", "CM-005", "Mines of Minos (1982) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "456453a54ca65191781aef316343ae00", "", "", "Full Screen Bitmap (3-D Green) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4565c1a7abce773e53c75b35414adefd", "Arcadia Corporation", "", "Supercharger BIOS (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "457b03cd48ff6d895795ef043c6b0f1e", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "457e7d4fcd56ebc47f5925dbea3ee427", "Carrere Video - JWDA, Garry Kitchen - Teldec - Prism", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "457f4ad2cda5f4803f122508bfbde3f5", "", "", "Canyon Bomber (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "458883f1d952cd772cf0057abca57497", "", "", "Fishing Derby (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45a095645696a217e416e4bd2baea723", "Digivision", "", "Snoopy (Digivision)", "AKA Snoopy and the Red Baron", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45a4f55bb9a5083d470ad479afd8bca2", "CommaVid, Joseph Biel", "", "Frog Demo (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45beef9da1a7e45f37f3f445f769a0b3", "Atari, Suki Lee", "CX2658", "Math Gran Prix (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45c4413dd703b9cfea49a13709d560eb", "Jone Yuan Telephonic Enterprise Co", "", "Challenge of.... Nexar, The (Jone Yuan) (Hack)", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "45cb0f41774b78def53331e4c3bf3362", "Carrere Video - JWDA, Roger Booth, Sylvia Day, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV - Teldec - Prism", "USC1007", "Octopus (1983) (Carrere Video) (PAL)", "AKA Name This Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4605a00f5b44a9cbd5803a7a55de150e", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (07-03-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "461029ab23800833e9645be3e472d470", "", "", "Combat TC (v0.1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "46258bd92b1f66f4cb47864d7654f542", "Zellers", "", "Turmoil (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "463dd4770506e6c0ef993a40c52c47be", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (Preview) (1982) (Arcadia)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "463e66ad98806a49106cffa49c08e2ed", "", "", "Interlace Game Demo (01-09-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "467340a18158649aa5e02a4372dcfccd", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4689081b7363721858756fe781cc7713", "", "", "Oystron (V2.6) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "468f2dec984f3d4114ea84f05edf82b6", "Tigervision - Teldec", "7-011 - 3.60015 VG", "Miner 2049er Volume II (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4690fdb70c86604bb35da26696818667", "", "", "Euchre (Release Candidate) (NTSC) (28-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "469473ff6fed8cc8d65f3c334f963aab", "Atari, Bruce Poehlman, Gary Stark", "", "Dune (07-10-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "46c021a3e9e2fd00919ca3dd1a6b76d8", "Atari, Jim Huether - Sears", "CX2629 - 6-99843, 49-75118", "Sky Diver (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "46c43fdcbce8fde3a91ebeafc05b7cbd", "", "", "Invaders Demo (PAL) (2001) (Eckhard Stolberg)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "46e9428848c9ea71a4d8f91ff81ac9cc", "Telegames", "", "Astroblast (1988) (Telegames) (PAL)", "Can also use left joystick", "", "", "", "", "", "", "", "PADDLES", "", "YES", "AUTO 55", "", "", "", "", "" }, { "4702d8d9b48a332724af198aeac9e469", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "470878b9917ea0348d64b5750af149aa", "Atari, Suki Lee - Sears", "CX2658 - 49-75128", "Math Gran Prix (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47464694e9cce07fdbfd096605bf39d4", "Activision, Dan Kitchen", "EAK-050-04", "Double Dragon (1989) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4767356fa0ed3ebe21437b4473d4ee28", "Atari, Dan Hitchens, Mimi Nyden", "CX2685", "Gravitar (04-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47711c44723da5d67047990157dcb5dd", "CCE", "", "Ice Hockey (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47911752bf113a2496dbb66c70c9e70c", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1984) (Atari) (PAL)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "4799a40b6e889370b7ee55c17ba65141", "Konami", "RC 100-X 02", "Pooyan (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "215", "", "" }, { "47aad247cce2534fd70c412cb483c7e0", "Rainbow Vision - Suntek", "SS-010", "Mafia (Rainbow Vision) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47abfb993ff14f502f88cf988092e055", "Zellers", "", "Inca Gold (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47aef18509051bab493589cb2619170b", "", "", "Stell-A-Sketch (Bob Colbert) (PD)", "Uses Driving, Joystick, or Amiga/Atari ST mouse Controllers", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "47b82d47e491ac7fdb5053a88fccc832", "Atari Freak 1, Franklin Cruz", "", "Asteroid 2 (Atari Freak 1) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "47bb1c677fe7ba5f376372ae7358e790", "", "", "Star Fire (10-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "47cd61f83457a0890de381e478f5cf5f", "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop", "720111-2A, 13205", "Fathom (1983) (Imagic) (PAL)", "AKA Scuba", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "481d20ec22e7a63e818d5ef9679d548b", "Atari", "CX26163P", "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "481f9a742052801cc5f3defb41cb638e", "Jeffry Johnston", "", "Radial Pong - Version 4 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "48287a9323a0ae6ab15e671ac2a87598", "Zellers", "", "Laser Volley (Zellers)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "48411c9ef7e2cef1d6b2bee0e6055c27", "Telesys, Don Ruffcorn, Jack Woodman", "1003", "Fast Food (1982) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "484b0076816a104875e00467d431c2d2", "Atari", "CX26150", "Q-bert (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4868a81e1b6031ed66ecd60547e6ec85", "Eric Mooney", "", "Invaders by Erik Mooney (V2.1) (1-3-98) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4884b1297500bd1243659e43c7e7579e", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (10-24-1991) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4892b85c248131d6a42c66a4163a40d0", "Canal 3 - Intellivision", "", "Tac-Scan (Canal 3)", "Uses the Paddle Controllers", "", "", "", "", "", "", "YES", "PADDLES", "", "YES", "AUTO 60", "", "", "215", "", "" }, { "48bcf2c5a8c80f18b24c55db96845472", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "48e5c4ae4f2d3b62b35a87bca18dc9f5", "Quelle", "476.774 5", "Bobby geht nach Hause (1983) (Quelle) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "42", "", "", "" }, { "48f18d69799a5f5451a5f0d17876acef", "ZiMAG - Emag - Vidco", "GN-070", "Mysterious Thief, A (1983) (ZiMAG) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4901c05068512828367fde3fb22199fe", "Imagic, Rob Fulop", "720101-2B, IA3200P, EIX-006-04I", "Demon Attack (1982) (Imagic) (PAL)", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4904a2550759b9b4570e886374f9d092", "Parker Brothers, Charlie Heath", "931506", "Reactor (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "490e3cc59d82f85fae817cdf767ea7a0", "", "", "Berzerk (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "490eed07d4691b27f473953fbea6541a", "Activision, David Crane", "AB-035-04", "Pitfall II (1983) (Activision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "493daaf9fb1ba450eba6b8ed53ffb37d", "", "", "3-D Corridor Demo (27-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "493de059b32f84ab29cde6213964aeee", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Stargate (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "493e90602a4434b117c91c95e73828d1", "Telegames", "", "Lock 'n' Chase (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4947c9de2e28b2f5f3b0c40ce7e56d93", "", "", "3-D Corridor Demo 2 (29-03-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "494cda91cc640551b4898c82be058dd9", "Andreas Dietrich", "", "Donkey Kong VCS (2017) (1.0) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "YES", "" }, { "49571b26f46620a85f93448359324c28", "", "", "Save Our Ship (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "37", "", "", "" }, { "497f3d2970c43e5224be99f75e97cbbb", "CommaVid, John Bronstein", "CM-002", "Video Life (1984) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4981cefe5493ea512284e7f9f27d1e54", "Home Vision - Gem International Corp. - VDI", "VCS83136", "Cosmic War (1983) (Home Vision) (PAL)", "AKA Cosmic Corridor", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "4999b45be0ab5a85bac1b7c0e551542b", "CCE", "", "Double Dragon (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "499b612f6544ae71d4915aa63e403e10", "Atari, Carol Shaw", "CX26163P", "Checkers (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4a196713a21ef07a3f74cf51784c6b12", "Jone Yuan Telephonic Enterprise Co", "", "Frogs and Flies (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4a2fe6f0f6317f006fd6d4b34515448b", "", "", "Warring Worms (Midwest Classic Edition) (08-06-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4a45c6d75b1ba131f94a9c13194d8e46", "", "", "How to Draw a Playfield II (Joystick Hack) (1997) (Eric Bacher) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4a5fddf89801336637ac8e57a7c9a881", "Amiga", "1125", "Power Play Arcade Video Game Album IV (1984) (Amiga) (Prototype)", "Atlantis, Cosmic Ark, Dragonfire", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4a6be79310f86f0bebc7dfcba4d74161", "", "", "Demolition Herby (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4a7eee19c2dfb6aeb4d9d0a01d37e127", "Hozer Video Games", "", "Crazy Valet (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4a8c743396b8ad69d97e6fd3dd3e3132", "Arcadia Corporation", "", "Supercharger BIOS (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4a9009620038f7f30aaeb2a00ae58fde", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (3 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4ab2ebd95a8f861ea451abebdad914a5", "Nukey Shay, Thomas Jentzsch", "PAL conversion (F6)", "Montezuma's Revenge (PAL) (Genesis)", "Genesis controller (B jumps left, C jumps right)", "Homebrew", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "4ab4af3adcdae8cdacc3d06084fc8d6a", "Nick Bensema", "", "Sucky Zepplin (Nick Bensema) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4abb4c87a4c5f5d0c14ead2bb36251be", "Atari - Imagineering, Alex DeMeo", "CX26135, CX26135P", "RealSports Boxing (1987) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4ac9f40ddfcf194bd8732a75b3f2f214", "Atari - CCW, Stephan R. Keith, Laura Scholl, Preston Stuart", "CX26106", "Grover's Music Maker (12-29-1982) (Atari) (Prototype)", "Uses Keypad Controller", "Prototype", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, { "4ae8c76cd6f24a2e181ae874d4d2aa3d", "", "", "Flash Gordon (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4af4103759d603c82b1c9c5acd2d8faf", "Imagic, Bob Smith", "720114-2A, 13207, EIZ-001-04I", "Moonsweeper (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4afa7f377eae1cafb4265c68f73f2718", "Ed Fries", "", "Halo 2600 (2010) (Ed Fries)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4afe528a082f0d008e7319ebd481248d", "", "", "Multi-Color Demo 1 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b143d7dcf6c96796c37090cba045f4f", "Atari, Jim Huether - Sears", "CX2644 - 6-99824", "Flag Capture (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b205ef73a5779acc5759bde3f6d33ed", "", "", "Berzerk (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b27f5397c442d25f0c418ccdacf1926", "Atari, Warren Robinett", "CX2613, 49-75154", "Adventure (1980) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b71197153d651480830638cb6a03249", "Atari, Larry Kaplan", "CX26163P", "Bowling (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b753a97aee91e4b3e4e02f5e9758c72", "Glenn Saunders, Roger Williams", "", "Asymmetric Reflected Playfield (Glenn Saunders)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4b94fd272785d7ec6c95fb7279d0f522", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (12-03-1982) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "4b9581c3100a1ef05eac1535d25385aa", "", "", "IQ 180 (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "235", "", "" }, { "4baada22435320d185c95b7dd2bcdb24", "Atari, Jerome Domurat, Dave Staugas", "CX2682", "Krull (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4bcc7f6ba501a26ee785b7efbfb0fdc8", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4bdae9246d6ee258c26665512c1c8de3", "Atari", "CX26163P", "Human Cannonball (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c030667d07d1438f0e5c458a90978d8", "Retroactive", "", "Qb (V2.03) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4c0fb2544ae0f8b5f7ae8bce7bd7f134", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (Preview) (1983) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "", "", "", "", "", "" }, { "4c205f166157154df2f1ef60d87e552f", "", "", "Single-Scanline Positioning Demo 2 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c39a2c97917d3d71739b3e21f60bba5", "", "", "Whale (Sub Scan Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c462b2b6fb0a19a1437eb2c3dc20783", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c4ce802cbfd160f7b3ec0f13f2a29df", "", "", "Beta Demo (V1.1) (26-09-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c606235f4ec5d2a4b89139093a69437", "Andrew Davies", "", "Andrew Davies early notBoulderDash demo (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4c6afb8a44adf8e28f49164c84144bfe", "CCE", "C-806", "Mission 3,000 A.D. (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c8832ed387bbafc055320c05205bc08", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c8970f6c294a0a54c9c45e5e8445f93", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4c9307de724c36fd487af6c99ca078f2", "Imagic, Brad Stewart", "720106-1A, IA3409", "Sky Patrol (1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4ca0959f846d2beada18ecf29efe137e", "Atari, Jim Huether, Alan J. Murphy, Robert C. Polaro", "CX2666, CX2666P", "RealSports Volleyball (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4ca73eb959299471788f0b685c3ba0b5", "Activision, Steve Cartwright", "AX-031", "Frostbite (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4ca90ba45eced6f5ad560ea8938641b2", "", "", "Hangman Man Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4cabc895ea546022c2ecaa5129036634", "Funvision - Fund. International Co.", "", "Ocean City (Funvision)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4cd796b5911ed3f1062e805a3df33d98", "Tigervision - Software Electronics Corporation - Teldec", "7-006", "Springer (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "4d0a28443f7df5f883cf669894164cfa", "", "", "Beast Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4d2cef8f19cafeec72d142e34a1bbc03", "HES", "771-422", "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4d38e1105c3a5f0b3119a805f261fcb5", "Bit Corporation", "PGP212", "Phantom UFO (4 Game in One Light Green) (1983) (BitCorp) (PAL)", "AKA Spider Fighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4d502d6fb5b992ee0591569144128f99", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (11-21-1989) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4d5f6db55f7f44fd0253258e810bde21", "Fabrizio Zavagli", "", "Betterblast (Fabrizio Zavagli) (Hack)", "Hack of Astroblast", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4d7517ae69f95cfbc053be01312b7dba", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4d77f291dca1518d7d8e47838695f54b", "Data Age", "DA1004", "Airlock (1982) (Data Age)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4d8396deeabb40b5e8578276eb5a8b6d", "Otto Versand", "781698", "Volleyball (1983) (Otto Versand) (PAL)", "AKA RealSports Volleyball (Double-Game Package)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4dbf47c7f5ac767a3b07843a530d29a5", "Ric Pryor", "", "Breaking News (2002) (Ric Pryor) (Hack)", "Hack of Bump 'n' Jump", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4dcc7e7c2ec0738e26c817b9383091af", "", "", "Unknown Title (bin00026 (200110)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4dd6c7ab9ef77f2b4950d8fc7cd42ee1", "Retroactive", "", "Qb (V2.04) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4df6124093ccb4f0b6c26a719f4b7706", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) [a]", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 60", "", "", "", "", "" }, { "4df9d7352a56a458abb7961bf10aba4e", "", "", "Racing Car (Unknown)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "4e01d9072c500331e65bb87c24020d3f", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (06-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4e02880beeb8dbd4da724a3f33f0971f", "Imagic, Michael Greene", "EIZ-002-04I", "Wing War (1983) (Imagic) (PAL)", "AKA Flap!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4e15ddfd48bca4f0bf999240c47b49f5", "Avalon Hill, Jean Baer, Jim Jacob", "5001002", "Death Trap (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4e2c884d04b57b43f23a5a2f4e9d9750", "", "", "Baby Center Animation (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4e37992a37ea36489283f7eb90913bbc", "Kris", "", "Hangman Ghost Halloween (Kris) (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4e4895c3381aa4220f8c2795d6338237", "", "", "Backwards Cannonball v1 (Hack)", "Hack of Human Cannonball", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4e66c8e7c670532569c70d205f615dad", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4e86866d9cde738d1630e2e35d7288ce", "Supergame", "", "River Raid III (Supergame)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4e99ebd65a967cabf350db54405d577c", "Coleco", "2663", "Time Pilot (1983) (Coleco) [b1]", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4eb4fd544805babafc375dcdb8c2a597", "Inspirational Video Concepts, Steve Shustack", "321430", "Red Sea Crossing (1983) (Inspirational Video Concepts)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4edb251f5f287c22efc64b3a2d095504", "Atari", "", "Atari VCS Point-of-Purchase ROM (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f0071946e80ca68edfdccbac86dcce0", "", "", "Virtual Pet Demo 1 (CRACKERS) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f2d47792a06da224ba996c489a87939", "HES - Activision", "223", "Super Action Pak - Pitfall, Barnstorming, Grand Prix, Laser Blast (1988) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f32b24869d8c1310fecf039c6424db6", "U.S. Games Corporation - JWDA, Todd Marshall", "", "3-D Zapper (12-15-82) (U.S. Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f618c2429138e0280969193ed6c107e", "Activision, Alan Miller", "AZ-028, AG-028-04", "Robot Tank (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f634893d54e9cabe106e0ec0b7bdcdf", "Retroactive", "", "Qb (2.14) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4f64d6d0694d9b7a1ed7b0cb0b83e759", "20th Century Fox Video Games, John Russell", "11016", "Revenge of the Beefsteak Tomatoes (1983) (20th Century Fox)", "AKA Revenge of the Cherry Tomatoes", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f6702c3ba6e0ee2e2868d054b00c064", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen - Ariola", "EAZ-033 - 711 033-725", "Space Shuttle (1983) (Activision) (PAL)", "A Journey Into Space, Eine Reise ins All", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f781f0476493c50dc578336f1132a67", "", "", "Indy 500 (Unknown) (PAL) (4K)", "Uses Driving Controllers", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "", "" }, { "4f7b07ec2bef5ccffe06403a142f80db", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4f82d8d78099dd71e8e169646e799d05", "", "", "Miniature Golf (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4f89b897444e7c3b36aed469b8836839", "Atari", "CX26190", "BMX Air Master (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4fae08027365d31c558e400b687adf21", "", "", "Qb (V2.17) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "4faeb04b1b7fb0fa25db05753182a898", "", "", "2600 Digital Clock (V x.xx) (PD) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4fbe0f10a6327a76f83f83958c3cbeff", "CCE", "C-816", "Keystone Kappers (1983) (CCE)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "4fc1b85b8074b4b9436d097900e34f29", "John K. Harvey", "", "John K. Harvey's Equalizer (John K. Harvey)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "50200f697aeef38a3ce31c4f49739551", "Mystique - American Multiple Industries, Joel H. Martin", "", "Custer's Revenge (1982) (Mystique) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "502044b1ac111b394e6fbb0d821fca41", "", "", "Hangman Invader 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "502168660bfd9c1d2649d415dc89c69d", "Activision, Bob Whitehead - Ariola", "EAG-019, EAG-019-04I - 711 019-715", "Sky Jinks (1982) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "504688d49a41bf03d8a955512609f3f2", "Thomas Jentzsch", "", "SWOOPS! (TJ)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "PADDLES", "", "", "", "28", "", "", "" }, { "50568c80ac61cab789d9923c9b05b68e", "Ebivision", "", "Merlin's Walls - Standard Edition (1999) (Ebivision)", "Image rotated 90 degrees CW", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5069fecbe4706371f17737b0357cfa68", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Shark Attack (1982) (Apollo) (PAL)", "AKA Lochjaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5079bfbc7b8f5770f84215ed2e3bdd1b", "Omegamatrix (2012)", "", "Genesis Button Tester", "", "Homebrew", "", "", "", "", "", "", "GENESIS", "GENESIS", "", "", "", "", "", "", "" }, { "50a410a5ded0fc9aa6576be45a04f215", "Activision, Bob Whitehead - Ariola", "EAG-019, EAG-019-04I - 711 019-715", "Sky Jinks (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "50c7edc9f9dc0369abcdab3b4efeb5e9", "U.S. Games Corporation - JWDA, Todd Marshall", "", "3-D Zapper (U.S. Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "50ef88f9a5e0e1e6b86e175362a27fdb", "", "", "Multi-Sprite Game V2.4 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "512e874a240731d7378586a05f28aec6", "Tigervision, Rorke Weigandt - Teldec", "7-005", "Marauder (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5131ab3797fe8c127e3e135b18b4d2c8", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "514f911ecff2be5eeff2f39c49a9725c", "Parker Brothers", "931510", "Sky Skipper (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "515046e3061b7b18aa3a551c3ae12673", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "516ffd008057a1d78d007c851e6eff37", "Parker Brothers, Dawn Stockbridge", "PB5910", "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "517592e6e0c71731019c0cebc2ce044f", "Parker Brothers - JWDA, Todd Marshall", "PB5550", "Q-bert's Qubes (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "214", "", "" }, { "517923e655755086a3b72c0b17b430e6", "Tron", "", "Super Tennis (Tron)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5188fee071d3c5ef0d66fb45c123e4a5", "Gameworld", "133-001", "Encounter at L-5 (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 50", "", "", "", "", "" }, { "519f007c0e14fb90208dbb5199dfb604", "Amiga - Video Soft", "", "Depth Charge (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "51de328e79d919d7234cf19c1cd77fbc", "Atari, Mark R. Hahn", "CX2678", "Dukes of Hazzard (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "51e390424f20e468d2b480030ce95d7b", "Video Game Program", "", "Fire Bird (Video Game Program) (PAL)", "AKA Phoenix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "51f15b39d9f502c2361b6ba6a73464d4", "", "", "Amanda Invaders (PD) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "51f211c8fc879391fee26edfa7d3f11c", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "521f4dd1eb84a09b2b19959a41839aad", "Bit Corporation", "PG206", "Bobby Is Going Home (1983) (BitCorp)", "AKA Bobby geht Heim", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "522c9cf684ecd72db2f85053e6f6f720", "Rainbow Vision - Suntek", "SS-008", "Year 1999, The (Rainbow Vision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "52385334ac9e9b713e13ffa4cc5cb940", "CCE", "C-804", "Open, Sesame! (1983) (CCE)", "AKA I Want My Mommy", "", "", "", "", "", "", "", "", "", "", "", "", "", "214", "YES", "" }, { "523f5cbb992f121e2d100f0f9965e33f", "Joe Grand", "", "SCSIcide (1.30) (CGE 2001 Release) (Joe Grand)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "", "" }, { "524693b337f7ecc9e8b9126e04a232af", "", "", "Euchre (19-08-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5256f68d1491986aae5cfdff539bfeb5", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-26-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "525ea747d746f3e80e3027720e1fa7ac", "Activision, Garry Kitchen - Ariola", "EAZ-032 - 771 032-712", "Pressure Cooker (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "525f2dfc8b21b0186cff2568e0509bfc", "Activision, David Crane", "AG-930-04, AZ-030", "Decathlon (1983) (Activision) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "52615ae358a68de6e76467e95eb404c7", "", "", "DJdsl-wopd (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "528400fad9a77fd5ad7fc5fdc2b7d69d", "Starpath Corporation, Stephen H. Landrum, Jon Leupp", "11 AR-4201", "Sword of Saros (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "52a0003efb3b1c49fcde4dbc2c685d8f", "Atari, Alan Miller - Sears", "CX2641 - 99807, 49-75105", "Surround (1977) (Atari) (4K) [a]", "", "", "", "2K", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "52b448757081fd9fabf859f4e2f91f6b", "", "", "Worm War I (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "52bae1726d2d7a531c9ca81e25377fc3", "", "", "Space Instigators (V1.8 Fixed) (20-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "52e1954dc01454c03a336b30c390fb8d", "Retroactive", "", "Qb (2.14) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "52e9db3fe8b5d336843acac234aaea79", "", "", "Fu Kung! (V0.11) (28-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5305f69fbf772fac4760cdcf87f1ab1f", "Jone Yuan Telephonic Enterprise Co", "", "Ski Run (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5324cf5b6dc17af4c64bf8696c39c2c1", "Imagic, Dennis Koble", "IA3203, IX-010-04", "Atlantis (1982) (Imagic) (8K)", "AKA Lost City of Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5336f86f6b982cc925532f2e80aa1e17", "Parker Brothers - JWDA, Todd Marshall, Robin McDaniel, Ray Miller", "PB5060", "Star Wars - Death Star Battle (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "534e23210dd1993c828d944c6ac4d9fb", "M Network, Stephen Tatsumi, Jane Terjung - Kool Aid", "MT4648", "Kool-Aid Man (1983) (M Network)", "AKA Kool Aid Pitcher Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5355f80cacf0e63a49cbf4ade4e27034", "Christian Samuel", "", "Cute Dead Things House (Christian Samuel) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5360693f1eb90856176bd1c0a7b17432", "", "", "Oystron (V2.85) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "537ed1e0d80e6c9f752b33ea7acbe079", "", "", "A-VCS-tec Challenge (beta 5) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5385cf2a04de1d36ab55c73174b84db0", "Paul Slocum", "", "Combat Rock (PD) (Hack)", "Hack of Combat", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "539b7038acec0ccedeae40f238998579", "", "", "Star Fire (25-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "539d26b6e9df0da8e7465f0f5ad863b7", "Atari, Carol Shaw - Sears", "CX2636 - 49-75156", "Video Checkers (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "53b66f11f67c3b53b2995e0e02017bd7", "CCE", "C-1005", "Super Tennis (1983) (CCE)", "AKA RealSports Tennis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "53d181cde2e0219b5754caad246fcb66", "", "", "Missile Demo (1998) (Ruffin Bailey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "53f147b9746fdc997c62f3dd67888ee5", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "540075f657d4b244a1f74da1b9e4bf92", "Bit Corporation", "PGP230", "Festival (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5409d20c1aea0b89c56993aec5dc5740", "", "", "Carnival Shooter (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5428cdfada281c569c74c7308c7f2c26", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "542c6dd5f7280179b51917a4cba4faff", "ZiMAG - Emag - Vidco", "GN-080", "Spinning Fireball (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5438e84b90e50a5362f01cc843b358d4", "Arcadia Corporation, Scott Nelson", "3 AR-4300", "Fireball (1982) (Arcadia) (Prototype)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "543b4b8ff1d616fa250c648be428a75c", "Warren Robinett", "", "Adventure (1978) (Warren Robinett) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "545048ccb045f9efc6cf2b125cd0dfa8", "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp", "AR-4201", "Sword of Saros (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "54785fa29e28aae6038929ba29d33d38", "", "", "Poker Squares (V0.19) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5494b9ee403d9757f0fd1f749e80214a", "Larry Petit", "", "Xenophobe Arcade (2003) (Larry Petit) (Hack)", "Hack of Xenophobe", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "54a1c1255ed45eb8f71414dadb1cf669", "Spectravideo", "SA-212", "Mangia' (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "54bafc299423f5a50b8bc3a797914706", "SOLID Corp. (D. Scott Williamson)", "CX2655*", "Star Castle 2600 (SolidCorp) (PAL)", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "54da3b0b3f43f5b37911c135b9432b49", "", "", "Halloween III Revision (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "54f7efa6428f14b9f610ad0ca757e26c", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Shark Attack (1982) (Apollo)", "AKA Lochjaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "551a64a945d7d6ece81e9c1047acedbc", "Matthias Jaap", "", "Coffee Cup Soccer (Matthias Jaap) (Hack)", "Hack of Pele's Soccer", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "551ef75593ec18d078e8f5cc0229e1c4", "", "", "Star Fire - New Paulstar WIP (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5524718a19107a04ec3265c93136a7b5", "Thomas Jentzsch", "", "RealSports Basketball (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "557e893616648c37a27aab5a47acbf10", "Atari - Axlon, Tod Frye - Heuristica, Augustin Ortiz", "CX26169", "Shooting Arcade (01-16-1990) (Atari) (Prototype) (PAL)", "Uses the Light Gun Controller (left only)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "559317712f989f097ea464517f1a8318", "Panda", "100", "Space Canyon (1983) (Panda)", "AKA Space Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "55949cb7884f9db0f8dfcf8707c7e5cb", "Atari, Ed Logg, Carol Shaw - Sears", "CX2639 - 49-75162", "Othello (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "55ace3c775f42eb46f08bb1dca9114e7", "", "", "Shadow Keep (04-03-2003) (Andrew Towers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "55ef6ab2321ca0c3d369e63d59c059c8", "", "", "Pitfall! (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "55ef7b65066428367844342ed59f956c", "Atari - Roklan, Joe Gaucher, Alex Leavens", "CX2683", "Crazy Climber (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "562acb1b7ff182aba133bda8e21ad7c1", "", "", "Space Treat Deluxe (08-03-2003) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "562bf02f5031d51c6b53b03972a56b22", "", "", "Star Fire - Framework Done (30-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "56300ed31fef018bd96768ccc982f7b4", "HES - Activision", "559", "Rad Action Pak - Kung-Fu Master, Freeway, Frostbite (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5641c0ff707630d2dd829b26a9f2e98f", "Joystik", "", "Motocross (Joystik)", "AKA Motocross Racer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5643ee916f7dc760148fca4db3aa7d10", "", "", "Moon Patrol (Genesis)", "Genesis controller (C is jump)", "Hack of Moon Patrol", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "5678ebaa09ca3b699516dba4671643ed", "Coleco, Sylvia Day, Henry Will IV", "2459", "Mouse Trap (1982) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "568371fbae6f5e5b936af80031cd8888", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "571c6d9bc71cb97617422851f787f8fe", "Activision, David Crane - Ariola", "EAG-004, PAG-004 - 711 004-715", "Fishing Derby (1980) (Activision) (PAL)", "AKA Schneller als der Hai", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "572d0a4633d6a9407d3ba83083536e0f", "Funvision - Fund. International Co.", "", "Busy Police (Funvision)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "575c0fb61e66a31d982c95c9dea6865c", "", "", "Blackjack (Unknown) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "" }, { "57939b326df86b74ca6404f64f89fce9", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "579baa6a4aa44f035d245908ea7a044d", "Jess Ragan", "", "Galaxian Enhanced Graphics (Jess Ragan) (Hack)", "Hack of Galaxian", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "57a66b6db7efc5df17b0b0f2f2c2f078", "Retroactive", "", "Qb (V2.08) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "57c5b351d4de021785cf8ed8191a195c", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari)", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "5835a78a88f97acea38c964980b7dbc6", "", "", "Cosmic Creeps (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "5846b1d34c296bf7afc2fa05bbc16e98", "Atari - Sears", "CX2643 - 6-99815", "Codebreaker (1978) (Atari)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "58513bae774360b96866a07ca0e8fd8e", "Mystique - American Multiple Industries, Joel H. Martin", "1001", "Custer's Revenge (1982) (Mystique)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "585600522b1f22f617652c962e358a5d", "", "", "Multi-Sprite Game V2.2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "585f73010e205ae5b04ee5c1a67e632d", "", "", "Daredevil (V3) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5864cab0bc21a60be3853b6bcd50c59f", "", "", "Commando Raid (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "58746219d8094edff869f0f5c2aeaad5", "Jone Yuan Telephonic Enterprise Co", "", "Bowling (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5894c9c0c1e7e29f3ab86c6d3f673361", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "AZ-033, AZ-033-04", "Space Shuttle (1983) (Activision)", "A Journey Into Space", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "589c73bbcd77db798cb92a992b4c06c3", "Xonox - K-Tel Software - Action Graphics, John Perkins, David Thiel", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL60)", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "58a82e1da64a692fd727c25faef2ecc9", "CCE", "C-824", "Jaw Breaker (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "58c396323ea3e85671e34c98eb54e2a4", "Brian Watson", "", "Color Tweaker (B. Watson)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "58d331c23297ed98663d11b869636f16", "", "", "Fu Kung! (V0.09) (26-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "58e313e2b5613b2439b5f12bb41e3eef", "", "", "Cube Conquest (Demo Interlace) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "590ac71fa5f71d3eb29c41023b09ade9", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (01-05-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "59135f13985b84c4f13cc9e55eec869a", "", "", "Multi-Sprite Game V2.0 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "594dbc80b93fa5804e0f1368c037331d", "Telesys, Alex Leavens", "", "Bouncin' Baby Bunnies (1983) (Telesys) (Prototype)", "AKA Bouncing Baby Monkeys", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5961d259115e99c30b64fe7058256bcf", "Universal Gamex Corporation, Miguel Castillo, H.K. Poon", "GX-001", "X-Man (1983) (Universal)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "59734e1cc41822373845a09c51e6ba21", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "598a4e6e12f8238b7e7555f5a7777b46", "Tigervision", "7-008", "Miner 2049er (1982) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "214", "", "" }, { "599cbf919d47a05af975ad447df29497", "Jake Patterson", "", "Baubles (V0.002) (2001) (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "59b70658f9dd0e2075770b07be1a35cf", "Thomas Jentzsch", "", "Surfer's Paradise (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "59d33e00c07665395209c1e55da0b139", "", "", "Imagic Selector ROM (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "59e53894b3899ee164c91cfa7842da66", "Data Age", "", "Survival Run (1983) (Data Age) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "59e96de9628e8373d1c685f5e57dcf10", "PlayAround - J.H.M.", "204", "Beat 'Em & Eat 'Em (1982) (PlayAround)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 45", "", "", "", "", "" }, { "59f596285d174233c84597dee6f34f1f", "CCE", "C-811", "River Raid (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a0ff99ba10bd26d542e1d6f59f56850", "Champ Games", "CG-04-P", "Super Cobra Arcade (PAL60)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "YES", "" }, { "5a17e30e6e911e74ccd7b716d02b16c6", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a272012a62becabcd52920348c7c60b", "Star Game", "", "Pitfall (Star Game)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a2f2dcd775207536d9299e768bcd2df", "Otto Versand", "781698", "Flippern (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Video Pinball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a5390f91437af9951a5f8455b61cd43", "Retroactive", "", "Qb (0.11) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "5a6febb9554483d8c71c86a84a0aa74e", "CCE", "C-1003", "Donkey Kong Jr (1983) (CCE)", "AKA Donkey Kong Junior", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a734779d797ccef25dc8acfa47244c7", "", "", "Oh No! (Version 2) (18-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a80b857eb8b908ab477ec4ef902edc8", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a81ad4e184050851e63c8e16e3dac77", "Jone Yuan Telephonic Enterprise Co", "Hack", "Sky Diver (Jone Yuan) (Hack)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a8afe5422abbfb0a342fb15afd7415f", "Atari - Bobco, Robert C. Polaro", "CX26155", "Sprint Master (1988) (Atari)", "AKA Sprint 88, Sprint 2000", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a93265095146458df2baf2162014889", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a9685c4d51a6c1d6a9544946d9e8dc3", "AtariAge", "", "Grandma's Revenge (AtariAge)", "Can use driving controller in right port", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5a9d188245aff829efde816fcade0b16", "CCE", "C-808", "Phantom Tank (1983) (CCE) (PAL)", "AKA Tanks But No Tanks", "", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "5acf9865a72c0ce944979f76ff9610f0", "", "", "Dodge Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5ae73916fa1da8d38ceff674fa25a78a", "CCE", "", "Barnstorming (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5aea9974b975a6a844e6df10d2b861c4", "Atari, Dan Hitchens. Mimi Nyden", "CX2656", "SwordQuest - EarthWorld (1982) (Atari)", "AKA Adventure I, SwordQuest I - EarthWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5af9cd346266a1f2515e1fbc86f5186a", "Sega", "002-01", "Sub-Scan (1983) (Sega)", "AKA Subterfuge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b124850de9eea66781a50b2e9837000", "PlayAround - J.H.M.", "205", "Bachelor Party (1982) (PlayAround)", "Uses the paddle controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "AUTO 65", "", "22", "222", "YES", "" }, { "5b574faa56836da0866ba32ae32547f2", "", "", "Tomb Raider 2600 [REV 03] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b5d04887922b430de0b7b2a21f9cd25", "", "", "Omega Race (Genesis)", "Genesis controller (B is thrust, C is fire)", "Hack of Omega Race", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "5b6f5bcbbde42fc77d0bdb3146693565", "", "", "Seaquest (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b7ea6aa6b35dc947c65ce665fde624b", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (2 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b85e987e2b1618769d97ba9182333d0", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (05-12-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b92a93b23523ff16e2789b820e2a4c5", "Activision, Dan Kitchen", "AG-039-04", "Kung-Fu Master (1987) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b98e0536c3f60547dd708ae22adb04b", "Ben Hudman", "", "Donkey Kong Gingerbread Man (Ben Hudman) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5b9c2e0012fbfd29efd3306359bbfc4a", "HES", "", "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5babe0cad3ec99d76b0aa1d36a695d2f", "Coleco - Individeo, Ed Temple", "2654", "Looping (1983) (Coleco) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5bba254e18257e578c245ed96f6b003b", "", "", "Music Effects Demo (21-01-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "5bbab3f3e4b47e3e23f9820765dbb45c", "", "", "Pitfall! (says 1985) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5bc9998b7e9a970e31d2cb60e8696cc4", "Jack Kortkamp", "", "Borgwars Asteroids (2003) (Jack Kortkamp) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "5bcc83677d68f7ef74c1b4a0697ba2a8", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision) (16K)", "", "", "", "4K", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5bd79139a0c03b63f6f2cf00a7d385d2", "Marc de Smet", "", "An Exercise In Minimalism (V1) (1999) (Marc de Smet) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5be03a1fe7b2c114725150be04b38704", "Atari, Alan Miller", "CX2642", "Hunt & Score (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "5c0227ad63300670a647fcebf595ea37", "Josh", "", "Battle for Naboo (Josh) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5c0520c00163915a4336e481ca4e7ef4", "Quelle", "262.794 1", "Wuestenschlacht (1983) (Quelle) (PAL)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5c19f6da638c4c7c1f98d09e63df43e4", "Canal 3 - Intellivision", "", "Cosmic Ark (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5c1b1aa78b7609d43c5144c3b3b60adf", "", "", "Demo Image Series #8 - Two Marios (Different Interlacing) (27-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5c3a6d27c026f59a96b7af91e8b1bf26", "PlayAround - J.H.M.", "", "PlayAround Demo (PlayAround) (1982)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5c618a50dfa23daac97ba459b9ff5206", "Steve Engelhardt", "", "Berzerk Renegade (2002) (Steve Engelhardt) (Hack)", "Hack of Room of Doom", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "5c73693a89b06e5a09f1721a13176f95", "", "", "Wavy Line Test 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5c86e938e0845b9d61f458539e9a552b", "Atari, Alan Miller", "CX26163P", "Surround (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5cbd7c31443fb9c308e9f0b54d94a395", "Spectravideo, Mark Turmell", "SA-217", "Gas Hog (1983) (Spectravideo) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5ce98f22ade915108860424d8dde0d35", "", "", "Hangman Man Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d0e8a25cbd23e76f843c75a86b7e15b", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-07-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d132d121aabc5235dd039dfc46aa024", "", "", "Basketball (208 in 1) (Unknown) (PAL) (Hack)", "Console ports are swapped", "Hack", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "5d25df9dc2cde746ceac48e834cf84a7", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "EAZ-033", "Space Shuttle (1983) (Activision) (SECAM)", "A Journey Into Space", "", "", "FE", "", "", "", "", "", "", "", "", "SECAM", "", "", "", "" }, { "5d2cc33ca798783dee435eb29debf6d6", "Activision - Imagineering, Mike Reidel", "AK-043-04", "Commando (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d799bfa9e1e7b6224877162accada0d", "Spectravision - Spectravideo - Sirius Software, David Lubar", "SA-206", "Challenge of.... Nexar, The (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d8f1ab95362acdf3426d572a6301bf2", "Thomas Jentzsch", "", "SWOOPS! (v0.96) (TJ) (PAL)", "Uses the Joystick (L) and Paddle (R) Controllers", "Homebrew", "", "", "", "", "", "", "", "PADDLES", "", "", "", "28", "", "", "" }, { "5d8fb14860c2f198472b233874f6b0c9", "", "", "Boing! (PD) [a2]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5d9592756425192ec621d2613d0e683d", "CCE", "C-839", "Misterious Thief, A (1983) (CCE) [a]", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5da8fd0b5ed33a360bff37f8b5d0cd58", "Tron", "", "Pole Position (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5dae540347cf0a559962d62604ecf750", "Canal 3 - Intellivision", "", "Freeway (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5db9e5bf663cad6bf159bc395f6ead53", "Goliath - Hot Shot", "83-212", "Time Race (1983) (Goliath) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "5dccf215fdb9bbf5d4a6d0139e5e8bcb", "Froggo", "FG1009", "Sea Hunt (1987) (Froggo)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5de8803a59c36725888346fdc6e7429d", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5df32450b9fbcaf43f9d83bd66bd5a81", "Eric Ball", "", "Atari Logo Playfield Demo (2001) (Eric Ball) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5df559a36347d8572f9a6e8075a31322", "Digivision", "", "Enduro (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e0c37f534ab5ccc4661768e2ddf0162", "Telegames - VSS, Ed Salvo", "5667 A106", "Glacier Patrol (1988) (Telegames)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e1b4629426f4992cf3b2905a696e1a7", "Activision - Bobco, Robert C. Polaro", "AK-049-04", "Rampage! (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e1b7a6078af428ef056fe85a37a95ca", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e1cd11a6d41fc15cf4792257400a31e", "Philip R. Frey", "", "Return of Mario Bros (Philip R. Frey) (Hack)", "Hack of Mario Bros.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e201d6bfc520424a28f129ee5e56835", "Universal Gamex Corporation, Miguel Castillo, H.K. Poon", "GX-001", "X-Man (1983) (Universal) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e2495d43b981010304af55efed1e798", "Jone Yuan Telephonic Enterprise Co", "", "Math Gran Prix (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e2928f089490017e88e9f9e5a881a25", "", "", "Star Fire - Faster Skipping 1 (24-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5e99aa93d0acc741dcda8752c4e813ce", "", "", "2600 Digital Clock (V b2) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5ec73ac7d2ac95ac9530c6d33e713d14", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (2 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "5eeb81292992e057b290a5cd196f155d", "Wizard Video Games - VSS, Ed Salvo", "008", "Texas Chainsaw Massacre, The (1983) (Wizard Video)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5ef303b9f0aa8cf20720c560e5f9baa1", "Atari, Jim Huether", "CX2629, CX2629P", "Sky Diver (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f1b7d5fa73aa071ba0a3c2819511505", "CCE", "", "Cosmic Commuter (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f2b4c155949f01c06507fb32369d42a", "Apollo, Ed Salvo", "AP-1001", "Skeet Shoot (1981) (Apollo) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f316973ffd107f7ab9117e93f50e4bd", "", "", "Commando Raid (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f39353f7c6925779b0169a87ff86f1e", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (1983) (Atari) [a]", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f46d1ff6d7cdeb4b09c39d04dfd50a1", "Atari, Gary Palmer", "CX2661P", "Fun with Numbers (1980) (Atari) (PAL)", "AKA Basic Math", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f560837396387455c9dcb05cdd4b053", "Canal 3 - Intellivision", "", "Eggomania (Canal 3)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 60", "", "", "", "", "" }, { "5f681403b1051a0822344f467b05a94d", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "5f69453a69f21dc49697a80d2e933491", "", "", "Star Fire - Reduced Flickering (06-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f708ca39627697e859d1c53f8d8d7d2", "Atari, Warren Robinett - Sears", "CX2606 - 6-99825, 49-75112", "Slot Racers (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f73e7175474c1c22fb8030c3158e9b3", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f786b67e05fb9985b77d4beb35e06ee", "Atari, Bill Aspromonte, Andrew Fuchs", "CX26120", "Defender II (1987) (Atari) (PAL)", "AKA Stargate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f7ae9a7f8d79a3b37e8fc841f65643a", "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira", "CX26109", "Sorcerer's Apprentice (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5f7de62a408b9de3a1168898298fd31d", "", "", "Super Cobra (Genesis)", "Genesis controller (B is bomb, C is laser)", "Hack of Super Cobra", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "5f950a2d1eb331a1276819520705df94", "20th Century Fox Video Games", "", "Unknown 20th Century Fox Game (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "5f9b62350b31be8bd270d9a241cbd50e", "Telegames", "5658 A088", "Football (1988) (Telegames) (PAL)", "AKA Super Challenge Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5faffe1c4c57430978dec5ced32b9f4a", "Dactari - Milmar", "", "Volleyball (Dactari - Milmar)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "5fb71cc60e293fe10a5023f11c734e55", "", "", "This Planet Sucks (Fix) (27-12-2002) (Greg Troutman)", "", "", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "600d48eef5c0ec27db554b7328b3251c", "", "", "Bars and Text Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6015a9cef783e97e98a2aa2cf070ae06", "Thomas Jentzsch", "", "Battlezone TC (Thomas Jentzsch) (Hack)", "Uses two simultaneous Joystick Controllers, Hack of Battlezone", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "60358edf0c2cc76b1e549e031e50e130", "Manuel Polik", "", "Cyber Goth Galaxian (Manuel Polik) (Hack)", "Hack of Galaxian", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "603c7a0d12c935df5810f400f3971b67", "Bit Corporation", "PG209", "Mr. Postman (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6041f400b45511aa3a69fab4b8fc8f41", "Apollo, Ban Tran", "AP-2010", "Wabbit (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "604e09724555807c28108049efe34a13", "", "", "Sokoban (01-01-2003) (Adam Wozniak)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6058e40ce79d7434c7f7477b29abd4a5", "", "", "Rubik's Cube Demo (23-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "605dcb73d22f4efdb90ef9da2f290f7c", "Atari, Larry Kaplan", "CX26163P", "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "40", "256", "", "" }, { "605fd59bfef88901c8c4794193a4cbad", "Data Age", "", "Secret Agent (1983) (Data Age) (Prototype)", "Uses the Paddle Controllers", "Prototype", "", "", "", "", "", "", "PADDLES", "", "", "01 45", "", "", "", "", "" }, { "606c2c1753051e03c1f1ac096c9d2832", "Jone Yuan Telephonic Enterprise Co", "", "Crackpots (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6076b187a5d8ea7a2a05111c19b5d5cd", "", "", "Fu Kung! (V0.14) (01-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "60a61da9b2f43dd7e13a5093ec41a53d", "VentureVision, Dan Oliver", "VV2001", "Rescue Terra I (1982) (VentureVision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "60bbd425cb7214ddb9f9a31948e91ecb", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "60cd61a2dfccb0e2736434f9792c1672", "Amiga - Video Soft, Frank Ellis, Jerry Lawson", "2110", "3-D Havoc (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "60d304582d33e2957b73eb300a7495bb", "", "", "Jam Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "60e0ea3cbe0913d39803477945e9e5ec", "Atari, Joe Decuir - Sears", "CX2621 - 99806, 6-99806, 49-75104", "Video Olympics (1977) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "AUTO 60", "", "", "", "", "" }, { "613abf596c304ef6dbd8f3351920c37a", "", "", "Boring Pac-Man (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "6141c095d0aee4e734bebfaac939030a", "Rainbow Vision - Suntek", "SS-017", "Mariana (Rainbow Vision) (PAL)", "AKA Seaquest", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61426cee013306e7f7367534ab124747", "", "", "One Blue Bar Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "615a3bf251a38eb6638cdc7ffbde5480", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61621a556ad3228f0234f5feb3ab135c", "", "", "Fu Kung! (V0.05 Cuttle Card Compattle Revision) (14-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61631c2f96221527e7da9802b4704f93", "Activision - Imagineering, Mike Reidel", "AK-043-04", "Commando (1988) (Activision) [different logo]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61719a8bdafbd8dab3ca9ce7b171b9e2", "", "", "Enduro (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61728c6cfb052e62a9ed088c5bf407ba", "", "", "Sprite Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "619de46281eb2e0adbb98255732483b4", "", "", "Time Warp (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "61dbe94f110f30ca4ec524ae5ce2d026", "CCE", "C-820", "Space Invaders (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61e0f5e1cc207e98704d0758c68df317", "Star Game", "007", "Tennis (Star Game)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "61ef8c2fc43be9a04fe13fdb79ff2bd9", "", "", "Gas Gauge Demo - Revisited (2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6205855cc848d1f6c4551391b9bfa279", "", "", "Euchre (Release Candidate 2) (NTSC) (01-10-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "624e0a77f9ec67d628211aaf24d8aea6", "Panda", "108", "Sea Hawk (1983) (Panda)", "AKA Seahawk", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "626d67918f4b5e3f961e4b2af2f41f1d", "Atari", "50008", "Diagnostic Test Cartridge 2.0 (1980) (Atari) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6272f348a9a7f2d500a4006aa93e0d08", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "62899430338e0538ee93397867d85957", "Gameworld", "133-004", "Airlock (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "62921652f6634eb1a0940ed5489c7e18", "", "", "SCSIcide (V1.09) (2001) (Joe Grand)", "", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "", "" }, { "62992392ea651a16aa724a92e4596ed6", "Eric Mooney", "", "Invaders by Erik Mooney (Beta) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "62d1f50219edf9a429a9f004c19f31b3", "JWDA, Todd Marshall", "", "Euro Gen (02-01-83) (JWDA) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "62f74a2736841191135514422b20382d", "", "", "Pharaoh's Curse (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "20", "225", "YES", "" }, { "62ffd175cac3f781ef6e4870136a2520", "", "", "2600 Digital Clock (V x.xx) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63166867f75869a3592b7a94ea62d147", "", "", "Indy 500 (Hack) [a1]", "Hack of Indy 500", "Hack", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "", "", "", "", "", "" }, { "6333ef5b5cbb77acd47f558c8b7a95d3", "Greg Troutman", "", "Dark Mage (Greg Troutman) (PD) (8K)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6337927ad909aa739d6d0044699a916d", "Jeffry Johnston", "", "Radial Pong - Version 2 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6339d28c9a7f92054e70029eb0375837", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6342afe9c9ad1b6120b8f6fb040d0926", "", "", "Move a Blue Blob Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6354f9c7588a27109c66905b0405825b", "Thomas Jentzsch", "", "Amidar DS (2003) (TJ) (Hack)", "Hack of Amidar", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "635cc7a0db33773959d739d04eff96c2", "", "", "Minesweeper (V.90) (Soren Gust) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6362396c8344eec3e86731a700b13abf", "Panda", "109", "Exocet (1983) (Panda)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "637efac676ff063f2fbb0abff77c4fa5", "", "", "Noize Maker Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63811ed69bdbc35c69d8aa7806c3d6e9", "Atari", "CX26163P", "Homerun (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "638cc82ea96f67674595ba9ae05da6c6", "Rainbow Vision - Suntek", "SS-011", "Super Ferrari (Rainbow Vision) (PAL)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63a6eda1da30446569ac76211d0f861c", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "27", "", "", "" }, { "63a7445b1d3046d3cdcdbd488dca38d9", "Rob Kudla", "", "Better Space Invaders (1999) (Rob Kudla) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63c5fef3208bb1424d26cf1ab984b40c", "", "", "Analog Clock (V0.1) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63c7395d412a3cd095ccdd9b5711f387", "Eric Ball", "ELB005", "Skeleton+ (PAL)", "Stereo sound", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63d6247f35902ba32aa49e7660b0ecaa", "", "", "Space War (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63e42d576800086488679490a833e097", "Telesys, Jim Rupp", "1004", "Ram It (1983) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63e783994df824caf289b69a084cbf3e", "David Marli", "", "Fat Albert (David Marli) (Hack)", "Hack of Fast Food", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "63e9e612bbee31045f8d184a4e53f8ec", "ATARITALIA", "", "Moby Blues (2002) (ATARITALIA) (Hack)", "Hack of Mario Bros", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "640a08e9ca019172d612df22a9190afb", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691, CX2691P", "Joust (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "64198bb6470c78ac24fcf13fe76ab28c", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "643e6451eb6b8ab793eb60ba9c02e000", "Salu - Avantgarde Software, Michael Buetepage", "460741", "Ghostbusters II (1992) (Salu) (PAL) [different tune]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "645bf7f9146f0e4811ff9c7898f5cd93", "Xonox - K-Tel Software - VSS, Robert Weatherby", "6230, 6250", "Super Kung-Fu (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6468d744be9984f2a39ca9285443a2b2", "Atari, Ed Logg, Carol Shaw", "CX26163P", "Reversi (32 in 1) (1988) (Atari) (PAL)", "AKA Othello", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "647162cceb550fd49820e2206d9ee7e8", "", "", "Skeleton (NTSC) (2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "64b8e19c767191ccdc97acc6904c397b", "Jeffry Johnston", "", "Radial Pong - Version 6 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "64ca518905311d2d9aeb56273f6caa04", "CCE", "", "Cubo Magico (CCE)", "AKA Cubicolor", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "64d43859258dc8ca54949e9ff4174202", "Thomas Jentzsch", "", "Lilly Adventure (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "230", "", "" }, { "64fab9d15df937915b1c392fc119b83b", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (05-20-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "650df778c6ce22d3fd1a7c33c565bcc3", "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae", "CX2694", "Pole Position (1983) (Atari)", "Genesis controller (B is high gear, C is low gear, left difficulty switch swaps gear buttons)", "Hack of Pole Position", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "651d2b6743a3a18b426bce2c881af212", "CCE", "C-812", "Pac Man (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6522717cfd75d1dba252cbde76992090", "Home Vision - Gem International Corp. - VDI", "VCS83102", "War 2000 (1983) (Home Vision) (PAL)", "AKA Astrowar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6538e454b0498ad2befe1ef0f87815c0", "Joe Grand", "", "SCSIcide (v1.2) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "", "" }, { "65490d61922f3e3883ee1d583ce10855", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692, CX2692P", "Moon Patrol (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "65562f686b267b21b81c4dddc129d724", "", "", "Euchre (28-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "655c84e5b951258c9d20f0bf2b9d496d", "", "", "2600_2003 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "656dc247db2871766dffd978c71da80c", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (1980) (Sears)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "PADDLES", "", "AUTO 60", "", "", "", "", "" }, { "65917ae29a8c9785bb1f2acb0d6aafd0", "", "", "Junkosoft One Year Demo (1999) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6596b3737ae4b976e4aadb68d836c5c7", "Digivision", "", "Defender (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "659a20019de4a23c748ec2292ea5f221", "Retroactive", "", "Qb (V2.05) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "65b106eba3e45f3dab72ea907f39f8b4", "Sparrow - HomeComputer Software, Dan Schafer, Glenn Stohel, Jon Tedesco", "GCG 1001T", "Music Machine, The (1983) (Sparrow)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 45", "", "", "", "", "" }, { "65ba1a4c643d1ab44481bdddeb403827", "Quelle", "876.013 4", "Katastrophen-Einsatz (1983) (Quelle) (PAL)", "AKA M.A.S.H.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "65bd29e8ab1b847309775b0de6b2e4fe", "Coleco, Ed English", "2667", "Roc 'n Rope (1984) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "65c6406f5af934590097c8c032ebb482", "", "", "Three Hugger (Pave Demo) (20-12-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6604f72a966ca6b2df6a94ee4a68eb82", "", "", "MegaMania (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "662eca7e3d89175ba0802e8e3425dedb", "", "", "Hangman Pac-Man Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "66362890eb78d6ea65301592cce65f5b", "", "", "Euchre (13-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "663ef22eb399504d5204c543b8a86bcd", "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner", "4L1720, 4L1721, 4L1722, 4L2276", "Wizard of Wor (1982) (CBS Electronics) (PAL)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "YES", "" }, { "6651e2791d38edc02c5a5fd7b47a1627", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (04-05-1984) (Parker Bros) (Prototype) (8K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "665b8f8ead0eef220ed53886fbd61ec9", "Telesys, Don Ruffcorn, Jack Woodman", "1003", "Fast Food (1982) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "66706459e62514d0c39c3797cbf73ff1", "Video Gems", "VG-05", "Treasure Below (1983) (Video Gems) (PAL)", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "" }, { "6672de8f82c4f7b8f7f1ef8b6b4f614d", "Videospielkassette - Ariola", "PGP237", "Angeln I (Ariola) (PAL)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "668dc528b7ea9345140f4fcfbecf7066", "Gakken", "001", "Pooyan (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6697f177847c70505824422e76aad586", "", "", "Tennis (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "669840b0411bfbab5c05b786947d55d4", "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee", "CX26117", "Obelix (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "66b89ba44e7ae0b51f9ef000ebba1eb7", "Atari - CCW, Stephan R. Keith, Laura Scholl, Preston Stuart", "CX26106", "Grover's Music Maker (01-18-1983) (Atari) (Prototype)", "Uses Keypad Controller", "Prototype", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, { "66b92ede655b73b402ecd1f4d8cd9c50", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "66bc1bef269ea59033928bac2d1d81e6", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (Preview) (1982) (Arcadia)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "66c2380c71709efa7b166621e5bb4558", "Parker Brothers, Dave Engman, Dawn Stockbridge", "931509", "Tutankham (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "66c4e0298d4120df333bc2f3e163657e", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (2 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "66fcf7643d554f5e15d4d06bab59fe70", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6706a00f9635508cfeda20639156e66e", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "672012d40336b403edea4a98ce70c76d", "", "", "Spider Kong (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "675ae9c23fa1aae376cea86cad96f9a5", "", "", "Poker Squares (V0.25) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "67631ea5cfe44066a1e76ddcb6bcb512", "", "", "Termool (Unknown) (PAL)", "AKA Turmoil", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "67684a1d18c85ffa5d82dab48fd1cb51", "Tigervision, Warren Schwader - Teldec", "7-003", "Threshold (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "678c1d71a1616d9d022f03d8545b64bb", "", "", "Demo Image Series #11 - Donald And Mario (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "67931b0d37dc99af250dd06f1c095e8d", "CommaVid, Irwin Gaines", "CM-004", "Room of Doom (1982) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "679d30c7886b283cbe1db4e7dbe5f2a6", "Colin Hughes", "", "Puzzle (Colin Hughes) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "679e910b27406c6a2072f9569ae35fc8", "Data Age", "DA1002", "Warplock (1982) (Data Age)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01 40", "", "", "", "YES", "" }, { "67bd3d4dc5ac6a42a99950b4245bdc81", "Retroactive", "", "Qb (2.11) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "67c05ae94bf8b83a666c3ae2c4bc14de", "Atari", "CX26163P", "NFL Football (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "67cdde4176e0447fc45a71e0a1cdd288", "Telegames - VSS, Ed Salvo", "5665 A016", "Glacier Patrol (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "67ce6cdf788d324935fd317d064ed842", "Retroactive", "", "Qb (V2.09) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "67cf913d1df0bf2d7ae668060d0b6694", "", "", "Hangman Monkey 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6803fa7c2c094b428b859a58dc1dd06a", "Retroactive", "", "Qb (0.11) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6805734a0b7bcc8925d9305b071bf147", "Bit Corporation", "PGP229", "Kung Fu (4 Game in One Dark Green) (1983) (BitCorp) (PAL)", "AKA Karate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "681206a6bde73e71c19743607e96c4bb", "", "", "Casino (Unknown) (PAL)", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "49", "", "", "" }, { "683bb0d0f0c5df58557fba9dffc32c40", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia) [a]", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "683dc64ef7316c13ba04ee4398e2b93a", "Ed Federmeyer", "", "Edtris (1995) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "68449e4aaba677abcd7cde4264e02168", "", "", "Horizonal Color Bars Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6847ce70819b74febcfd03e99610243b", "", "", "Ruby Runner 4A50", "", "", "", "", "", "", "", "", "", "", "", "", "", "27", "", "YES", "" }, { "68489e60268a5e6e052bad9c62681635", "Bit Corporation", "PG201", "Sea Monster (1982) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "68597264c8e57ada93be3a5be4565096", "Data Age", "DA1005", "Bugs (1982) (Data Age)", "Uses the Paddle Controllers", "Uncommon", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 50", "", "", "", "", "" }, { "685e9668dc270b6deeb9cfbfd4d633c3", "CommaVid, Irwin Gaines - Ariola", "CM-004 - 712 004-720", "Room of Doom (1982) (CommaVid) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "68760b82fc5dcf3fedf84376a4944bf9", "CCE", "C-860", "Laser Gate (1983) (CCE)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "687c23224e26f81c56e431c24faea36d", "", "", "Qb (Simple Background Animation) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "68878250e106eb6c7754bc2519d780a0", "CCE", "C-809", "Squirrel (1983) (CCE)", "AKA Snail Against Squirrel", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "68c80e7e1d30df98a0cf67ecbf39cc67", "Hozer Video Games", "", "Gunfight 2600 - One Step Forward & Two Steps Back (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "68cd2adc6b1fc9a1f263ab4561112f30", "Thomas Jentzsch", "", "Boulderdash Demo (09-12-2002) (TJ)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "68feb6d6ff63e80df1302d8547979aec", "", "", "Starfield Demo 2 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "690a6049db78b9400c13521646708e9c", "King Tripod Enterprise Co.", "SS - 007", "Space Raid (King Tripod) (PAL)", "AKA Challenge of.... Nexar, The", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6913c90002636c1487538d4004f7cac2", "Atari - CCW", "CX26131", "Monster Cise (1984) (Atari) (Prototype)", "Uses the Keypad Controllers (left only)", "Prototype", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, { "691d67910b08b63de8631901d1887c1f", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "692202772d8b38ccf85a90c8003a1324", "", "", "Zi - The Flie Buster (2002) (Fernando Mora) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "693137592a7f5ccc9baae2d1041b7a85", "", "", "Qb (V2.02) (Stella) (2001) (Retroactive) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6979f30204149be3e227558cffe21c1d", "Atari", "CX26163P", "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Miniature Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6982854657a2cc87d712f718e402bf85", "Zellers", "", "Earth Attack (Zellers)", "AKA Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "698f569eab5a9906eec3bc7c6b3e0980", "SpkLeader", "", "Demons! (2003) (SpkLeader) (Hack)", "Hack of Phoenix", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "69974dd5d6420b90898cde50aec5ef39", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "69df0411d4d176e558017f961f5c5849", "CCE", "C-831", "Cosmic Ark (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "69e79b1352b9ee1754bbe63b4a7062c3", "Barry Laws Jr.", "", "Pink Floyd - The Wall (2003) (Barry Laws Jr.) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "69ebf910ab9b63e5b8345f016095003b", "", "", "Maze Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "69fac82cd2312dd9ce5d90e22e2f070a", "Spectravision - Spectravideo - Quelle", "SA-202 - 412.851 8", "Planet Patrol (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6a03c28d505bab710bf20b954e14d521", "", "", "Pressure Gauge 2 Beta (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6a07836c382195dd5305ce61d992aaa6", "Apollo, Larry Martin", "AP-2008", "Guardian (1982) (Apollo) (Prototype)", "Uses the Paddle Controller (left only)", "Prototype", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "6a091b8ffeacd0939850da2094b51564", "", "", "Vertically Scrolling Playfield (02-02-2003) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6a2c68f7a77736ba02c0f21a6ba0985b", "Atari, Larry Wagner, Bob Whitehead", "", "Computer Chess (07-07-1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6a3b0c33cf74b1e213a629e3c142b73c", "Cody Pittman", "", "Cory The Interviewer (Cody Pittman) (Hack)", "Hack of Ghostbusters", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6a76d5f0ed721639474aa9bbde69ebf0", "", "", "Play Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6a82b8ecc663f371b19076d99f46c598", "Activision, Larry Miller - Ariola", "EAX-026, EAX-026-04B, EAX-026-04I - 711 026-725", "Enduro (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6a882fb1413912d2ce5cf5fa62cf3875", "Video Game Cartridge - Ariola", "TP-605", "Dragon Defender (Ariola) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6a8c6940d3be6fd01274363c4d4b298e", "", "", "Spy Hunter (Genesis)", "Genesis controller (C is oil/smoke)", "Hack of Spy Hunter", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "6a9b30ca46b0dba9e719f4cbd340e01c", "", "", "Frostbite (Unknown) (PAL) (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "240", "", "" }, { "6a9e0c72fab92df70084eccd9061fdbd", "CCE", "C-835", "Beany Bopper (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6aa66e9c3eea76a0c40ef05513497c40", "", "", "Hangman Ghost Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6ac3fd31a51730358708c7fdc62487f8", "Matthias Jaap", "", "PC Invaders (Matthias Jaap) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6ae4dc6d7351dacd1012749ca82f9a56", "Atari - GCC, Jaques Hugon, Seth Lipkin", "CX26125, CX26127", "Track and Field (1984) (Atari)", "Uses the Track & Field Controller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6b01a519b413f8cfa2f399f4d2841b42", "", "", "Aphex Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6b1fc959e28bd71aed7b89014574bdc2", "Bit Corporation", "PG203", "Phantom Tank (1982) (BitCorp) (PAL)", "AKA Tanks But No Tanks", "", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "6b4eb5b3df80995b8d9117cb7e9aeb3c", "Gameworld, J. Ray Dettling", "133-006", "Journey Escape (1983) (Gameworld) (PAL)", "AKA Rock 'n' Roll Escape", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6b683be69f92958abe0e2a9945157ad5", "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Steven B. Sidley, Tom Sloper", "VC2007", "Entombed (1983) (U.S. Games)", "Released as Name That Game for a contest (winning name was Entombed)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6b6ca32228ae352b4267e4bd2cddf10c", "", "", "Pac-Man 4 (Pac-Man Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "6b71f20c857574b732e7a8e840bd3cb2", "", "", "Frostbite (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6b72b691ea86f61438ed0d84c4d711de", "", "", "Fishing Derby (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6b75f8fa4fd011a6698c58315f83d2ac", "Thomas Jentzsch", "", "Sprintmaster DC (TJ)", "Uses the Driving Controllers, Hack of Sprintmaster (Atari)", "New Release (Hack)", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "", "" }, { "6b7a56b6ac2ca4bf9254474bf6ed7d80", "", "", "Horizonal Color Bars Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6b7e1c11448c4d3f28160d2de884ebc8", "Zirok", "", "Fast Food (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6b8fb021bb2e1f1e9bd7ee57f2a8e709", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum) (PD) [a]", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6bb09bc915a7411fe160d0b2e4d66047", "Atari", "CX26163P", "UFO (32 in 1) (1988) (Atari) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6bb22efa892b89b69b9bf5ea547e62b8", "Dynacom", "", "Megamania (1982) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6bde3f6ac31aceef447ce57d4d2c2ec0", "Piero Cavina", "", "Mondo Pong V1 (Piero Cavina) (PD)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "01", "", "", "", "", "" }, { "6c128bc950fcbdbcaf0d99935da70156", "Digitel", "", "Volleyball (1983) (Digitel)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6c1553ca90b413bf762dfc65f2b881c7", "Quelle", "343.073 3", "Winterjagd (1983) (Quelle) (PAL)", "AKA Ski Hunt", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6c1f3f2e359dbf55df462ccbcdd2f6bf", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6c25f58fd184632ca76020f589bb3767", "Dynacom", "", "Beat 'Em & Eat 'Em (1983) (Dynacom)", "Uses the Paddle Controller (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 45", "", "", "", "", "" }, { "6c449db9bbbd90972ad1932d6af87330", "", "", "20 Sprites at Once Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6c658b52d03e01828b9d2d4718a998ac", "", "", "Hangman Invader Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6c76fe09aa8b39ee52035e0da6d0808b", "Atari, Brad Stewart", "CX2622, CX2622P", "Breakout (1978) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 60", "", "", "", "", "" }, { "6c85098518d3f94f7622c42fd1d819ac", "Suntek", "SS-028", "Firebug (Suntek) (PAL)", "AKA Spinning Fireball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6c91ac51421cb9fc72c9833c4f440d65", "ITT Family Games", "554-33 375", "Cosmic Town (1983) (ITT Family Games) (PAL)", "AKA Base Attack (Perry Rhodan-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6c9a32ad83bcfde3774536e52be1cce7", "", "", "Space Treat (NTSC) (13-08-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6cbe945e16d9f827d0d295546ac11b22", "", "", "Gunfight 2600 - AI (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6ccd8ca17a0e4429b446cdcb66327bf1", "", "", "RPG Engine (12-05-2003) (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6cd1dc960e3e8d5c5e0fbe67ab49087a", "", "", "Vertical Playfield Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6cd506509e8fd5627f55603780e862a8", "Greg Troutman", "", "Dark Mage (SuperCharger) (Greg Troutman) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6ce2110ac5dd89ab398d9452891752ab", "Funvision - Fund. International Co.", "", "Persian Gulf War (Funvision)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6cea35ded079863a846159c3a1101cc7", "", "", "Atlantis (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6ceb7d6a54e9a5e62d26874d1cc88dbc", "Video Soft", "", "Atom Smasher (1984) (Video Soft) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6cf054cd23a02e09298d2c6f787eb21d", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6d218dafbf5a691045cdc1f67ceb6a8f", "Robin Harbron", "", "6 Digit Score Display (1998) (Robin Harbron) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6d475019ea30d0b29f695e9dcfd8f730", "Eric Mooney", "", "Invaders by Erik Mooney (Alpha 2) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6d74ebaba914a5cfc868de9dd1a5c434", "", "", "Fortress (Smooth Version) (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6d842c96d5a01967be9680080dd5be54", "Activision, David Crane", "AB-035-04", "Pitfall II (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6d8a04ee15951480cb7c466e5951eee0", "Zirok", "", "Kanguru (1983) (Zirok)", "AKA Kangaroo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6d9afd70e9369c2a6bff96c4964413b7", "", "", "Time Warp (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6dda84fb8e442ecf34241ac0d1d91d69", "Atari - GCC, Douglas B. Macrae", "CX2677", "Dig Dug (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6de924c2297c8733524952448d54a33c", "CCE", "C-1006", "Moon Patrol (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6dfad2dd2c7c16ac0fa257b6ce0be2f0", "Parker Brothers, Larry Gelberg", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6e179eee3d4631a7434d40cf7aeea6e8", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6e19428387686a77d8c8d2f731cb09e0", "", "", "Purple Cross Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6e372f076fb9586aff416144f5cfe1cb", "Atari, Tod Frye - Sears", "CX2646 - 49-75185", "Pac-Man (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6e4521989a60a0ddf4ff1fc6e6e5fc3d", "", "", "Star Fire (01-05-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6e59dd52f88c00d5060eac56c1a0b0d3", "Atari, Bob Smith", "CX2648", "Video Pinball (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6e5d5ba193d2540aec2e847aafb2a5fb", "Retroactive", "", "Qb (2.14) (Retroactive) (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6e7ed74082f39ad4166c823765a59909", "", "", "Poker Squares (V0.14) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6ed5012793f5ddf4353a48c11ea9b8d3", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Down on the Line (3 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "PADDLES", "", "01 70", "", "", "", "", "" }, { "6ed6bda5c42b2eb7a21c54e5b3ace3e3", "Canal 3 - Intellivision", "", "Ice Hockey (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6efe876168e2d45d4719b6a61355e5fe", "Bit Corporation", "PG207", "Mission 3,000 A.D. (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6f084daf265599f65422ef4173b69bc7", "", "", "Music Kit (V2.0) - Song Player (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "6f2aaffaaf53d23a28bf6677b86ac0e3", "U.S. Games Corporation - Vidtec - JWDA, Garry Kitchen", "VC1001", "Space Jockey (1982) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6f3e3306da2aa6e74a5e046ff43bf028", "", "", "Defender Arcade (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender 2", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "6f74ed915ffe73b524ef0f63819e2a1d", "Eckhard Stolberg", "", "An Exercise In Minimalism (V2) (1999) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6f75d72e4cf996100ccdd163d57bdac2", "", "", "Star Fire (200203) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6fa0ac6943e33637d8e77df14962fbfc", "Imagic, Rob Fulop", "", "Cubicolor (1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6fac680fc9a72e0e54255567c72afe34", "", "", "Superman (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6fbd05b0ad65b2a261fa154b34328a7f", "", "", "Boardgame Demo (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6fc0176ccf53d7bce249aeb56d59d414", "Rainbow Vision - Suntek", "SS-004", "Pyramid War (Rainbow Vision) (PAL)", "AKA Chopper Command", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6fc27a9233fc69d28d3f190b4ff80f03", "", "", "UFO #6 (Charles Morgan) (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6fc394dbf21cf541a60e3b3631b817f1", "Imagic, Bob Smith", "720020-2A, IA3611P", "Dragonfire (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6fd7c7057eeab273b29c7aafc7429a96", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6fe67f525c39200a798985e419431805", "Atari - GCC, Kevin Osborn", "CX2689, CX2689P", "Kangaroo (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "6ff4156d10b357f61f09820d03c0f852", "Atari, Larry Kaplan - Sears", "CX2612 - 99804, 49-75103", "Street Racer (1977) (Atari) (4K)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 60", "", "", "", "", "" }, { "6ffc95108e5add6f9b8abcaf330be835", "Charles Morgan", "", "TP Bug (Charles Morgan) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "700a786471c8a91ec09e2f8e47f14a04", "Activision", "", "Hard-Head (1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "703d32062436e4c20c48313dff30e257", "", "", "Moving Maze Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "703f0f7af350b0fa29dfe5fbf45d0d75", "Bit Corporation", "P460", "4 Game in One Dark Green (1983) (BitCorp) (PAL)", "Rodeo Champ, Bobby is Going Home, Open Sesame, Festival", "", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "705fe719179e65b0af328644f3a04900", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "706e3cc4931f984447213b92d1417aff", "", "", "Joustpong (06-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "707ecd80030e85751ef311ced66220bc", "", "", "Double-Height 6-Digit Score Display (Background Color Change) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7096a198531d3f16a99d518ac0d7519a", "Telesys, Jim Rupp", "1004", "Ram It (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "709910c2e83361bc4bf8cd0c20c34fbf", "Rainbow Vision - Suntek", "SS-006", "Netmaker (Rainbow Vision) (PAL)", "AKA Amidar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "70a8480cfaf08776e5420365732159d2", "Rob Kudla", "", "Horizontally Scrolling Playfield Thing (Rob Kudla) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "70ce036e59be92821c4c7fd735ec6f68", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "70d14c66c319683b4c19abbe0e3db57c", "", "", "Oystron (V2.82) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "710497df2caab69cdcc45e919c69e13f", "Arcadia Corporation, Dennis Caswell", "5 AR-4200", "Labyrinth (Escape from the Mindmaster Beta) (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "713fde2af865b6ec464dfd72e2ebb83e", "", "", "Challenge (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "71464c54da46adae9447926fdbfc1abe", "M Network - APh Technological Consulting, Bruce Pedersen - INTV", "MT5663", "Lock 'n' Chase (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "714e13c08508ee9a7785ceac908ae831", "Home Vision - Gem International Corp. - VDI", "VCS83123", "Parachute (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "715dbf2e39ba8a52c5fe5cdd927b37e0", "Amiga - Video Soft", "3135", "S.A.C. Alert (1983) (Amiga) (Prototype)", "Uses Joyboard", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "715dd9e0240638d441a3add49316c018", "Atari", "", "128-in-1 Junior Console (Chip 2 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7187118674ff3c0bb932e049d9dbb379", "Zirok", "", "Keystone Keypers (1983) (Zirok)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "718ae62c70af4e5fd8e932fee216948a", "Data Age, J. Ray Dettling", "112-006", "Journey Escape (1983) (Data Age)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "718ee85ea7ec27d5bea60d11f6d40030", "Thomas Jentzsch", "", "Ghostbusters II (1992) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7197b6cbde6ecd10376155e6b848e80d", "Piero Cavina", "", "Multi-Sprite Game V2.1 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "71b193f46c88fb234329855452dfac5b", "Digitel", "", "Atlantis (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "71d005b60cf6e608d04efb99a37362c3", "Atari, Larry Kaplan", "CX2643", "Codebreaker (1978) (Atari) (PAL) (4K) [a]", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "57", "", "", "" }, { "71f09f128e76eb14e244be8f44848759", "Funvision - Fund. International Co.", "", "Time Race (Funvision) (PAL)", "AKA Time Warp", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "71f8bacfbdca019113f3f0801849057e", "Atari, Dan Hitchens", "CX26126", "Elevator Action (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72097e9dc366900ba2da73a47e3e80f5", "", "", "Euchre (15-06-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "721a5567f76856f6b50a6707aa8f8316", "Activision, David Crane, Dan Kitchen", "EAG-108-04, EAZ-108-04B", "Ghostbusters (1985) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72305c997f2cec414fe6f8c946172f83", "Arcadia Corporation, Dennis Caswell", "AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "724613effaf7743cbcd695fab469c2a8", "", "", "Super-Ferrari (Unknown)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "728152f5ae6fdd0d3a9b88709bee6c7a", "Spectravideo, Mark Turmell", "SA-217", "Gas Hog (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72876fd7c7435f41d571f1101fc456ea", "Quelle", "688.383 9", "Die Ente und der Wolf (1983) (Quelle) (PAL)", "AKA Pooyan", "", "", "", "", "", "", "", "", "", "", "", "", "26", "256", "", "" }, { "72a46e0c21f825518b7261c267ab886e", "Xonox - K-Tel Software - Computer Magic", "99005, 6220, 6250", "Robin Hood (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "31", "220", "", "" }, { "72a5b5052272ac785fa076709d16cef4", "", "", "KC Munckin (29-01-2003) (J. Parlee)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72bda70c75dfa2365b3f8894bace9e6a", "Thomas Jentzsch", "", "Atlantis (TJ) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72d0acb5de0db662de0360a6fc59334d", "", "", "Cosmic Ark (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72db1194b1cc7d45b242f25eb1c148d3", "", "", "Pac-Man (1981) (Atari) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "72fd08deed1d6195942e0c6f392e9848", "HES", "0701-406", "2 Pak Special - Wall Defender, Planet Patrol (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "72ffbef6504b75e69ee1045af9075f66", "Atari, Richard Maurer - Sears", "CX2632 - 49-75153", "Space Invaders (1980) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73158ea51d77bf521e1369311d26c27b", "Zellers", "", "Challenge (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "25", "", "", "" }, { "73521c6b9fed6a243d9b7b161a0fb793", "Atari, Tom Reuterdahl", "CX26163P", "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL)", "AKA Miniature Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "736388d73198552d77d423962000006f", "Dactari", "", "Tennis (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73a710e621d44e97039d640071908aef", "", "", "Barber Pole Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73aa02458b413091ac940c0489301710", "Quelle - Otto Versand", "463.574 4 - 781393, 986153", "Kampf dem Steinfresser (1983) (Quelle) (PAL)", "Boom Bang (AKA Crackpots)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73b4e8f8b04515d91937510e680214bc", "", "", "Rubik's Cube Demo 3 (24-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73c545db2afd5783d37c46004e4024c2", "CBS Electronics - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "4L1767, 4L1768, 4L1769, 4L1770", "Smurf - Schtroumpfs (1983) (CBS Electronics) (PAL)", "Pitufo", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73c839aff6a055643044d2ce16b3aaf7", "Activision, Alan Miller - Ariola", "EAX-016, PAX-016 - 711 016-725", "StarMaster (1982) (Activision) (PAL)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73cb1f1666f3fd30b52b4f3d760c928f", "", "", "Mines of Minos (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "225", "YES", "" }, { "73e66e82ac22b305eb4d9578e866236e", "Jone Yuan Telephonic Enterprise Co", "", "Unknown Datatech Game (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "73efa9f3cbe197f26e0fb87132829232", "CCE", "C-858", "Tennis (1983) (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "74023e0f2e739fc5a9ba7caaeeee8b6b", "Jone Yuan Telephonic Enterprise Co", "", "Fishing Derby (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "740a7fa80f52cc7287ba37677afb6b21", "", "", "Double Dragon (PAL) (Genesis)", "Genesis controller (C is jumpkick)", "Hack of Double Dragon", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "740b47df422372fbef700b42cea4e0bf", "", "", "Dizzy Wiz (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "740f39e71104e90416c29a73560b9c6b", "Atari", "TE016643", "Diagnostic Test Cartridge 2.6P (1982) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "742de93b8d849220f266b627fbabba82", "", "", "SCSIcide (25-02-2001) (Chris Wilkson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7450ae4e10ba8380c55b259d7c2b13e8", "", "", "Register Twiddler Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7454786af7126ccc7a0c31fcf5af40f1", "", "", "Tanks But No Tanks (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7465b06b6e25a4a6c6d77d02242af6d6", "Atari", "CX26193", "8 in 1 (01-16-92) (Atari) (Prototype)", "Game 2 is Centipede, but doesn't work", "Prototype", "", "8IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7481f0771bff13885b2ff2570cf90d7b", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "749fec9918160921576f850b2375b516", "Spectravision - Spectravideo", "SA-205", "China Syndrome (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "74ca9bdc91ee387a5bd929b73aec5c2c", "", "", "Star Fire - New Shields (03-04-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "74d072e8a34560c36cacbc57b2462360", "Sancho - Tang's Electronic Co.", "TEC002", "Seahawk (1982) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "74ebaca101cc428cf219f15dda84b6f8", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "74f623833429d35341b7a84bc09793c0", "Zellers", "", "Radar (Zellers)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75028162bfc4cc8e74b04e320f9e6a3f", "Atari, Greg Easter, Mimi Nyden", "CX26107", "Snow White (02-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7511c34518a9a124ea773f5b0b5c9a48", "", "", "Donkey Kong (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75169c08b56e4e6c36681e599c4d8cc5", "M Network - APh Technological Consulting, Hal Finney - INTV", "MT5666", "Astroblast (1982) (M Network)", "Can also use left joystick", "Uncommon", "", "", "", "", "", "", "PADDLES", "", "YES", "AUTO 55", "", "", "", "", "" }, { "753375d183c713cfa0aa7298d1f3067b", "Arcadia Corporation, Steve Hales, Stephen Harland Landrum", "AR-4102", "Suicide Mission (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7550b821ee56fb5833dca2be88622d5a", "", "", "Multiple Moving Objects Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75511bb694662301c9e71df645f4b5a7", "Activision, Bob Whitehead - Ariola", "EAG-011, PAG-011 - 711 011-715", "Stampede (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "755fed16b48e81de05130708a905d00d", "SnailSoft", "", "Comitoid beta 3 (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "756ca07a65a4fbbedeb5f0ddfc04d0be", "Atari, Jim Huether", "CX2629, CX2629P", "Sky Diver (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7574480ae2ab0d282c887e9015fdb54c", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1984) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7576dd46c2f8d8ab159d97e3a3f2052f", "Goliath - Hot Shot", "83-112", "Time Machine (1983) (Goliath) (PAL)", "AKA Asteroid Fire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "757f529026696e13838364dea382a4ed", "Activision, David Crane - Ariola", "EAX-014, PAX-014, EAX-014-04B, EAX-014-04I - 711 014-720", "Grand Prix (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75a303fd46ad12457ed8e853016815a0", "ZiMAG - Emag - Vidco", "715-111 - GN-060", "Immies & Aggies (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75b22fdf632d76e246433db1ebccd3c4", "", "", "Skeleton+ (05-05-2003) (Eric Ball) (PAL)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75b557be7f08db84ec5b242207b9f241", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75e276ba12dc4504659481c31345703a", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75e8d8b9e9c5c67c2226dbfd77dcfa7d", "", "", "2600 Digital Clock (V b1) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75ea128ba96ac6db8edf54b071027c4e", "Atari, David Crane", "CX26163P", "Slot Machine (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "75ea60884c05ba496473c23a58edf12f", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari) (PAL) [a]", "ROM must be started in bank 0", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "75ee371ccfc4f43e7d9b8f24e1266b55", "Atari, Greg Easter, Mimi Nyden", "CX26107", "Snow White (11-09-1982) (Atari) (Prototype)", "ROM must be started in bank 0", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7608abdfd9b26f4a0ecec18b232bea54", "Atari, Bob Whitehead", "CX26163P", "NFL Football (32 in 1) (1988) (Atari) (PAL)", "AKA Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7623a639a6fffdb246775fe2eabc8d01", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7628d3cadeee0fd2e41e68b3b8fbe229", "Atari", "CX26163P", "Fishing Derby (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7648e72a5b5899076688df18a1ddcf72", "CBS Electronics, Richard K. Balaska Jr., Andy Frank, Stuart Ross", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics) (Prototype)", "Black Box", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "76809eb1ee0db8a318308a5cdda0f4e2", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (1983) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "769ddc995dbb9edb8167efcea9f34a7c", "", "", "H.E.R.O. (Genesis)", "Genesis controller (B is laser, C is dynamite)", "Hack of H.E.R.0.", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "76a9bf05a6de8418a3ebc7fc254b71b4", "VideoSoft, Jerry Lawson, Dan McElroy", "VS1008", "Color Bar Generator (1984) (VideoSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "76c685d1a60c0107aa54a772113a2972", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (3 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "76c88341017eae660efc6e49c4b6ab40", "", "", "Indiana Pitfall (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "76ee917d817ef9a654bc4783e0273ac4", "Otto Versand", "311377", "Fox & Goat (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Nuts", "", "", "", "", "", "", "", "", "", "", "", "", "45", "256", "", "" }, { "76f53abbbf39a0063f24036d6ee0968a", "M Network, David Akers, Joe 'Ferreira' King, Patricia Lewis Du Long, Jeff Ratcliff - INTV", "MT7045", "Bump 'n' Jump (1983) (M Network)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "76f66ce3b83d7a104a899b4b3354a2f2", "UA Limited", "", "Cat Trax (1983) (UA Limited) (1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "77057d9d14b99e465ea9e29783af0ae3", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision)", "AKA Drag Strip", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "7732e4e4cc2644f163d6650ddcc9d9df", "HES", "771-333", "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7778ac65d775a079f537e97cbdad541c", "", "", "Spider Fighter (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "777aece98d7373998ffb8bc0b5eff1a2", "", "", "2600 Collison Demo 2 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "77887e4192a6b0a781530e6cf9be7199", "Atari", "CX2604", "Space War (1978) (Atari) [b1]", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "77be57d872e3f5b7ecf8d19d97f73281", "", "", "Basketball (208 in 1) (Unknown) (PAL)", "Console ports are swapped", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "77cd9a9dd810ce8042bdb9d40e256dfe", "Kyle Pittman", "", "Evil Dead (2003) (Kyle Pittman) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "77d0a577636e1c9212aeccde9d0baa4b", "Atari, Joe Decuir", "CX2621, CX2621P", "Video Olympics (1977) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "AUTO 60", "", "", "", "", "" }, { "78297db7f416af3052dd793b53ff014e", "", "", "Poker Squares (V0.17) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7836794b79e8060c2b8326a2db74eef0", "", "", "RIOT RAM Test (26-11-2002) (Dennis Debro)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "784176346e9422733d55c427230e5bad", "Activision, Alex DeMeo", "", "Title Match Pro Wrestling (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7860716fa5dbc0fffab93fb9a4cb4132", "", "", "Hangman Monkey Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7867ee819b53d69cfcfe740f7ddca574", "Arcadia Corporation, Dennis Caswell", "1 AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "787ebc2609a31eb5c57c4a18837d1aee", "Prescott", "", "Vault Assault (19xx) (Prescott)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "78821ef76ebc3934850d1bc1b9e4f4b0", "HES - Activision", "542", "Hot Action Pak - Ghostbusters, Tennis, Plaque Attack (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "78963290052fd17c6c7998305ab3a6a0", "", "", "Push (V0.08) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "78b84cfb1c57b0488d674d2374e656e6", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "78c2de58e42cd1faac2ea7df783eaeb3", "", "", "Fu Kung! (V0.07) (25-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79004f84bdeee78d142e445057883169", "CCE", "C-830", "Planet Patrol (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "791bc8aceb6b0f4d9990d6062b30adfa", "Activision, David Crane - Ariola", "EAX-018, EAX-018-04B, EAX-018-04I - 711 018-725", "Pitfall! (1982) (Activision) (PAL)", "Abenteuer im Urwald (Jungle Runner)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7926083ad423ed685de3b3a04a914315", "Barry Laws Jr.", "", "Face Invaders 2 (Barry Laws Jr.) (Hack)", "Hack of Astroblast", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "792b1d93eb1d8045260c840b0688ec8f", "Kroko", "", "3E Bankswitch Test (TIA @ $00)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7972e5101fa548b952d852db24ad6060", "Atari - Sears", "CX2627 - 6-99841", "Human Cannonball (1979) (Atari)", "AKA Cannon Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "798b8921276eec9e332dfcb47a2dbb17", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari) (PAL) [a]", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "798cc114f1623c14085868cd3494fe8e", "", "", "Pins Revenge (Atari Freak 1)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7991e1797e5e9f311fd957e62d889dff", "Joe Grand", "", "SCSIcide (v1.1) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "", "" }, { "7996b8d07462a19259baa4c811c2b4b4", "", "", "Math Gran Prix (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79ab4123a83dc11d468fb2108ea09e2e", "Activision - Cheshire Engineering, David Rolfe, Larry Zwick", "AZ-037-04", "Beamrider (1984) (Activision)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79b649fb812c50b4347d12e7ddbb8400", "", "", "Red Pong Number 2 Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "79c27f90591e3fdc7d2ed020ecbedeb3", "CCE", "C-815", "Seaquest (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79d4af56036ec28f298cad964a2e2494", "", "", "Hangman Pac-Man Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79d6f61da3c64688ac8e075667f8a39f", "", "", "Tie-Fighters (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79e5338dbfa6b64008bb0d72a3179d3c", "M Network, David Akers, Patricia Lewis Du Long - INTV", "MT4313", "Star Strike (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "79fcdee6d71f23f6cf3d01258236c3b9", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673, CX2673P", "Phoenix (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a09299f473105ae1ef3ad6f9f2cd807", "Atari, Steve Wright", "CX2616P", "Pele's Soccer (1981) (Atari) (PAL)", "AKA Pele's Championship Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a2af383014f5d810ad26d322823549d", "", "", "FlickerSort Demo (20-04-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a5463545dfb2dcfdafa6074b2f2c15e", "20th Century Fox Video Games - Sirius Software, Mark Turmell", "11007", "Turmoil (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a63d7ea3f2851bcf04f0bb4ba1a3929", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (3 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a64a8b727c8215d945e37d565ca95a5", "Atari, Warren Robinett", "CX2606", "Slot Racers (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a64b5a6e90619c6aacf244cdd7502f8", "Baroque Gaming (Brian Eno)", "", "Warring Worms (Beta 1) (2002) (Baroque Gaming)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a7f6ab9215a3a6b5940b8737f116359", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7a93d0c029eaa72236523eedc3f19645", "", "", "20 Sprites at Once Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ab0917107b6ec768a5ebaadf28c497a", "", "", "Santa's Helper (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "7ab210f448de518fa61a5924120ba872", "", "", "Fortress (20-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ab2f190d4e59e8742e76a6e870b567e", "Apollo, Larry Martin", "AP-2008", "Guardian (1982) (Apollo)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01 65", "", "", "", "", "" }, { "7ac4f4fb425db38288fa07fb8ff4b21d", "Goliath", "83-213", "Space Eagle (1983) (Goliath) (PAL)", "AKA Exocet", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ad257833190bc60277c1ca475057051", "Atari, Alan J. Murphy, Robert Zdybel", "CX2668", "RealSports Football (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7ad782952e5147b88b65a25cadcdf9e0", "Imagic, Dave Johnson", "720119-1A, 03211", "Kwibble (1983) (Imagic) (Prototype)", "AKA Quick Step! Beta", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7adbcf78399b19596671edbffc3d34aa", "Atari, Mimi Nyden, Joseph Tung", "CX26152", "Super Baseball (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7af40c1485ce9f29b1a7b069a2eb04a7", "Amiga - Video Soft", "3120", "Mogul Maniac (1983) (Amiga)", "Uses the Amiga Joyboard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b24bfe1b61864e758ada1fe9adaa098", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b33407b2b198af74906b936ce1eecbb", "King Atari", "", "Ghostbuster 2 (King Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7b3cf0256e1fa0fdc538caf3d5d86337", "CommaVid, Joseph Biel", "CM-009", "Stronghold (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b43c32e3d4ff5932f39afcb4c551627", "Syncro, Daniel Wolf", "", "Kamikaze Saucers (1983) (Syncro) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "222", "", "" }, { "7b5207e68ee85b16998bea861987c690", "Atari, Carol Shaw", "CX26163P", "3-D Tic-Tac-Toe (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b6f3348dbf71ada88db0fdaf7feefe0", "", "", "3-D Corridor (Pink Spiral) (31-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b79beb378d1b4471def90ceccf413de", "", "", "Pitfall Cupcake (Hack)", "Hack of Pitfall", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b7b4ac05232490c28f9b680c72998f9", "Zellers", "", "Freeway (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b8a481e0c5aa78150b5555dff01f64e", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (05-16-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7b938c7ddf18e8362949b62c7eaa660a", "Atari, Bob Whitehead - Sears", "CX2603 - 99803, 49-75601", "Star Ship (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ba07d4ea18bf3b3245c374d8720ad30", "Starpath Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (Preview) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7bb286cb659d146af3966d699b51f509", "Atari - Axlon, Tod Frye", "CX26178", "Save Mary! (04-03-1989) (Atari) (Prototype)", "AKA Saving Mary", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7bc4fd254ec8c0a25a13f02fd3f762ff", "Retroactive", "", "Qb (V1.00) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7c00e7a205d3fda98eb20da7c9c50a55", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo", "AP-2004", "Lost Luggage (1982) (Apollo)", "AKA Airport Mayhem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7c4a499d343fca0cef2d59dd16af621a", "", "", "Poker Card Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7c757bb151269b2a626c907a22f5dae7", "TNT Games - Sculptured Software, Adam Clayton", "26192", "BMX Air Master (1989) (TNT Games) (PAL)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7c7a4a2d505c2d0c75337c44711d8d54", "Atari, Warren Robinett", "", "Elf Adventure (04-22-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7c9b3b8b25acf2fe3b8da834f69629c6", "", "", "I Robot (1984) (Atari) (Prototype) [!]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ca7a471d70305c673fedd08174a81e8", "Tim Snider", "", "Venture II (2001) (Tim Snider)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7cc77f6745e1f2b20df4a4327d350545", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ccf350354ee15cd9b85564a2014b08c", "", "", "Big Dig (13-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "7cd379da92c93679f3b6d2548617746a", "", "", "Demo Image Series #5 - Clown (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7cd900e9eccbb240fe9c37fa28f917b5", "Jone Yuan Telephonic Enterprise Co", "", "Bi! Bi! (Jone Yuan) (PAL)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ced6709f091e79a2ab9575d3516a4ac", "Activision, Steve Cartwright - Ariola", "EAX-027 - 711 027-722", "Plaque Attack (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7cedffa0db65d610568b90aeca705ac6", "Atari, Rob Fulop - Sears", "CX2638 - 49-75166", "Missile Command (1981) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d0b49ea4fe3a5f1e119a6d14843db17", "Gameworld, J. Ray Dettling", "133-008", "Frankenstein's Monster (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d1034bcb38c9b746ea2c0ae37d9dff2", "Atari, Brad Stewart", "", "Morse Code Tutor (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d3cdde63b16fa637c4484e716839c94", "CCE", "", "Road Runner (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d483b702c44ee65cd2df22cbcc8b7ed", "Atari, Warren Robinett", "", "Elf Adventure (05-25-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d5c3b7b908752b98e30690e2a3322c2", "Dactari - Milmar", "", "Freeway (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d726fa494f706784bafeb1b50d87f23", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (07-27-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d903411807704e725cf3fafbeb97255", "Imagic, Rob Fulop", "720104-1A, 720104-1B, IA3204", "Cosmic Ark (Reaction) (1982) (Imagic) [selectable starfield]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d93071b3e3616093a6b5a98b0315751", "", "", "Gunfight 2600 - Music & Bugfixes 2 (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7d940d749e55b96b7b746519fa06f2de", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (Preview) (1983) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "", "", "", "", "", "" }, { "7d9c96b215d1941e87b6fb412eb9204f", "", "", "Othello (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7da9de8d62fcdd3a2c545b2e720c2a61", "CommaVid, John Bronstein", "CM-001", "MagiCard (1981) (CommaVid) (4K)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "24", "", "", "" }, { "7dbc8fa2e488e3f6b87fbe0f76c5b89f", "Ed Federmeyer", "", "Sound X (1996) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7dc03a1f56d0e6a8aae3e3e50d654a08", "", "", "Hozer Video Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7dcbfd2acc013e817f011309c7504daa", "Arcadia Corporation, Dennis Caswell", "AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7dd9c5284422f729066ab22a284c8283", "CCE", "C-833", "Target Practice (1983) (CCE) [a]", "AKA Carnival", "", "", "", "", "", "", "", "", "", "", "", "", "", "214", "", "" }, { "7dfd100bda9abb0f3744361bc7112681", "Telesys, Don Ruffcorn", "1006", "Demolition Herby (1983) (Telesys) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7e2fe40a788e56765fe56a3576019968", "Activision - Imagineering, Dan Kitchen", "AK-050-04", "Double Dragon (1989) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7e464186ba384069582d9f0c141f7491", "PlayAround - J.H.M.", "206", "General Re-Treat (1982) (PlayAround) (PAL)", "AKA Custer's Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7e4783a59972ae2cd8384f231757ea0b", "Atari - Imagineering, Dan Kichen", "CX26139P", "Crossbow (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7e51a58de2c0db7d33715f518893b0db", "CBS Electronics, E.F. Dreyer, Ed Salvo", "4L 2738 0000", "Mountain King (1983) (CBS Electronics) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7e52a95074a66640fcfde124fffd491a", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673", "Phoenix (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7e7c4c59d55494e66eef5e04ec1c6157", "Baroque Gaming (Brian Eno)", "", "Warring Worms (2002) (Baroque Gaming)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7e8aa18bc9502eb57daaf5e7c1e94da7", "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner", "M8774, M8794", "Wizard of Wor (1982) (CBS Electronics)", "Uses the Joystick Controllers (swapped)", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "YES", "" }, { "7e9da5cb84d5bc869854938fe3e85ffa", "Atari, Ian Shepard - Sears", "CX2604 - 6-99812, 49-75106", "Space War (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7eab0284a0cd1043461d446a08d08cec", "Jone Yuan Telephonic Enterprise Co", "", "Basic Math (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ead257e8b5a44cac538f5f54c7a0023", "Xonox, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7eaf009a892f03d90682dc1e67e85f07", "Fabrizio Zavagli", "", "Bounce! (18-03-2003) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7eafc9827e8d5b1336905939e097aae7", "Atari, Mark R. Hahn", "", "Elk Attack (1987) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7eba20c2291a982214cc7cbe8d0b47cd", "Imagic, Dave Johnson", "720119-1A, 03211", "Quick Step! (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ed61a18cebdeca0a93be1f5461731e5", "Dactari", "", "Skiing (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ed7130a6e4020161836414332b11983", "", "", "Fu Kung! (V0.05 Cuttle Card Compatible) (13-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7edc8fcb319b3fb61cac87614afd4ffa", "Activision, Alan Miller", "AG-003", "Checkers (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ef3ca08abde439c6ccca84693839c57", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix (1983) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01", "", "", "", "", "" }, { "7ef74879d7cb9fa0ef161b91ad55b3bb", "CCE", "", "Vanguard (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f0209cfcc3d181715463f4d6451cecf", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (05-15-1983) (Atari) (Prototype)", "AKA RealSports Driving", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f07cd2e89dda5a3a90d3ab064bfd1f6", "Videospielkassette - Ariola", "PGP234", "Boxen (Ariola) (PAL)", "AKA Boxing", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f430c33044e0354815392b53a9a772d", "HES", "773-891", "2 Pak Special - Cavern Blaster, City War (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f525b07bc98080cc8950f7284e52ede", "Atari", "", "128-in-1 Junior Console (Chip 4 of 4) (1991) (Atari) (PAL)", "Actually contains only 16 games, not 32", "", "", "16IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f54fa6aa824001af415503c313262f2", "HES", "", "Boom Bang (HES) (PAL)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f6533386644c7d6358f871666c86e79", "CommaVid, Irwin Gaines", "CM-008", "Cakewalk (1983) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f73ac39e5e3e13e40fd8ad885561a0f", "", "", "Star Fire - Warping Star (13-04-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f790939f7eaa8c47a246c4283981f84", "", "", "This Planet Sucks Demo 3 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "7f819454734ddf93f83fefcffcd3e212", "Jone Yuan Telephonic Enterprise Co", "", "Outlaw (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7f9fbe3e00a21ea06e6ae5e0e5db2143", "", "", "Skate Boardin' (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7fcd1766de75c614a3ccc31b25dd5b7a", "PlayAround - J.H.M.", "203", "Knight on the Town (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "216", "YES", "" }, { "7fcd5fb59e88fc7b8473c641f44226c3", "CCE", "C-807", "Space Tunnel (1983) (CCE)", "AKA Cosmic Corridor, O Tunel Espacial", "", "", "", "", "", "", "", "", "", "", "", "", "32", "215", "", "" }, { "7ff53f6922708119e7bf478d7d618c86", "Suntek", "SS-032", "Walker (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "7ffc2d80fd49a124808315306d19868e", "Ishido", "", "Domino (Ishido) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "801ba40f3290fc413e8c816c467c765c", "Hozer Video Games", "", "Gunfight 2600 - Westward Ho! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "803393ed29a9e9346569dd1bf209907b", "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker", "CX2684", "Galaxian (02-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "804ed85eadf1ce3e93721547cbea7592", "CCE", "", "Fishing Derby (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8055b9c2622136fd91edfea6df642daf", "Activision", "", "Unknown Activision Game #1 (1983) (Activision) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "805f9a32ef97ac25f999a25014dc5c23", "SnailSoft", "", "Balthazar (SnailSoft)", "AKA Babylon 5", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8068e07b484dfd661158b3771d6621ca", "Epyx, Steven A. Baker, Peter Engelbrite", "80561-00286", "California Games (1988) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "807841df228ee8aab0a06ee639ce5a8a", "Coleco - Project Guild - GMA, Michael Green, Anthony R. Henderson, Gary Littleton", "2455", "Turbo (1982) (Coleco) (Prototype)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "807a8ff6216b00d52aba2dfea5d8d860", "John Payson", "", "Strat-O-Gems Deluxe (2005) (J. Payson)", "Uses the AtariVox controller", "Homebrew", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "", "" }, { "808c3b1e60ee0e7c65205fa4bd772221", "CCE", "", "Defender (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "80cd42881e670e4b74a9ccd10d0d7b2e", "20th Century Fox Video Games - Sirius, Ed Hodapp", "11004", "Deadly Duck (1982) (20th Century Fox) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "80cec82239913cb8c4016eb13749de44", "David Marli", "", "Invaders from Space by David Marli (Space Invaders Hack)", "Hack of Space Invaders (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "80e1410ec98089e0733cc09e584dba4b", "Dynamics", "DY-293005", "Jumping Jack (1983) (Dynamics) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "80e52315919bd8a8b82a407ccd9bb13f", "", "", "Euchre (Jul 28) (2002) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "80e5400470ac788143e6db9bc8dd88cf", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (06-XX-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8101efafcf0af32fedda4579c941e6f4", "", "", "Okie Dokie (4K) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "81073d0377a2badef8d5e74fc44fc323", "Thomas Jentzsch", "", "Sadoom (TJ) (PAL60) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "PAL60", "", "", "", "" }, { "8108162bc88b5a14adc3e031cf4175ad", "Quelle", "719.941 7", "Vom Himmel durch die Hoelle (1983) (Quelle) (PAL)", "AKA Parachute", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8108ad2679bd055afec0a35a1dca46a4", "", "", "Maze Craze (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC", "", "", "", "" }, { "810d8952af5a6036fca8d0c4e1b23db6", "Tiger Vision - Eram", "", "Keystone (Tiger Vision)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "81254ebce88fa46c4ff5a2f4d2bad538", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "81341f00b61ab37d19d1529f483d496d", "", "", "Fu Kung! (V0.04) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "813985a940aa739cc28df19e0edd4722", "Imagic, Bob Smith", "720000-201, 720102-1B, IA3201", "Star Voyager (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "81414174f1816d5c1e583af427ac89fc", "Thomas Jentzsch", "", "Treasure Below (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "", "220", "", "" }, { "814210c0e121f7dbc25661b93c06311c", "", "", "Joustpong (16-09-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "81591a221419024060b890665beb0fb8", "Atari, Carla Meninsky, Ed Riddle", "CX2611, CX2611P", "Indy 500 (1977) (Atari) (PAL)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "", "" }, { "8190b403d67bf9792fe22fa5d22f3556", "", "", "Sky Diver (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "819aeeb9a2e11deb54e6de334f843894", "Atari, Gary Palmer", "CX2661", "Fun with Numbers (1980) (Atari)", "AKA Basic Math", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "81a010abdba1a640f7adf7f84e13d307", "Telegames - VSS", "7062 A305", "Universal Chaos (1988) (Telegames)", "AKA Targ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "81b3bf17cf01039d311b4cd738ae608e", "CBS Electronics - Roklan, Joe Gaucher, Alex Leavens", "M8776, M8793", "Gorf (1982) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "81f4f0285f651399a12ff2e2f35bab77", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "822a950f27ff0122870558a89a49cad3", "", "", "Space Jockey (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "82337e5fe0f418ca9484ca851dfc226a", "", "", "Robot City (V1.0) (Alpha) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "826481f6fc53ea47c9f272f7050eedf7", "Imagic, Dennis Koble", "720103-1A, IA3203", "Atlantis II (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "827a22b9dffee24e93ed0df09ff8414a", "CBS Electronics, Stuart Ross", "", "Wings (10-10-1983) (CBS Electronics) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8290daea8391f96d7c8e1482e184d19c", "Eckhard Stolberg", "", "Frame Timed Sound Effects (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "82bf0dff20cee6a1ed4bb834b00074e6", "Suntek", "SS-035", "Panda (Quest) (Suntek) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "82c25d1c35e6ac6f893d1d7c2fc2f9c8", "Atari, Larry Kaplan", "CX2628, CX2628P", "Bowling (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "82de957d155fc041fc6afb8315a28550", "Coleco, Joseph Biel", "2457", "Venture (1982) (Coleco) (Prototype)", "2K", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "82e7aab602c378cffdd8186a099e807e", "", "", "Space Robot (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "82efe7984783e23a7c55266a5125c68e", "CCE", "C-837", "Pizza Chef (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "834a2273e97aec3181ee127917b4b269", "Quelle", "043.151 0, 874.382 5", "Die hungrigen Froesche (1983) (Quelle) (PAL)", "AKA Frogs and Flies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "835759ff95c2cdc2324d7c1e7c5fa237", "20th Century Fox Video Games, Frank Cohen, Douglas 'Dallas North' Neubauer", "11011", "M.A.S.H (1983) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8372eec01a08c60dbed063c5524cdfb1", "", "", "Cross Force (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8388d6fe59c38c0b3a6ab2c58420036a", "Atari, Frank Hausman, Mimi Nyden, Steve Woita", "CX2686", "Quadrun (12-06-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "83b8c01c72306d60dd9b753332ebd276", "", "", "Bank Heist (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "83bdc819980db99bf89a7f2ed6a2de59", "Atari, Carla Meninsky - Sears", "CX2637 - 49-75158", "Dodge 'Em (1980) (Atari) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "83d15fb9843d9f84aa3710538403f434", "", "", "Gunfight 2600 - Release Candidate (2001) (MP) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "83f05ececae8be59ba1e51135f4bdcbf", "", "", "Demo Image Series #13 - Mario (4K Interleaved Chronocolour) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "83f50fa0fbae545e4b88bb53b788c341", "Atari, Larry Kaplan - Sears", "CX2643 - 6-99815", "Codebreaker (1978) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "83fafd7bd12e3335166c6314b3bde528", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00251", "Winter Games (1987) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "840a5a2eaea24d95d289f514fd12f9bb", "", "", "GBImprov (Hack)", "Hack of Ghostbusters", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "841057f83ce3731e6bbfda1707cbca58", "Champ Games", "CG-04-N", "Super Cobra Arcade (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "841b7bc1cad05f5408302308777d49dc", "Activision", "", "Unknown Activision Game (10-22-1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "84290e333ff7567c2380f179430083b8", "Imagic, Dave Johnson", "13211, EIX-004-04I", "Quick Step! (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "843435eb360ed72085f7ab9374f9749a", "Joe Grand", "", "SCSIcide (1.31) (Joe Grand)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "", "" }, { "84535afb9a69712ec0af4947329e08b8", "CCE", "C-868", "Bingo (1983) (CCE) (PAL)", "AKA Dice Puzzle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8454ed9787c9d8211748ccddb673e920", "Froggo", "FG1002", "Spiderdroid (1987) (Froggo)", "AKA Amidar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8490e1014c2baa0d3a3a08854e5d68b3", "Xonox, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "84db818cd4111542a15c2a795369a256", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "850ffd5849c911946b24544ea1e60496", "", "", "Invasion (07-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "851cc1f3c64eaedd10361ea26345acea", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85227160f37aaa29f5e3a6c7a3219f54", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8530caaaf40acbdcd118c282b5f8a37a", "", "", "This Planet Sucks Demo 2 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "8538c5e3ee83267774480649f83fa8d6", "", "", "Escape Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "853c11c4d07050c22ef3e0721533e0c5", "", "", "Oink! (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85470dcb7989e5e856f36b962d815537", "Atari - Sculptured Software, Inc., Steve Aguirre", "CX26162", "Fatal Run (1989) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85478bb289dfa5c63726b9153992a920", "", "", "Candi (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "854b68b93e7123a3be42b5a2a41f75d7", "Atari, Carol Shaw", "CX2618, CX2618P", "3-D Tic-Tac-Toe (1980) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "44", "", "", "" }, { "85502d69fe46b7f54ef2598225678b47", "Jone Yuan Telephonic Enterprise Co", "", "Super-Ferrari (Jone Yuan)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85564dd0665aa0a1359037aef1a48d58", "ITT Family Games", "554-33 367", "Laser Base (1983) (ITT Family Games) (PAL) [a]", "AKA The End of the World (Perry Rhodan-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8556b42aa05f94bc29ff39c39b11bff4", "Atari, Craig Nelson - Sears", "CX2617 - 49-75183", "Backgammon (1979) (Atari)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 80", "", "", "", "", "" }, { "855a42078b14714bcfd490d2cf57e68d", "Atari, Suki Lee", "CX26113", "Miss Piggy's Wedding (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "85a4133f6dcf4180e36e70ad0fca0921", "CCE", "C-827", "Chopper Command (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85b1bca93e69f13905107cc802a02470", "Atari, Craig Nelson", "CX2617, CX2617P", "Backgammon (1979) (Atari) (PAL)", "Uses the Paddle Controllers", "Extremely Rare", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 80", "", "", "", "", "" }, { "85bbefb90e16bf386b304c1e9a1f6084", "Champ Games", "CG-02-P", "Conquest Of Mars (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "85e48d68c8d802e3ba9d494a47d6e016", "", "", "Ship Demo (V 15) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "85e564dae5687e431955056fbda10978", "Milton Bradley Company - Renaissance Technology, Ty Roberts", "4362", "Survival Run (1983) (Milton Bradley)", "AKA Cosmic Commander", "", "", "", "", "", "", "", "", "", "", "", "", "", "225", "YES", "" }, { "86128001e69ab049937f265911ce7e8a", "Apollo - Games by Apollo, Steve Stringfellow", "AP-2005", "Lochjaw (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "862cf669cbced78f9ed31a5d375b2ebe", "", "", "Gunfight 2600 - Flicker acceptance (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8644352b806985efde499ae6fc7b0fec", "CCE", "C-801", "Mr. Postman (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8654d7f0fb351960016e06646f639b02", "Home Vision, R.J.P.G. - Gem International Corp. - VDI", "VCS83106", "Ski Hunt (1983) (Home Vision) (PAL)", "AKA Skiiing Hunt", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "866e5150c995c4ae5172e5207ba948c7", "Canal 3 - Intellivision", "", "Stampede (Canal 3) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "869abe0426e6e9fcb6d75a3c2d6e05d1", "", "", "Stampede (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "86b4aa76bbeb70e1a4f9211a9880ba8e", "", "", "Incoming (1 Player Version) (05-11-2002) (Ben Larson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "86f5e55ca9a9bde7338a157570828e79", "", "", "Star Fire - Creating a Universe (09-09-2002) (MP) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8712cceec5644aacc2c21203d9ebe2ec", "Retroactive", "", "Qb (V0.10) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8726c17ee7b559cb7bf2330d20972ad0", "", "", "Cave Demo (21-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "873fb75a7788ba0f4ae715229a05545e", "", "", "Euchre (Improved Colors) (PAL) (26-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8747ba79cd39fa83a529bb26010db21b", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL) [different speed and colors]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8749a0d088df25218c149dc325abc7ca", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a5]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "874c76726f68c166fcfac48ce78eef95", "", "", "Red Pong Number 2 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8764462d7d19a33b0717af22b99fc88f", "CCE", "", "Sky Jinks (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "87662815bc4f3c3c86071dc994e3f30e", "Intellivision Productions - M Network, Patricia Lewis Du Long, Stephen Tatsumi", "", "Swordfight (1983) (Intellivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "876a953daae0e946620cf05ed41989f4", "Retroactive", "", "Qb (V2.08) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "877a5397f3f205bf6750398c98f33de1", "Erik Eid", "", "Euchre (Beta) (PAL) (12-09-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8786c1e56ef221d946c64f6b65b697e9", "20th Century Fox Video Games, David Lubar", "11015", "AKA Space Adventure", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8786f229b974c393222874f73a9f3206", "Activision, Larry Miller - Ariola", "EAX-021, EAX-021-04I - 711 021-720", "Spider Fighter (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8786f4609a66fbea2cd9aa48ca7aa11c", "Goliath", "5", "Open Sesame (1983) (Goliath) (PAL)", "AKA I Want My Mommy", "", "", "", "", "", "", "", "", "", "", "", "", "34", "", "YES", "" }, { "87b460df21b7bbcfc57b1c082c6794b0", "Dennis Debro", "", "Climber 5 (20-03-2003) (Dennis Debro)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "87b6a17132fc32f576bc49ea18729506", "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn", "CX2690", "Pengo (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "87bea777a34278d29b3b6029833c5422", "Thomas Jentzsch", "", "Polaris (1983) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "87e79cd41ce136fd4f72cc6e2c161bee", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675", "Ms. Pac-Man (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "87f020daa98d0132e98e43db7d8fea7e", "20th Century Fox Video Games - Sirius, David Lubar", "11001", "Worm War I (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "883258dcd68cefc6cd4d40b1185116dc", "Activision, David Crane - Ariola", "EAZ-030, EAZ-030-04B, EAZ-030-04I - 711 030-725", "Decathlon (1983) (Activision) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8874b68751fd2ba6d3306a263ae57a7d", "Eric Mooney", "", "Invaders by Erik Mooney (Alpha 1) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8885d0ce11c5b40c3a8a8d9ed28cefef", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner - Sears", "CX2608 - 49-75165", "Super Breakout (1982 - 1981) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 45", "", "", "", "", "" }, { "888debb162d7d1ae71025b4ab794257f", "", "", "Interleaved ChronoColour - Nude Art (17-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "88a6c9c88cb329ee5fa7d168bd6c7c63", "CCE", "C-1007", "Jungle Hunt (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "88d300a38bdd7cab9edad271c18cd02b", "Funvision - Fund. Int'l Co.", "", "Pac Kong (Funvision) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "88d7b6b3967de0db24cdae1c7f7181bd", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "88d8a1accab58cf1abb043613cf185e9", "Ultravison", "", "Sabotage (Ultravison)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "88dce4037471424bb38ab6841aaa8cab", "", "", "Double-Height 6-Digit Score Display (Two Background Color Change) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "88ed87c011f699dd27321dbe404db6c8", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "88f74ec75ef696e7294b7b6ac5ca465f", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision) (16K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8905d54f48b8024fc718ed643e9033f7", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (05-24-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "890c13590e0d8d5d6149737d930e4d95", "Atari, David Crane - Sears", "CX2605 - 6-99822, 49-75109", "Outlaw (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8917f7c1ac5eb05b82331cf01c495af2", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "8933976f2029c0d8492ebd8f4eb21492", "", "", "Synthcart Plus (09-02-2003) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "8953bc11352d794431d3303e31d3b892", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (02-17-1983) (Tigervision) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "896ec58f26e930e02f5e4f046602c3a1", "", "", "Synthcart (Beta) (2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "YES", "" }, { "898143773824663efe88d0a3a0bb1ba4", "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "AZ-033, AZ-033-04", "Space Shuttle (1983) (Activision) [FE]", "A Journey Into Space", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "898748d5eaac3164b0391a64ae1e0e32", "", "", "Hangman Man 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "898b5467551d32af48a604802407b6e8", "Bit Corporation", "PG208", "Snail Against Squirrel (1983) (BitCorp) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "89a65b83203980d5d4d60f52a584a5b8", "", "", "Marble Craze (PAL) (02-02-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "89a68746eff7f266bbf08de2483abe55", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1984) (Atari)", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "89afff4a10807093c105740c73e9b544", "", "", "Pooyan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "89eaba47a59cbfd26e74aad32f553cd7", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2001", "Spacechase (1982) (Apollo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8a159ee58b2f0a54805162984b0f07e5", "Atari - Sculptured Software, Inc., Steve Aguirre", "CX26162", "Fatal Run (1989) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8a183b6357987db5170c5cf9f4a113e5", "Atari - Roklan, Joe Gaucher", "CX2679", "RealSports Basketball (1983) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8a42e2c7266439d8997a55d0124c912c", "", "", "Hangman Invader Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8a49cf1785e3dea2012d331a3ad476e1", "", "", "Boulderdash (10 Blocks Wide) (02-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8a6c84f481acf42abcb78ba5064ad755", "128-in-1 Junior Console", "", "Street Racer (128-in-1 Junior Console) (PAL) (4K)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 75", "", "", "", "", "" }, { "8a8e401369e2b63a13e18a4d685387c6", "Activision, David Crane - Ariola", "EAG-008, PAG-008, EAG-008-04I - 711 008-720", "Laser Blast (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8a9d874a38608964f33ec0c35cab618d", "Chris Cracknell", "", "Rescue Bira Bira (Chris Cracknell)", "Hack of Jungle Fever", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8a9d953ac3db52a313a90d6a9b139c76", "", "", "Hangman Invader Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8aad33da907bed78b76b87fceaa838c1", "Atari, Larry Kaplan", "CX26163P", "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "8ac18076d01a6b63acf6e2cab4968940", "Atari, Dan Hitchens, Mimi Nyden", "CX2685", "Gravitar (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8af58a9b90b25907da0251ec0facf3b8", "Jone Yuan Telephonic Enterprise Co", "", "Cosmic Swarm (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8b04e9d132b8e30d447acaa6bd049c32", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8b40a9ca1cfcd14822e2547eaa9df5c1", "Parker Brothers - Western Technologies, Dave Hampton, Tom Sloper", "931517", "Q-bert (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8b504b417c8626167a7e02f44229f0e7", "Retroactive", "", "Qb (V1.00) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8b556c3d9ca8e5e6e665bd759b93ffae", "", "", "Synthcart (2002) (Paul Slocum) (PAL) [!]", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "YES", "" }, { "8b5b1e3a434ebbdc2c2a49dc68f46360", "CBS Electronics - Woodside Design Associates - Imaginative Systems Software, Dan Kitchen, Garry Kitchen", "4L1700, 4L1701, 4L1702, 4L1802, 4L2274", "Donkey Kong (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8b7ca29a55432f886cee3d452fb00481", "Starpath Corporation, Stephen H. Landrum, Jon Leupp", "11 AR-4201", "Sword of Saros (1983) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8b8152d6081f31365406cb716bd95567", "Atari", "CX2626, CX2626P", "Miniature Golf (1979) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8b8789c6669a4cee86c579a65332f852", "Digivision", "", "Plaque Attack (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8bbfd951c89cc09c148bfabdefa08bec", "UA Limited", "", "Pleiades (1983) (UA Limited) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8bc0d2052b4f259e7a50a7c771b45241", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox) [a]", "AKA Thundarr the Barbarian", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "", "" }, { "8bd8f65377023bdb7c5fcf46ddda5d31", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8bebac614571135933116045204f0f00", "Thomas Jentzsch", "", "Missile Command (Trakball) (2002) (TJ) (PAL)", "Uses the Trakball Controller", "Homebrew", "", "", "", "", "", "", "TRAKBALL", "", "", "", "", "", "", "YES", "" }, { "8c103a79b007a2fd5af602334937b4e1", "Thomas Jentzsch", "", "Laser Base (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "240", "", "" }, { "8c136e97c0a4af66da4a249561ed17db", "", "", "Poker Squares (V0.27) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8c2fa33048f055f38358d51eefe417db", "Home Vision - Gem International Corp. - VDI", "VCS83137", "Teddy Apple (1983) (Home Vision) (PAL)", "AKA I Want My Mommy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8c36ed2352801031516695d1eeefe617", "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite", "80561-00251", "Winter Games (1987) (Epyx) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8c7e5e2329f4f4e06cbcc994a30fd352", "Data Age", "DA1004", "Airlock (1982) (Data Age) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8c8a26ed57870daba8e13162d497bad1", "HES", "", "2 Pak Special - Dolphin, Oink (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8c8b15b3259e60757987ed13cdd74d41", "Supergame", "71", "River Raid (1984) (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8c941fa32c7718a10061d8c328909577", "Digivision", "", "River Raid (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8ccaa442d26b09139685f5b22bf189c4", "Retroactive", "", "Qb (V1.01) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8cd26dcf249456fe4aeb8db42d49df74", "Atari - Imagineering, Dan Kichen", "CX26139", "Crossbow (1988) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8ce9126066f2ddd5173e9f1f9ce1494e", "Thomas Jentzsch", "", "Missile Command (Trakball) (2002) (TJ)", "Uses the Trakball Controller", "Homebrew", "", "", "", "", "", "", "TRAKBALL", "", "", "", "", "", "", "YES", "" }, { "8cf0d333bbe85b9549b1e6b1e2390b8d", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8d00a38f4c8f8800f1c237215ac243fc", "", "", "3-D Corridor (Green) (30-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8d1e2a6d2885966e6d86717180938f87", "Thomas Jentzsch", "", "Missile Command (Amiga Mouse) (2002) (TJ)", "Uses Amiga Mouse Controller", "Homebrew", "", "", "", "", "", "", "AMIGAMOUSE", "", "", "", "", "", "", "YES", "" }, { "8d8b7d7b983f75debbdaac651e814768", "", "", "Demo Image Series #15 - Three Marios (PAL) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8d9a06101ebb0f147936356e645309b8", "", "", "Grid Pattern Demo 2 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8da51e0c4b6b46f7619425119c7d018e", "Atari - Imagineering, David Lubar", "CX26183", "Sentinel (1991) (Atari)", "Uses the Light Gun Controller (left only)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8db152458abaef3cfa7a4e420ddbda59", "", "", "Keystone Kapers (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8df4be9ddc54ac363b13dc57ceaf161a", "Scott Stilphen", "", "Asteroids SS (Scott Stilphen) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8e0ab801b1705a740b476b7f588c6d16", "Activision, David Crane", "AG-009, AG-009-04", "Freeway (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e42674972d6805068fc653e014370fd", "", "", "Skeleton (PAL) (15-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e48ea6ea53709b98e6f4bd8aa018908", "CBS Electronics, Stuart Ross", "", "Wings (06-03-1983) (CBS Electronics) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8e4cd60d93fcde8065c1a2b972a26377", "Imagic, Dan Oliver", "720118-2A, 13208, EIX-007-04I", "Laser Gates (1983) (Imagic) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e4fa8c6ad8d8dce0db8c991c166cdaa", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e512ad4506800458f99dec084fc2c64", "Bob Montgomery, Nathan Strum", "", "Reindeer Rescue (2005)", "2005 AtariAge Holiday Cart", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e7241bfc8380aac3c0ef1b6881cdded", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (09-01-81) (Atari) (Prototype)", "Time Freeze", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8e737a88a566cc94bd50174c2d019593", "Quelle", "343.173 1", "Feuerwehr im Einsatz (1983) (Quelle) (PAL)", "AKA Fire Fighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e822b39a71c84ac875f0107fb61d6f0", "", "", "Hangman Ghost Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8e879aa58db41edb67cbf318b77766c4", "Thomas Jentzsch", "", "Cosmic Commuter (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "8e887d1ba5f3a71ae8a0ea16a4af9fc9", "", "", "Skeleton (V1.1) (PAL) (24-10-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8ed5a746c59571feb255eaa7d6d0cf98", "", "", "Carnival (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8ed73106e2f42f91447fb90b6f0ea4a4", "Spectravision - Spectravideo", "SA-204", "Tapeworm (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8ee3f64dc0f349adc893fe93df5245d8", "", "", "Euchre (20-07-2001) (Eric Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f33bce5ba1053dcf4cea9c1c69981e4", "", "", "Jawbreaker (Unknown) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f53a3b925f0fd961d9b8c4d46ee6755", "", "", "Astrowar (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f5ac5139419c5d49bacc296e342a247", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (12-22-1983) (Atari) (Prototype)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "8f60551db6d1535ef0030f155018c738", "", "", "Space War (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f613ea7c32a587d6741790e32872ddd", "", "", "Troll Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f88309afad108936ca70f8b2b084718", "Spectravision - Spectravideo - Quelle", "SA-203 - 413.223 9", "Cross Force (1982) (Spectravision) (PAL)", "AKA Kreuzfeuer (Cross Fire)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f90590dba143d783df5a6cff2000e4d", "", "", "Gopher (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8f98519a91dbbf4864f135a10050d9ed", "Silvio Mogno", "", "Rainbow Invaders (non-playable demo) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8fa47e5242776e841df7e708b12eb998", "", "", "Sea Hawk (Genesis)", "Genesis controller (C drops bomb)", "Hack of Sea Hawk", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "8fbabaa87941cdf3a377c15e95bdb0f3", "", "", "Meteor Smasher (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8fe00172e7fff4c1878dabcf11bb8dce", "Quelle", "689.302 8", "Hili Ball (1983) (Quelle) (PAL)", "AKA Racquetball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "8febdd9142960d084ab6eeb1d3e88969", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "8fffc8f15bb2e6d24e211884a5479aa5", "Retroactive", "", "Qb (V1.00) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9048ccb7e0802cd8fa5bfc2609f292d8", "Tigervision, Robert H. O'Neil", "7-007", "Polaris (1983) (Tigervision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9057694dce8449521e6164d263702185", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "90578a63441de4520be5324e8f015352", "Bit Corporation", "PGP204", "Open Sesame (4 Game in One) (1983) (BitCorp) (PAL)", "AKA I Want My Mommy", "", "", "", "", "", "", "", "", "", "", "", "", "34", "", "YES", "" }, { "9072c142728a3a3d994956d03bfacba2", "Fabrizio Zavagli", "", "Crash Dive (Fabrizio Zavagli) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "PAL60", "30", "", "", "" }, { "90b1799dddb8bf748ee286d22e609480", "", "", "Ship Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "90b647bfb6b18af35fcf613573ad2eec", "AtariAge (Chris Walton)", "", "Juno First (2009)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "ATARIVOX", "", "", "", "", "", "YES", "" }, { "90ccf4f30a5ad8c801090b388ddd5613", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "90d77e966793754ab4312c47b42900b1", "Imagic, Brad Stewart", "720105-2A, IA3400P, EIX-005-04I", "Fire Fighter (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "90f502cbf4438a95f69f848cef36eb64", "Digitel", "", "River Raid II (1985) (Digitel)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "910dd9bf98cc5bc080943e5128b15bf5", "", "", "Gunfight 2600 - Improved AI (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "911d385ee0805ff5b8f96c5a63da7de5", "Hozer Video Games", "", "Jammed (V0.1) (Demo) (2001) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "913d5d959b5021f879033c89797bab5e", "", "", "Robot Player Graphic (1996) (J.V. Matthews) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "914a8feaf6d0a1bbed9eb61d33817679", "Atari", "CX26163P", "Freeway Chicken (32 in 1) (1988) (Atari) (PAL)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "91925abce3a29e33b6a8b81482f4f5af", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9193b6fff6897d43274741d4f9855b6d", "", "", "M.A.S.H (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "91a3749ff7b7e72b7fa09e05396a0e7b", "", "", "Gunfight 2600 - Final Run Part 2 (2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "91b007f33f9b790be64f57220ec52e80", "Jone Yuan Telephonic Enterprise", "", "Laser Blast (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "91c2098e88a6b13f977af8c003e0bca5", "Atari - GCC", "CX2676", "Centipede (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "91d1c82ceaf8af2add3973a3c34bc0cb", "", "", "Starfield Demo 1 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "91f0a708eeb93c133e9672ad2c8e0429", "", "", "Oystron (V2.9) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "91fdb6541f70c40b16aabf8308123be8", "", "", "Interlacing Game (19-08-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9222b25a0875022b412e8da37e7f6887", "Panda", "106", "Dice Puzzle (1983) (Panda)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9245a84e9851565d565cb6c9fac5802b", "Bomb - Onbase", "CA282", "Great Escape (1983) (Bomb)", "AKA Asteroid Fire", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "927d422d6335018da469a9a07cd80390", "Activision, Carol Shaw - Ariola", "EAX-020, EAX-020-04B, EAX-020-04I - 711 020-720", "River Raid (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9281eccd7f6ef4b3ebdcfd2204c9763a", "Retroactive", "", "Qb (2.15) (Retroactive) (PAL)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9295570a141cdec18074c55dc7229d08", "Telegames", "7045 A015", "Bump 'n' Jump (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "929e8a84ed50601d9af8c49b0425c7ea", "Bit Corporation", "PG205", "Dancing Plate (1982) (BitCorp) (PAL)", "AKA Dishaster, Dancing Plates, Tanzende Teller", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "92a1a605b7ad56d863a56373a866761b", "U.S. Games Corporation - Western Technologies, Dave Hampton", "VC2006", "Raft Rider (1983) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "92c5abb7a8bb1c3fc66c92ba353a3d21", "", "", "Star Fire - Sorting Fixed (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "92d1f6ac179ebe5963868d6bc1bdda8d", "HES", "498", "Smash Hit Pak - Frogger, Boxing, Seaquest, Skiing, Stampede (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "92e72f7cc569584c44c9530d645ae04e", "Canal 3 - Intellivision", "", "Spider Fighter (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "92ede72ed8f61d255bc58d2f166dc6b6", "", "", "Star Fire - Shootable (26-09-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "931b91a8ea2d39fe4dca1a23832b591a", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9333172e3c4992ecf548d3ac1f2553eb", "Konami", "RC 101-X 02", "Strategy X (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93420cc4cb1af1f2175c63e52ec18332", "Tim Snider", "", "Blair Witch Project (Tim Snider) (Hack)", "Hack of Haunted House", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9364ad51c321e0f15c96a8c0aff47ceb", "Atari, Rob Fulop", "CX2638", "Missile Command (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "936ef1d6f8a57b9ff575dc195ee36b80", "", "", "Pac Kong (Unknown)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "936f555b4b1a2cd061b659ff63f4f5f2", "HES, David Lubar", "535", "My Golf (1990) (HES) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "937736d899337036de818391a87271e0", "Atari, Peter C. Niday", "CX26108", "Donald Duck's Speedboat (04-12-1983) (Atari) (Prototype)", "AKA Donald Duck's Regatta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "939ce554f5c0e74cc6e4e62810ec2111", "ZiMAG - Emag - Vidco", "711-111 - GN-020", "Dishaster (1983) (ZiMAG)", "AKA Dancing Plate", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "93acd5020ae8eb5673601e2edecbc158", "Chris Cracknell", "", "Video Time Machine (Chris Cracknell)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93b9229fc0ea4fb959d604f83f8f603c", "Thomas Jentzsch", "", "Amidar DS (Fast Enemies) (2003) (TJ) (Hack)", "Hack of Amidar", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93c52141d3c4e1b5574d072f1afde6cd", "Imagic, Mark Klein", "720112-1A, 03213", "Subterranea (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93c8d9d24f9c5f1f570694848d087df7", "Digivision", "", "Galaxian (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93c9f9239a4e5c956663dd7affa70da2", "Quelle", "626.610 0", "Billard (1983) (Quelle) (PAL)", "AKA Trick Shot", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "93dc15d15e77a7b23162467f95a5f22d", "CCE", "", "Sky Jinks (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "93eb1795c8b1065b1b3d62bb9ec0ccdc", "JSK", "", "Custer's Viagra (JSK) (Hack)", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "94102febc53b4a78342d11b645342ed4", "", "", "Joustpong (14-07-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9436b7ad131b5a1f7753ce4309ba3dee", "Kyle Pittman", "", "War of The Worlds (Kyle Pittman) (Hack)", "Hack of Defender", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9469d18238345d87768e8965f9f4a6b2", "CCE", "", "Ms. Pac-Man (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "947317a89af38a49c4864d6bdd6a91fb", "CBS Electronics, Bob Curtiss", "4L 2487 5000", "Solar Fox (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "94b92a882f6dbaa6993a46e2dcc58402", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "94d90f63678e086f6b6d5e1bc6c4c8c2", "Digivision", "", "Seaquest (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "94e3fbc19107a169909e274187247a9d", "", "2402-044-01", "2-in-1 Freeway and Tennis (Unknown)", "", "", "", "2IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "94e4c9b924286038527f49cdc20fda69", "Retroactive", "", "Qb (V2.12) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "94e7cc6342d11e508e7e8b2ddf53c255", "", "", "Missile Command (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "94ff6b7489ed401dcaaf952fece10f67", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-31-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "951e8cec7a1a1d6c01fd649e7ff7743a", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dark Chambers (1988) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9526e3db3bdfbc27989a9cbfd0ee34bf", "", "", "Atari Logo Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "95351b46fa9c45471d852d28b9b4e00b", "Atari, Tom Rudadahl", "CX26163P", "Golf (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "955c408265ad6994f61f9b66657bbae9", "", "", "Quadrun (Video Conversion) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "956496f81775de0b69a116a0d1ad41cc", "CCE", "", "Alien (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "956b99511c0f47b3a11d18e8b7ac8d47", "", "", "Bones (Arcade Golf Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "95956108289a917f80667eccd3ce98a9", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "95a69cf8c08ef1522b050529464f0bca", "", "", "Grid Pattern Demo 1 (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "95a89d1bf767d7cc9d0d5093d579ba61", "PlayAround - J.H.M.", "204", "Lady in Wading (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "216", "YES", "" }, { "95e1d834c57cdd525dd0bd6048a57f7b", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "95e542a7467c94b1e4ab24a3ebe907f1", "Quelle", "719.252 9", "Im Schutz der Drachen (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "95fd6097dc27c20666f039cfe34f7c69", "", "", "Oh No! (Version 1) (17-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "961112b74a920a5242e233480326c356", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "962ffd3eaf865230a7a312b80e6c5cfd", "Imagic, Wilfredo 'Willy' Aguilar, Michael Becker, Rob Fulop", "13205", "Fathom (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "96670d0bf3610da2afcabd8e21d8eabf", "", "", "Boring Pitfall (Hack)", "Hack of Pitfall!", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "966b11d3c147d894dd9e4ebb971ea309", "", "", "Marble Craze Song (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9671b658286e276cc4a3d02aa25931d2", "", "", "Hangman Ghost Wordlist (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "968efc79d500dce52a906870a97358ab", "TNT Games - Sculptured Software, Adam Clayton", "26192", "BMX Air Master (1989) (TNT Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "969b968383d9f0e9d8ffd1056bcaef49", "Atari, Larry Kaplan", "CX2628, CX2628P", "Bowling (1979) (Atari) (PAL)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "96bcb3d97ce4ff7586326d183ac338a2", "", "", "Revenge of the Apes (Hack) [h2]", "Hack of Planet of the Apes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "96e798995af6ed9d8601166d4350f276", "20th Century Fox Video Games - Videa, David Ross", "11029", "Meltdown (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "96eccc2277043508a6c481ea432d7dd9", "Thomas Jentzsch", "", "Missile Command (Atari Mouse) (2002) (TJ) (PAL)", "Uses Atari ST Mouse Controller", "Homebrew", "", "", "", "", "", "", "ATARIMOUSE", "", "", "", "", "", "", "YES", "" }, { "96f806fc62005205d851e758d050dfca", "", "", "Push (V0.05) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "97184b263722748757cfdc41107ca5c0", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9718b85ac5a55cbc7348963c63ffa35a", "Robby", "", "Demon Attack (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "972486110933623039a3581db308fda6", "", "", "Xeno Plus (Hack)", "Hack of Xenophobe", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "97327d6962f8c64e6f926f79cd01c6b9", "", "", "Jawbreaker (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "977294ae6526c31c7f9a166ee00964ad", "Atari - GCC, Douglas B. Macrae", "CX2677, CX2677P", "Dig Dug (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "97842fe847e8eb71263d6f92f7e122bd", "Imagic, Wilfredo Aguilar, Michael Becker, Dennis Koble", "720113-1A, 03206", "Solar Storm (1983) (Imagic)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01 45", "", "", "", "", "" }, { "97933c9f20873446e4c1f8a4da21575f", "", "", "Racquetball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "97a9bb5c3679d67f5c2cd17f30b85d95", "Atari", "", "Colors (1980) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "97cd63c483fe3c68b7ce939ab8f7a318", "Thomas Jentzsch", "", "Robot City (V0.21) (15-09-2002) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "97d0151beb84acbe82aa6db18cd91b98", "Steve Engelhardt", "", "Lunar Attack (2002) (Steve Engelhardt) (Hack)", "Hack of Z-Tack", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "97d079315c09796ff6d95a06e4b70171", "Activision, Garry Kitchen", "AZ-032", "Pressure Cooker (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9813b9e4b8a6fd919c86a40c6bda8c93", "Atari", "CX26177", "Ikari Warriors (1989) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9831efc7f4cb8ffb4df0082bab2f07a3", "Activision, Steve Cartwright - Ariola", "EAX-031, EAX-031-04B - 711 031-717", "Frostbite (1983) (Activision) (PAL) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9848b5ef7a0c02fe808b920a2ac566d2", "Skyworks Technology Inc.", "", "Baseball (2002) (Skyworks)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9853089672116117258097dbbdb939b7", "Hozer Video Games", "", "Gunfight 2600 - Cowboy Hair (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98555b95cb38e0e0b22b482b2b60a5b6", "", "", "Spinning Fireball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "98ba601a60172cb46c5bf9a962fd5b1f", "", "", "Gorilla Kong (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98ccd15345b1aee6caf51e05955f0261", "Retroactive", "", "Qb (V2.03) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "98e5e4d5c4dd9a986d30fd62bd2f75ae", "", "", "Air-Sea Battle (Unknown) (Hack) (4K)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98e6e34af45a0664597972c3bb31180f", "", "", "Space Instigators (V1.7) (17-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98e7caaab8ec237558378d2776c66616", "Bradford W. Mott", "", "HMOVE Test (Bradford W. Mott) (1998) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98ea10c47c13f1b3306c7b13db304865", "", "", "Jam Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98ec0fa4199b9c01f7b8fa3732e43372", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98ef1593624b409b9fb83a1c272a0aa7", "CCE", "C-831", "Cosmic Ark (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98f63949e656ff309cefa672146dc1b8", "Atari - Axlon, John Vifian", "CX26168", "Off the Wall (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "98fa3ad778a668a79449350de4b3b95b", "", "", "Thrust (V1.1) (2000) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9905f9f4706223dadee84f6867ede8e3", "HES", "", "Challenge (HES) (PAL)", "ROM must be started in bank 1 (Surfer's Paradise if right difficulty = 'A')", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9912d06eea42200a198dd3e2be18c601", "Imagic, Michael Greene", "IA3312", "No Escape! (1982) (Imagic) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "991d57bbcd529ad62925098e0aec1241", "", "", "Gunfight 2600 - The Final Kernel (MP) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9945a22f60bbaf6d04a8d73b3cf3db75", "Activision, Dan Kitchen", "EAX-039-04B, EAX-039-04I", "Kung-Fu Master (1987) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9947f1ebabb56fd075a96c6d37351efa", "CBS Electronics", "4L 2737 0000", "Omega Race (1983) (CBS Electronics)", "Set right difficulty to 'A' for BoosterGrip in both ports", "", "", "", "", "A", "", "", "BOOSTERGRIP", "BOOSTERGRIP", "", "", "", "", "", "", "" }, { "9962034ea7b3d4a905d0991804670087", "", "", "Grid Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9989f974c3cf9c641db6c8a70a2a2267", "Eckhard Stolberg", "", "Colours Selector (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "99a24d7bb31d49b720b422550b32c35f", "", "", "Hangman Ghost Biglist1 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "99f7c6c26046bbe95f1c604b25da8360", "SnailSoft", "", "Comitoid beta 2 (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9a01115206f32eb0b539c7e5a47ccafa", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (07-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9a165c39af3f050fdee6583fdfcdc9be", "Zirok", "", "Mario Bros. (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9a21fba9ee9794e0fadd7c7eb6be4e12", "Atari - Imagineering, Dan Kitchen", "CX26177", "Ikari Warriors (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9a25b3cfe2bbb847b66a97282200cca2", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 60", "", "", "", "", "" }, { "9a4274409216ff09ecde799f2a56ac73", "CCE", "C-801", "Mr. Postman (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9ab72d3fd2cc1a0c9adb504502579037", "Epyx, Steven A. Baker, Peter Engelbrite", "80561-00286", "California Games (1988) (Epyx)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9ad362179c2eea4ea115c7640b4b003e", "", "", "Barnstorming (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "NTSC50", "", "", "", "" }, { "9ad36e699ef6f45d9eb6c4cf90475c9f", "Imagic, Dennis Koble", "720103-1A, 720103-1B, IA3203, IX-010-04", "Atlantis (1982) (Imagic)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9aeb5206c5bf974892a9cc59f1478db3", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9af615951e9719df2244bc77fc50cb95", "Dactari - Milmar", "", "Defender (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9afdfe1cff7f37f1c971fe3f0c900606", "Funvision - Fund. International Co.", "", "Plug Attack (Funvision)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9b150a42fc788960fbb4cbe250259ee2", "Kroko", "", "3E Bankswitch Test (TIA @ $40)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9b21d8fc78cc4308990d99a4d906ec52", "CCE", "C-838", "Immies & Aggies (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "18", "223", "", "" }, { "9b246683f44c963a50e41d6b485bee77", "", "", "Boring (PAL) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9bb136b62521c67ac893213e01dd338f", "Xonox - Beck-Tech", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9bd4e0d5f28ba6da417c26649171f8e4", "", "", "Hangman Pac-Man Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9be58a14e055b0e7581fc4d6c2f6b31d", "", "", "Adventure (Color Scrolling) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9c27ef3bd01c611cdb80182a59463a82", "Arcadia Corporation, Kevin Norman", "AR-4103", "Killer Satellites (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9c40bf810f761ffc9c1b69c4647a8b84", "", "", "2 in 1 - Frostbite, River Raid (Unknown)", "", "", "", "2IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9c6d65bd3b477aace0376f705b354d68", "", "", "RPG Kernal (18-04-2003) (Paul Slocum) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9c6faa4ff7f2ae549bbcb14f582b70e4", "U.S. Games Corporation, Garry Kitchen, Paul Willson - Vidtec", "VC1002", "Sneak 'n Peek (1982) (U.S. Games)", "AKA Hide 'n Seek", "", "", "", "", "", "", "", "", "", "", "", "", "", "215", "", "" }, { "9c6fd6ed3599978ab7b6f900484b9be6", "Andrew Wallace", "", "Laseresal 2002 (PAL60) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "9c729017dd2f9ccbadcb511187f80e6b", "", "", "J-Pac (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9c7fa3cfcaaafb4e6daf1e2517d43d88", "", "", "PIEROXM Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9ca2deb61318eba4fb784d4bf7441d8b", "", "", "Purple Bar Demo 2 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9cbb07f1993a027bc2f87d5205457ec9", "", "", "Eckhard Stolberg's Scrolling Text Demo 1 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9d0befa555f003069a21d2f6847ad962", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9d1556ae5890398be7e3d57449774b40", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "27", "", "", "" }, { "9d2938eb2b17bb73e9a79bbc06053506", "Imagic, Michael Greene", "EIZ-002-04I", "Wing War (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9d2f05d0fe8b2dfcf770b02eda066fc1", "", "", "Push (V0.06) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9d33d31fb1de58c5460d8a67b57b36da", "", "", "Star Voyager (Genesis)", "Genesis controller (C is secondary lasers)", "Hack of Star Voyager", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "9d37a1be4a6e898026414b8fee2fc826", "M Network - APh Technological Consulting, David Rolfe - INTV", "MT5665", "Super Challenge Baseball (1982) (M Network)", "AKA Big League Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9d4bc7c6fe9a7c8c4aa24a237c340adb", "Dennis Debro", "", "Climber 5 (16-04-2003) (Dennis Debro)", "For Philly Classic 4", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9d522a3759aa855668e75962c84546f7", "Atari, Tom Rudadahl", "CX2634, CX2634P", "Golf (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9d7f04618bb4043f531d087e3aaa7ac8", "Parker Brothers, Larry Gelberg, Gary Goltz", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL) (16K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9de0d45731f90a0a922ab09228510393", "20th Century Fox Video Games - Sirius, Mark Turmell", "11003", "Fast Eddie (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9dec0be14d899e1aac4337acef5ab94a", "CommaVid, John Bronstein", "CM-003", "Cosmic Swarm (1982) (CommaVid) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9e01f7f95cb8596765e03b9a36e8e33c", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "9e192601829f5f5c2d3b51f8ae25dbe5", "PlayAround - J.H.M.", "201", "Cathouse Blues (1982) (PlayAround)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9e2c7299c69b602443d327c7dad51cbf", "Charles Morgan", "", "Xaxyrax Road (Charles Morgan) (Hack)", "Hack of Freeway", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9e437229136f1c5e6ef4c5f36178ed18", "Funvision - Fund. International Co.", "", "Grand Prize (Funvision)", "AKA Enduro", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9e5007131695621d06902ab3c960622a", "Sega", "", "Tac Scan (1983) (Sega) [h1]", "", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 60", "", "", "215", "YES", "" }, { "9e6fa031ece07919c816fba5dc8de43e", "", "", "Star Fire - Meteor Dance (13-11-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9e792a59f8795664cbaaff1ba152d731", "", "", "Bullet Demo (20-12-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9e904e2eaa471c050c491289b8b80f60", "", "", "How to Draw a Playfield II (1997) (Erik Mooney) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9ea8ed9dec03082973244a080941e58a", "Eric Mooney, Piero Cavina", "", "INV+", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9ec1b259a1bcffa63042a3c2b3b90f0a", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9eca521db1959156a115dee85a405194", "", "", "Fu Kung! (V0.08) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9ed0f2aa226c34d4f55f661442e8f22a", "", "", "Nuts (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "45", "", "", "" }, { "9eeb40f04a27efb1c68ba1d25e606607", "Kyle Pittman", "", "Rambo II (2003) (Kyle Pittman) (Hack)", "Hack of Double Dragon", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9efa877a98dd5a075e058214da428abb", "Hozer Video Games", "", "SCSIcide (1.32) (Hozer Video Games)", "Uses the Paddle Controllers", "New Release", "", "", "", "", "", "", "PADDLES_IAXDR", "", "", "AUTO 65", "", "", "", "", "" }, { "9efb4e1a15a6cdd286e4bcd7cd94b7b8", "20th Century Fox Video Games, John W.S. Marvin", "", "Planet of the Apes (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9f2d58dce1b81c6ba201ed103507c025", "", "", "Fu Kung! (V0.02) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9f48eeb47836cf145a15771775f0767a", "Atari, Warren Robinett", "CX2620", "Basic Programming (1979) (Atari)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "YES", "" }, { "9f5096a6f1a5049df87798eb59707583", "20th Century Fox Video Games, Mark Klein", "11036", "Entity, The (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9f59eddf9ba91a7d93bce7ee4b7693bc", "Thomas Jentzsch", "", "Montezuma's Revenge (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "9f8fad4badcd7be61bbd2bcaeef3c58f", "Parker Brothers, Charlie Heath", "PB5330", "Reactor (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "9f901509f0474bf9760e6ebd80e629cd", "Atari, Bob Whitehead - Sears", "CX2623 - 6-99819, 49-75108, 49-75125", "Home Run (1978) (Atari) (4K)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "9f93734c68f6479eb022cab40814142e", "", "", "Push (V0.07) (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9f9ee0f60c119c831e80694b6678ca1a", "Jeffry Johnston", "", "Radial Pong - Version 8 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9fa0c664b157a0c27d10319dbbca812c", "Chris Walton, Justin Hairgrove, Tony Morse", "", "Hunchy II (2005)", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "9fc2d1627dcdd8925f4c042e38eb0bc9", "Atari - GCC, John Allred, Mike Feinstein", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "E68E28752D3C54EDD3CCDA42C27E320C", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox)", "Genesis controller (B is jump and throw, C switches between players)", "Hack of Tomarc the Barbarian", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "a0028f057d496f22b549fd8deecc6f78", "Joe Grand", "", "SCSIcide Pre-release 6 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a00ec89d22fcc0c1a85bb542ddcb1178", "CCE", "C-1012", "Phoenix (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a00ee0aed5c8979add4c170f5322c706", "Barry Laws Jr.", "", "Egghead (Barry Laws Jr.) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "a0185c06297b2818f786d11a3f9e42c3", "", "", "International Soccer (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a025a8f83a42a4d6d46c4887e799bfac", "Hozer Video Games", "", "Gunfight 2600 - Descissions had to be made (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a0297c4788f9e91d43e522f4c561b4ad", "Atari - CCW, Gary Stark", "CX26102", "Cookie Monster Munch (1983) (Atari) (PAL)", "Uses Kids/Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "a0563dd6d8215c38c488fbbd61435626", "", "", "Ship Demo (V 1501) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a0675883f9b09a3595ddd66a6f5d3498", "Telegames", "6057 A227", "Quest for Quintana Roo (1988) (Telegames)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a075ad332942740c386f4c3814925ece", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (2 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a0d502dc8b90b1d7daa5f6effb10d349", "", "", "Demo Image Series #5 - Sam (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a0e2d310e3e98646268200c8f0f08f46", "Atari, Ed Logg, Carol Shaw", "CX2639, CX2639P", "Othello (1981) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a100eff2d7ae61ca2b8e65baf7e2aae8", "David Marli", "", "Muncher (David Marli) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "a11099b6ec24e4b00b8795744fb12005", "Activision - Bobco, Robert C. Polaro", "EAK-049-04B", "Rampage! (1989) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a1403fef01641dcd3980cac9f24d63f9", "Dactari - Milmar", "", "Atlantis (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a14d8a388083c60283e00592b18d4c6c", "", "", "Tunnel Demo (28-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a15b5831a1fab52e4c416068c85ec011", "Hozer Video Games", "", "Gunfight 2600 - The Good, The Bad, The Ugly (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a174cece06b3abc0aec3516913cdf9cc", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (1980) (Sears) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "PADDLES", "", "", "", "", "", "", "" }, { "a1770ef47146ab7b12e2c4beccd68806", "Digitel", "", "Kaystone Kapers (1983) (Digitel)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a184846d8904396830951217b47d13d9", "Activision, Dan Kitchen", "AX-029", "Crackpots (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a189f280521f4e5224d345efb4e75506", "Atari - Thomas Jentzsch", "", "Obelix (1983) (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a1bcbe0bfe6570da2661fc4de2f74e8a", "Imagic - Advanced Program Technology, Rob Fulop", "", "Actionauts (Microbots) (1984-2008) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a1ca372388b6465a693e4626cc98b865", "Quelle", "176.543 7", "Der Vielfrass (1983) (Quelle) (PAL)", "AKA Fast Food", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a1ead9c181d67859aa93c44e40f1709c", "American Videogame - Dunhill Electronics, Darrell Wagner, Todd Clark Holm, John Simonds", "", "Tax Avoiders (1986) (American Videogame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a1f9159121142d42e63e6fb807d337aa", "Quelle - Otto Versand", "700.223 1 - 781627", "Der moderne Ritter (1983) (Quelle) (PAL)", "AKA Fast Eddie", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a204cd4fb1944c86e800120706512a64", "Coleco", "2511", "Smurfs Save the Day (1983) (Coleco)", "Uses the Kid Vid Controller", "", "", "", "", "", "", "", "", "KIDVID", "", "", "", "", "", "", "" }, { "a20b7abbcdf90fbc29ac0fafa195bd12", "Quelle - Otto Versand", "719.383 2 - 649635, 781393, 781784, 986404", "Motocross (1983) (Quelle) (PAL)", "AKA Motorcross", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a20d931a8fddcd6f6116ed21ff5c4832", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a2170318a8ef4b50a1b1d38567c220d6", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) [a1]", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a23ffc86804240ce77134a1c91926685", "", "", "Star Fire - Paulstar WIP (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2424c1a0c783d7585d701b1c71b5fdc", "", "", "Video Pinball (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a25bb76e9e773117e567fd4300b1bb23", "", "", "Interleaved ChronoColour Demo (NTSC) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a28d872fc50fa6b64eb35981d0f4bb8d", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari) (4K)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a29df35557f31dfea2e2ae4609c6ebb7", "Atari", "", "Circus Atari (1980) (Atari) (Joystick)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a29fc854838e08c247553a7d883dd65b", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision) (16K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2aae759e4e76f85c8afec3b86529317", "", "", "Boom Bang (Unknown)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2de0fc85548871279ed2a3c1325c13e", "George Veeder", "", "Cat and Mouse (George Veeder) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "a2eb84cfeed55acd7fece7fefdc83fbb", "", "", "Kool Aid Man (Fixed) (15-11-2002) (CT)", "HMOVE handling fixed in this version", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a2f296ea2d6d4b59979bac5dfbf4edf0", "", "", "Warring Worms (28-01-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a302b922a8dbec47743f28b7f91d4cd8", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a30ece6dc4787e474fbc4090512838dc", "Zellers", "", "Circus (Zellers)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a310494ad5ba2b5b221a30d7180a0336", "", "", "Demo Image Series #6 - Mario (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a336beac1f0a835614200ecd9c41fd70", "Atari, Christopher H. Omarzu, Robert Vieira", "CX26121", "Zoo Keeper Sounds (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a34560841e0878c7b14cc65f79f6967d", "Multivision, Michael Case", "", "Harem (1982) (Multivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a3486c0b8110d9d4b1db5d8a280723c6", "Atari, Alan J. Murphy, Robert C. Polaro", "CX26100", "Bugs Bunny (08-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a35d47898b2b16ec641d1dfa8a45c2b7", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a3873d7c544af459f40d58dfcfb78887", "", "", "Tennis (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a3b9d2be822eab07e7f4b10593fb5eaa", "", "", "GREGXM Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a3c1c70024d7aabb41381adbfb6d3b25", "Telesys, Alex Leavens", "1005", "Stargunner (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a3d7c299fbcd7b637898ee0fdcfc47fc", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (Preview) (1982) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "a3f2a0fcf74bbc5fa763b0ee979b05b1", "Quelle", "873.790 0", "Eishockey-Fieber (1983) (Quelle) (PAL)", "AKA Ice Hockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a3f8aebb38182749cb8da85cfbc63d7c", "", "", "Tennis (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a3fee8ce15525ea00d45a06f04c215d1", "Aaron Curtis", "", "AStar (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "a406d2f6d84e61d842f4cb13b2b1cfa7", "Tigervision, John Harris - Teldec", "7-002", "Jawbreaker (1982) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a412c8577b2d57b09185ae51739ac54f", "Arcadia Corporation, Dennis Caswell", "AR-4000", "Phaser Patrol (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "24", "", "YES", "" }, { "a41450333f8dd0e96e5e9f0af3770ae9", "", "", "Basic Math (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a422194290c64ef9d444da9d6a207807", "M Network - APh Technological Consulting, Hal Finney", "MT5667", "Dark Cavern (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a443d8557d712845c8cd3699363a42e6", "", "", "Star Fire (07-01-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a47878a760f5fa3aa99f95c3fdc70a0b", "", "", "Demo Image Series #5 - Baboon (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4790224bd5afabd53cbe93e46a7f241", "Activision, Bob Whitehead", "AG-019", "Sky Jinks (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a47e26096de6f6487bf5dd2d1cced294", "Atari", "CX2643", "Codebreaker (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "a499d720e7ee35c62424de882a3351b6", "Sega - Beck-Tech, Steve Beck, Phat Ho", "009-01", "Up 'n Down (1984) (Sega)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4aa7630e4c0ad7ebb9837d2d81de801", "", "", "Atari 2600 Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4ab331e8768eafdc20ce8b0411ff77a", "", "", "Demo Image Series #1 - Sam (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4b9423877a0b86ca35b52ca3c994ac5", "CCE", "C-805", "Sea Monster (1983) (CCE)", "O Monstro Marinho", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "a4b99aa5ed85cfdb7d101923147de035", "Jim Goebel", "", "Pac-Law (Jim Goebel) (Hack)", "Hack of Outlaw", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4c08c4994eb9d24fb78be1793e82e26", "Activision, Alan Miller", "AX-012, CAX-012, AX-012-04", "Ice Hockey (1981) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4d026a5c200ef98518ebb77719fe8dc", "Kyle Pittman", "", "SpongeBob SquarePants (2003) (Kyle Pittman) (Hack)", "Hack of Revenge of the Beefsteak Tomatoes", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4e885726af9d97b12bb5a36792eab63", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "223", "", "" }, { "a4ecb54f877cd94515527b11e698608c", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26119", "Saboteur (12-20-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4f1cea2c8479284e2a2292f8d51b5fa", "", "", "Gunfight 2600 - The Final Kernel Part 2 (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a4ff39d513b993159911efe01ac12eba", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694", "Pole Position (1983) (Atari)", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a511f7ee13e4b35512f9217a677b4028", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2674", "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a5262fe6d01d6a1253692682a47f79dd", "", "", "JKH Text Scrolling Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a537879d8e82e1061d3ad800479d3b84", "Andrew Wallace", "", "Brooni (2001) (Andrew Wallace) (PD) (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a539b9fd1ba57e46442b3e9351e6383b", "", "", "River Raid (208 in 1) (Unknown) (PAL) (Hack) [a]", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a56b642a3d3ab9bbeee63cd44eb73216", "Carrere Video - JWDA, Sylvia Day, Todd Marshall, Robin McDaniel, Henry Will IV - Teldec - Prism", "USC2001", "Gopher (1983) (Carrere Video) (PAL)", "AKA Vossicht Whlmaus!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a5855d73d304d83ef07dde03e379619f", "Atari, David Crane", "", "Boggle (08-07-1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "215", "YES", "" }, { "a58b11148c18d85e4c2aef4ff46ade67", "", "", "Video Chess (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a591b5e8587aae0d984a0f6fe2cc7d1c", "", "", "Globe Trotter Demo (24-03-2003) (Weston)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a5b7f420ca6cc1384da0fed523920d8e", "", "", "Adventure (New Graphics) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a5c96b046d5f8b7c96daaa12f925bef8", "Activision, Alan Miller - Ariola", "EAG-007, EAG-007-04I, PAG-007 - 711 007-720", "Tennis (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a5e9ed3033fb2836e80aa7a420376788", "Atari, Carla Meninsky", "CX2637, CX2637P", "Dodge 'Em (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a60598ad7ee9c5ccad42d5b0df1570a1", "Atari, Alan Miller", "CX26163P", "Surround (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a6127f470306eed359d85eb4a9cf3c96", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a62e3e19280ff958407e05ca0a2d5ec7", "", "", "Hangman Ghost Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a6737c81542a99ee71cb5f5ff14703d9", "", "", "Scrolling Playfield 3 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a69f5b1761a8a11c98e706ec7204937f", "", "", "Pharaoh's Curse (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "34", "", "YES", "" }, { "a74689a08746a667a299b0507e1e6dd9", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (1983) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a7523db9a33e9417637be0e71fa4377c", "Videospielkassette - Ariola", "PGP238", "Gangster (Ariola) (PAL)", "AKA Outlaw", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a7673809068062106db8e9d10b56a5b3", "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira", "CX26118, CX26118P", "Millipede (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a779b9fa02c62d00d7c31ed51268f18a", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a7a58e9291aefa1064e933071f60d4ef", "Arcadia Corporation, Dennis Caswell", "1 AR-4000, AR-4100", "Phaser Patrol (1982) (Arcadia) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a7b584937911d60c120677fe0d47f36f", "M Network - APh Technological Consulting, Hal Finney - INTV", "MT5661", "Armor Ambush (1982) (M Network)", "AKA Tank Battle", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a7b96a8150600b3e800a4689c3ec60a2", "Atari, Mike Lorenzen - Sears", "CX2630 - 49-75122", "Circus Atari (1980) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01 55", "", "", "", "", "" }, { "a7cf2b9afdbb3a161bf418dbcf0321dc", "Barry Laws Jr.", "", "Attack Of The Mutant Space Urchins (2002) (Barry Laws Jr.) (Hack)", "Hack of Alien", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a7ed7dc5cbc901388afa59030fb11d26", "Atari, Warren Robinett", "CX2606, CX2606P", "Slot Racers (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a7ef44ccb5b9000caf02df3e6da71a92", "Atari, Ian Shepard - Sears", "CX2604 - 6-99812, 49-75106", "Space War (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8101cb667e50a46165c6fb48c608b6b", "", "", "Kung Fu Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a81697b0c8bbc338ae4d0046ede0646b", "CCE", "", "Gravitar (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a81b29177f258494b499fbac69789cef", "Greg Thompson", "", "Console Wars (Greg Thompson) (Hack)", "Hack of Space Jockey", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a83b070b485cf1fb4d5a48da153fdf1a", "Apollo", "AP-2011", "Pompeii (1983) (Apollo) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8435ec570141de5d833c4abec499e55", "", "", "Happy Birthday Demo (2001) (Dennis Debro) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8633050a686270fcf6c0cc4dcbad630", "Zirok", "", "Phoenix (Zirok)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a867b76098786c4091dba2fcee5084c3", "", "", "Dragrace (Hack)", "Hack of Dragster", "Hack", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "a875f0a919129b4f1b5103ddd200d2fe", "Atari, Dan Hitchens. Mimi Nyden", "CX2656", "SwordQuest - EarthWorld (1982) (Atari) (PAL)", "AKA Adventure I, SwordQuest I - EarthWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8916734ff8c64ec3342f4c73fd5b57d", "Atari", "", "Stand Alone Test Cart (1982) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a89a3e0547d6887279c34aba4b17a560", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (1983) (Mattel) (Prototype)", "", "Prototype", "", "4K", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8a703e073183a89c94d4d99b9661b7f", "Franklin Cruz", "", "Spice Invaders (Franklin Cruz) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8b3ea6836b99bea77c8f603cf1ea187", "CCE", "C-861", "Boxing (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8c48b4e0bf35fe97cc84fdd2c507f78", "Puzzy - Bit Corporation", "PG201", "Seamonster (1982) (Puzzy)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "a8d0a4a77cd71ac601bd71df5a060e4c", "", "", "Space Shuttle (1983) (Activision) [t2] (Fuel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8d4a9500b18b0a067a1f272f869e094", "", "", "Red And White Checkerboard Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a8e49d7e24ce293629ca29614862821b", "", "", "Enduro (Genesis)", "Genesis controller (B is acceleration, C is brakes)", "Hack of Enduro", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "a91d0858a52de3a2e6468437212d93e8", "", "", "Q-bert (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a936d80083e99d48752ad15c2b5f7c96", "", "", "Room of Doom (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a93e8ea1f565c3c1e86b708cf0dc2fa9", "Jess Ragan", "", "Kabul! (Jess Ragan) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "a94528ae05dd051894e945d4d2349b3b", "Genus", "", "River Raid (Genus)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a94b8ca630f467b574b614808d813919", "HES", "773-883", "2 Pak Special - Space Voyage, Fire Alert (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a9531c763077464307086ec9a1fd057d", "Atari, John Dunn - Sears", "CX2631 - 49-75152", "Superman (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a957dbe7d85ea89133346ad56fbda03f", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "a97733b0852ee3096300102cb0689175", "CCE", "C-834", "Fast Eddie (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a9784c24cddb33bd0d14442b97784f3d", "", "", "Omega Race DC (2003) (TJ) (Omega Race Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a98b649912b6ca19eaf5c2d2faf38562", "", "", "This Planet Sucks (Greg Troutman) (PAL) [!]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "a995b6cbdb1f0433abc74050808590e6", "Imagic, Rob Fulop, Bob Smith", "720106-1A, IA3600", "Riddle of the Sphinx (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a9cb638cd2cb2e8e0643d7a67db4281c", "M Network - APh Technological Consulting, Larry Zwick - INTV", "MT5861", "Air Raiders (1983) (M Network)", "AKA Air Battle", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "a9d9e19d0c89fb31780b5d63e1f8c6a4", "AtariAge, Chris Spry", "CX26201", "Zippy the Porcupine (2014) (Sprybug) (PAL60)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "a9e3c23599c0d77151602f8e31daf879", "", "", "Kung Fu Master (Genesis)", "Genesis controller (C is extra kick modes)", "Hack of Kung Fu Master", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "aa1c41f86ec44c0a44eb64c332ce08af", "Spectravideo, David Lubar", "SA-218", "Bumper Bash (1983) (Spectravideo)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "20", "", "", "" }, { "aa2c4b32656bde9a75042a4d158583e1", "", "", "Oystron X (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aa5cfe3b20395aba1d479135943ad85c", "", "", "Defender (Hack) (Unknown)", "", "Hack of Defender", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aa7bb54d2c189a31bb1fa20099e42859", "CBS Electronics, Ed English", "4L4478", "Mr. Do! (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "aa8e4b2cb8a78ffe6b20580033f4dec9", "", "", "Bitmap Demo (13-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aaac0d277eda054861e613c59c2e4ff2", "JWDA, Todd Marshall", "", "Music Demo (JWDA)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aab840db22075aa0f6a6b83a597f8890", "Home Vision, R.J.P.G. - Gem International Corp. - VDI", "VCS83124", "Racing Car (1983) (Home Vision) (PAL)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "aad61898633f470ce528e3d7ef3d0adb", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a1]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aad91be0bf78d33d29758876d999848a", "Activision, David Crane", "AX-018, AX-018-04", "Pitfall! (1981) (Activision) (Prototype)", "Pitfall Harry's Jungle Adventure (Jungle Runner)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aaea37b65db9e492798f0105a6915e96", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Tug of War (2 of 3) (1983) (Arcadia)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "02", "", "", "", "", "" }, { "aafc79ffc32c4c9b2d73c8ada7602cfe", "", "", "Planet Patrol (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab10f2974dee73dab4579f0cab35fca6", "ITT Family Games", "", "Wilma Wanderer (1983) (ITT Family Games) (PAL)", "AKA Lilly Adventure", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab2cfcaad3daaf673b2b14fdbb8dac33", "M Network, David Akers, Joe King, Patricia Lewis Du Long, Jeff Ratcliff - INTV", "MT7045", "Bump 'n' Jump (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab2ea35dcc1098c87455bb8210b018cf", "", "", "Fu Kung! (V0.04 Single Line Resolution) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab301d3d7f2f4fe3fdd8a3540b7a74f5", "Jone Yuan Telephonic Enterprise Co", "", "IQ 180 (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "27", "230", "", "" }, { "ab434f4c942d6472e75d5490cc4dd128", "HES", "773-875", "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab4ac994865fb16ebb85738316309457", "Atari, Alan Miller - Sears", "CX2624 - 6-99826, 49-75113", "Basketball (1978) (Atari)", "Console ports are swapped", "Common", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "ab56f1b2542a05bebc4fbccfc4803a38", "Activision - Imagineering, Dan Kitchen, David Lubar", "AK-048-04", "River Raid II (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab5bf1ef5e463ad1cbb11b6a33797228", "Imagic, Rob Fulop", "720104-1A, 720104-1B, IA3204", "Cosmic Ark (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab60ea7b707c58d356cad858eb18db43", "", "", "Tazer (John K. Harvey)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ab8d318da4addd39c65b7f9c408df2a6", "", "", "Star Trek (Genesis)", "Genesis controller (B is phaser, C is warp)", "Hack of Star Trek", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "YES", "" }, { "abb740bea0a6842831b4f53112fb8145", "", "", "Qb (V1.01) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "abb741c83f665d73c86d90a7d9292a9b", "Telegames", "", "Space Attack (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "abc64037ca5d5b04ae8a7eedbca3ed74", "", "", "Green and Yellow Number 1 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "abe40542e4ff2d1c51aa2bb033f09984", "Absolute Entertainment, David Crane", "EAZ-042-04B, EAZ-042-04I", "Skate Boardin' (1987) (Absolute) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ac05c0e53a5e7009ddd75ed4b99949fc", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ac0ddbcff34d064009591607746e33b8", "Thomas Jentzsch", "", "Atlantis FH (2003) (TJ) (Hack)", "Hack of Atlantis", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ac26d7d37248d1d8eac5eccacdbef8db", "", "", "Snail Against Squirrel (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ac3dd22dd945724be705ddd2785487c2", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (06-15-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ac53b83e1b57a601eeae9d3ce1b4a458", "Retroactive", "", "Qb (2.15) (Retroactive) (NTSC)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ac5f78bae0638cf3f2a0c8d07eb4df69", "", "", "Minesweeper (V.99) (Soren Gust) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ac7c2260378975614192ca2bc3d20e0b", "Activision, David Crane", "AG-930-04, AZ-030", "Decathlon (1983) (Activision)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ac9adbd6de786a242e19d4bec527982b", "Activision, Alan Miller - Ariola", "EAG-012-04I, EAX-012, EAX-012-04B - 711 012-720", "Ice Hockey (1981) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aca09ffea77174b148b96b205109db4d", "Activision, Alan Miller", "AG-007, CAG-007", "Tennis (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "acaa27d214039d89d7031609aafa55c3", "", "", "Sprite Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "acb6787b938079f4e74313a905ec3ceb", "", "", "Chronocolor Donkey Kong (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "acb7750b4d0c4bd34969802a7deb2990", "Parker Brothers, Ed Temple", "PB5310", "Amidar (1982) (Parker Bros)", "", "Uncommon", "", "", "A", "A", "", "", "", "", "", "", "", "", "", "", "" }, { "acb962473185d7a652f90ed6591ae13b", "Imagic, Dennis Koble", "IA3203, IX-010-04", "Atlantis (1982) (Imagic) (16K)", "AKA Lost City of Atlantis", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ace319dc4f76548659876741a6690d57", "Atari, Steve Wright", "CX2616", "Pele's Soccer (1981) (Atari)", "AKA Pele's Championship Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ad2e6bfb3b9b9b36ba8bf493ce764c49", "", "", "2600 Collison Demo 1 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ad42e3ca3144e2159e26be123471bffc", "Atari", "CX26163P", "Human Cannonball (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ad7e97c19bd25d5aa3999430845c755b", "", "", "Sprite Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ad8072675109d13fdd31a2e0403d5cff", "Funvision - Fund. International Co.", "", "Tank City (Funvision)", "AKA Thunderground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "adb770ff70e9adf08bbb907a7eccd240", "", "", "Inv Demo 3 (2001) (Erik Mooney) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "adb79f9ac1a633cdd44954e2eac14774", "Digivision", "", "Frostbite (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "adf1afac3bdd7b36d2eda5949f1a0fa3", "Quelle - Otto Versand", "495.463 2 - 746381", "Angriff der Luftflotten (1983) (Quelle) (PAL)", "AKA Paris Attack, M.A.D.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "adfbd2e8a38f96e03751717f7422851d", "Champ Games", "CG-01-N", "Lady Bug (NTSC)", "", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ae047e9468bda961d8e9e9d8ff52980f", "", "", "Tunnel Demo (Red Spiral) (30-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ae0d4f3396cb49de0fabdff03cb2756f", "Retroactive", "", "Qb (V2.02) (PAL) (2001) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ae10527840a1ac24de43730645ed508d", "Charles Morgan", "", "Planet Invaders (Charles Morgan) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ae18c11e4d7ed2437f0bf5d167c0e96c", "", "", "Multi-Color Demo 3 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ae2f1f69bb38355395c1c75c81acc644", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-23-1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ae465044dfba287d344ba468820995d7", "", "", "Inca Gold (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ae4be3a36b285c1a1dff202157e2155d", "Spectravideo", "SA-210", "Master Builder (1983) (Spectravideo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ae682886058cd6981c4b8e93e7b019cf", "Retroactive", "", "Qb (V0.12) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ae6cb335470788b94beb5787976e8818", "", "", "Mortal Kurling (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ae83541cf4a4c0bce0adccd2c1bf6288", "", "", "Maze 003 Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ae97cf8ed21f4154b4360a3cf6c95c5e", "", "", "Teleterm 2600 (John K. Harvey) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aeb104f1e7b166bc0cbaca0a968fde51", "", "", "Ms. Pac-Man (1999) (Hack)", "Hack of Ms. Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aec9b885d0e8b24e871925630884095c", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype)", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aed0b7bd64cc384f85fdea33e28daf3b", "Atari, Alan J. Murphy, Robert C. Polaro", "CX2666", "RealSports Volleyball (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "aed82052f7589df05a3f417bb4e45f0c", "Atari, Warren Robinett - Sears", "CX2606 - 6-99825, 49-75112", "Slot Racers (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "af6ab88d3d7c7417db2b3b3c70b0da0a", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "af6f3e9718bccfcd8afb421f96561a34", "Atari, Tod Frye", "CX2695", "Xevious (01-18-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "afb3bc45c6a82739cc82582127cd96e6", "Atari - Sculptured Software, Adam Clayton", "CX26151, CX26151P", "Dungeon (11-22-1985) (Atari) (Prototype)", "Dark Chambers Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "afc194534c1b346609ef05eff6d3cef6", "Jone Yuan Telephonic Enterprise Co", "", "Boxing (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "afd2cf258d51ae4965ee21abba3627ab", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (12-08-1982) (Atari) (Prototype)", "Uses the Keypad Controller", "Prototype", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "", "" }, { "afe4eefc7d885c277fc0649507fbcd84", "Atari", "CX26163P", "Ant Party (32 in 1) (1988) (Atari) (PAL)", "AKA Cosmic Swarm", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "afe776db50e3378cd6f29c7cdd79104a", "Thomas Jentzsch", "", "Bobby is Going Home (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "23", "245", "", "" }, { "afe88aae81d99e0947c0cfb687b16251", "Apollo - Games by Apollo", "AP-2006", "Infiltrate (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "aff8cba0f2d2eb239953dd7116894a08", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b00088418fc891f3faa3d4ddde6ace94", "", "", "Unknown Title (bin00007 (200102)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b00a8bc9d7fe7080980a514005cbad13", "K-Tel Vision", "", "Vulture Attack (1982) (K-Tel Vision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b00e8217633e870bf39d948662a52aac", "Konami", "RC 102-X 02", "Marine Wars (1983) (Konami)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b049fc8ac50be7c2f28418817979c637", "Activision - Imagineering, Dan Kitchen, David Lubar", "EAK-048-04, EAK-048-04B", "River Raid II (1988) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b06050f686c6b857d0df1b79fea47bb4", "Activision", "AIZ-001", "Moonsweeper (1988) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b061e98a4c854a672aadefa233236e51", "Atari, Warren Robinett", "CX2620, CX2620P", "Basic Programming (1979) (Atari) (PAL)", "Uses Keypad Controllers", "Common", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "YES", "" }, { "b095009004df341386d22b2a3fae3c81", "", "", "Sub-Scan (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b09b79c9628878be051e89f7f1e77378", "Activision, Larry Kaplan, David Crane - Ariola", "EAG-010, PAG-010 - 711 010-720", "Kaboom! (1981) (Activision) (PAL) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "b0ba51723b9330797985808db598fc31", "Atari, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "b0c47e426c7f799aee2c40422df8f56a", "", "", "Space Treat (PAL) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b0c9cf89a6d4e612524f4fd48b5bb562", "Atari - GCC", "CX2663", "Combat Two (1982) (Atari) (Prototype)", "AKA Super Combat", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b0e1ee07fbc73493eac5651a52f90f00", "Colin Hughes", "", "Tetris 2600 (Colin Hughes)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b12a7f63787a6bb08e683837a8ed3f18", "Imagic, Rob Fulop", "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04", "Demon Attack (1982) (Imagic) [fixed]", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b1339c56a9ea63122232fe4328373ac5", "Goliath - Hot Shot", "83-215", "Dream Flight (1983) (Goliath) (PAL)", "AKA Nightmare", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "b1486e12de717013376447ac6f7f3a80", "Spectravideo, Mark Turmell, Quelle", "SA-217, SA-217C - 413.723 8", "Gas Hog - Piraten Schiff (1983) (Spectravideo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b15026b43c6758609667468434766dd8", "Retroactive", "", "Qb (0.06) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b16cd9784589219391c839cb68c47b9c", "Video Soft, Jerry Lawson, Dan McElroy", "", "Golf Diagnostic (1983) (Video Soft) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b17b9cc4103844dcda54f77f44acc93a", "Quelle", "377.943 6", "Stopp die Gangster (1983) (Quelle) (PAL)", "AKA Gangster Alley", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b1a6c96e9093352106bc335e96caa154", "Joe Grand", "", "SCSIcide Pre-release 1 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "38", "", "", "" }, { "b1b20536aef4eed9c79dc5804f077862", "", "", "Euchre (NTSC) (09-11-2001) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b1c14b5ac896400cc91c8e5dd67acb59", "", "", "River Raid (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b1d1e083dc9e7d9a5dc1627869d2ade7", "CCE", "C-1004", "Mario's Bros. (1983) (CCE)", "AKA Mario Bros.", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b1e2d5dc1353af6d56cd2fe7cfe75254", "Atari - Axlon, Steve DeFrisco", "CX26171", "MotoRodeo (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b1fd0b71de9f6eeb5143a97963674cb6", "", "", "Multi-Color Demo 7 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b227175699e372b8fe10ce243ad6dda5", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [a1]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b23ebf427713dd0198b7ef47dbd07ef4", "Jone Yuan Telephonic Enterprise Co", "", "Sky Diver (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b24f6a5820a4b7763a3d547e3e07441d", "CCE", "C-823", "Demon Attack (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b26506fbf411009e5e3f7365f442960e", "Atari, Alan Miller", "CX2642", "Hunt & Score (1978) (Atari) (PAL) (4K)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "b2737034f974535f5c0c6431ab8caf73", "CBS Electronics, Richard K. Balaska Jr., Andy Frank, Stuart Ross", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b2761efb8a11fc59b00a3b9d78022ad6", "Atari, Bob Whitehead - Sears", "CX2651 - 99805, 49-75602", "Blackjack (1977) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "" }, { "b290c2b139344fcff5b312c71b9ac3b2", "Atari", "CX26163P", "UFO (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b29359f7de62fed6e6ad4c948f699df8", "Goliath", "3", "Phantom Tank (1983) (Goliath) (PAL)", "AKA Tanks But No Tanks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b2a6f31636b699aeda900f07152bab6e", "", "", "Space Instigators (Public Release 2) (06-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b2d1e63f7f22864096b7b6c154151d55", "Fabrizio Zavagli", "", "Bounce! (17-03-2003) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b2d3bcee001cff2bd2d8a21b2cb55109", "Atari - GCC, Mike Feinstein, Kevin Osborn", "CX2691", "Joust (08-09-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b2d5d200f0af8485413fad957828582a", "Atari - Bobco, Robert C. Polaro", "CX26155P", "Sprint Master (1988) (Atari) (PAL)", "AKA Sprint 88, Sprint 2000", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b2f0d7217147160b2f481954cedf814b", "", "", "Marquee Drawer (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b3017e397f74efd53caf8fae0a38e3fe", "Retroactive", "", "Qb (2.12) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b311ab95e85bc0162308390728a7361d", "Parker Brothers - Roklan", "PB5080", "Gyruss (1984) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b31dc989f594764eacfa7931cead0050", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (2 of 3) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b31f178aa0d569cccac7959f84e0a724", "Atari, Jerome Domurat, Steve Woita", "CX2699", "Taz (07-13-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b3203e383b435f7e43f9492893c7469f", "Gameworld", "133-003", "Sssnake (1983) (Gameworld) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b36040a2f9ecafa73d835d804a572dbf", "Digitel", "", "Pac Man (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b37f0fe822b92ca8f5e330bf62d56ea9", "Xonox - K-Tel Software - Beck-Tech, Steve Beck", "6210, 7210, 06003. 99001", "Spike's Peak (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b392964e8b1c9c2bed12246f228011b2", "", "", "Name This Game (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b4030c38a720dd84b84178b6ce1fc749", "M Network - APh Technological Consulting, Kevin Miller", "MT5687", "International Soccer (1982) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b40dea357d41c5408546e4e4d5f27779", "Digivision", "", "Spider Fighter (Digivision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b41fdd4a522e1d5a2721840028684ac2", "", "", "Green and Yellow Number 1 Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b42df8d92e3118dc594cecd575f515d7", "Mystique - American Multiple Industries", "1003", "Burning Desire (1982) (Mystique) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b438a6aa9d4b9b8f0b2ddb51323b21e4", "Telegames", "5861 A030", "Bogey Blaster (1988) (Telegames) (PAL)", "AKA Air Raiders", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b451307b8b5e29f1c5f2cf064f6c7227", "", "", "Demo Image Series #6 - Mario (Fixed) (26-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b49331b237c8f11d5f36fe2054a7b92b", "", "", "Condor Attack (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b4a4c87840613f102acb5b3a647d0a67", "", "", "Mobile 48 Sprite Kernel (04-01-2003) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b4daedb43511521db9036d503b3c1b69", "", "", "Sokoban (01-01-2003) (Adam Wozniak) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b4e2fd27d3180f0f4eb1065afc0d7fc9", "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, William O. Sheppard", "5002002", "London Blitz (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b4f05e544834d0238a0c263491775edf", "Starpath Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (Preview) (1982) (Starpath) (PAL)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b4f31ea8a6cc9f1fd4d5585a87c3b487", "Mystique - American Multiple Industries, Joel H. Martin", "", "Beat 'Em & Eat 'Em (1982) (Mystique) (PAL)", "Uses the Paddle Controller (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 45", "", "", "", "", "" }, { "b4f87ce75f7329c18301a2505fe59cd3", "Videospielkassett - Ariola", "PGP232", "Autorennen (Ariola) (PAL)", "AKA Grand Prix", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b50ae55aac93fbed258bc5a873edd2cb", "Recompile", "", "E.T. The Extra-Terrestrial (Recompile) (Hack)", "www.neocomputer.org/projects/et", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b5110f55ed99d5279f18266d001a8cd5", "Eckhard Stolberg", "", "Auto-mobile Demo (2001) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b56264f738b2eb2c8f7cf5a2a75e5fdc", "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko", "CX2694, CX2694P", "Pole Position (1983) (Atari) (PAL)", "AKA RealSports Driving", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b5657d4c1c732fbb6af150668464247f", "Arcadia Corporation, Stephen H. Landrum", "AR-4400", "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b59417d083b0be2d49a7d93769880a4b", "Pet Boat", "", "Donkey Kong (1983) (Pet Boat) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b59fd465abf76f64c85652ff29d5952d", "VentureVision, Dan Oliver", "", "Innerspace (1983) (VentureVision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b5a1a189601a785bdb2f02a424080412", "Imagic, Dennis Koble", "720021-1A, IA3410", "Shootin' Gallery (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b5cb9cf6e668ea3f4cc2be00ea70ec3c", "CommaVid, Irwin Gaines - Ariola", "CM-005 - 712 005-720", "Mines of Minos (1982) (CommaVid) (PAL)", "AKA Im Labyrinth des Roboters", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b5cdbab514ea726a14383cff6db40e26", "Video Gems", "VG-04", "Mission Survive (1983) (Video Gems) (PAL) [a]", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b5efe0271d2214e4d5dc798881486884", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (06-14-1990) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b6166f15720fdf192932f1f76df5b65d", "Amiga - Video Soft", "3130", "Off Your Rocker (1983) (Amiga) (Prototype)", "Uses the Amiga Joyboard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b64426e787f04ff23ee629182c168603", "Dynacom", "", "Plaque Attack (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b65d4a38d6047735824ee99684f3515e", "Dynacom", "", "MegaBoy (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b676a9b7094e0345a76ef027091d916b", "Thomas Jentzsch", "", "Mission Survive (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "", "220", "YES", "" }, { "b6812eaf87127f043e78f91f2028f9f4", "Simage", "", "Eli's Ladder (1984) (Simage)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b6821ac51c4c1dcb283f01be2f047dc1", "", "", "Rubik's Cube 3D Demo (25-11-2002) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b6960be26bee87d53ba4e2e71cfe772f", "", "", "3-D Corridor (Spiral Words) (31-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b6d52a0cf53ad4216feb04147301f87d", "Imagic, Michael Greene", "720055-1A, IA3312", "No Escape! (1983) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b6e40bce550672e5495a8cdde7075b8b", "Arcadia Corporation, Steve Mundry, Scott Nelson", "AR-4401", "Survival Island (1 of 3) (1983) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b702641d698c60bcdc922dbd8c9dd49c", "Atari, Ian Shepard", "CX26163P", "Space War (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b719ada17771a8d206c7976553825139", "Ron Corcoran", "", "DUP Space Invaders (Ron Corcoran) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b731d35e4ac6b3b47eba5dd0991f452f", "", "", "Rubik's Cube 3D Demo (Final) (08-01-2003) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b7345220a0c587f3b0c47af33ebe533c", "Quelle", "176.433 1", "Landungskommando (1983) (Quelle) (PAL)", "AKA Strategy X", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b76fbadc8ffb1f83e2ca08b6fb4d6c9f", "Activision, Bob Whitehead", "AG-005, CAG-005, AG-005-04", "Skiing (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b77468d586957d1b7fb4cccda2684f47", "Atari", "CX26163P", "Boxing (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b7903268e235310dc346a164af4c7022", "Thomas Jentzsch", "", "Cat Trax (Thomas Jentzsch) (PAL60)", "NTSC Conversion", "Hack", "", "", "", "", "", "", "", "", "", "", "PAL60", "30", "", "YES", "" }, { "b79fe32320388a197ac3a0b932cc2189", "Imagic, Bob Smith", "13207, EIZ-001-04I", "Moonsweeper (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b7a7e34e304e4b7bc565ec01ba33ea27", "Parker Brothers", "PB5820", "Mr. Do!'s Castle (1984) (Parker Bros) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b7b1d3ce07e75976c43a2dca3866237e", "Atari", "CX26163P", "Freeway Chicken (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Freeway", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b7e459d5416eeb196aaa8e092db14463", "", "", "Push (V0.02) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b7f184013991823fc02a6557341d2a7a", "", "", "Blue Rod Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b80d50ecee73919a507498d0a4d922ae", "20th Century Fox Video Games - Sirius Software, David Lubar", "11008", "Fantastic Voyage (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b816296311019ab69a21cb9e9e235d12", "Atari, Bob Whitehead - Sears", "CX2652 - 6-99816, 49-75151", "Casino (1979) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "" }, { "b822fba8b7c8a97ea4e92aeb2c455ef9", "Dactari", "", "Freeway (Dactari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b83579c4450fcbdf2b108903731fa734", "", "", "Mission 3,000 A.D. (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b83df1f32b4539c324bdf94851b4db55", "Angelino", "", "One On One by Angelino (Basketball Hack)", "Hack of Basketball (1978) (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b86552198f52cfce721bafb496363099", "Apollo, Tim Martin", "AP-2007", "Kyphus (1982) (Apollo) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b86a12e53ab107b6caedd4e0272aa034", "Funvision - Fund. International Co.", "", "Treasure Hunting (Funvision)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b879e13fd99382e09bcaf1d87ad84add", "Zellers", "", "Time Warp (Zellers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b8865f05676e64f3bec72b9defdacfa7", "Activision, David Crane", "AG-004", "Fishing Derby (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b897f9e3f939b9f21566d56db812a84e", "Atari, Jim Huether", "CX26163P", "Flag Capture (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b8ed78afdb1e6cfe44ef6e3428789d5f", "Data Age, J. Ray Dettling", "112-007", "Bermuda Triangle (1983) (Data Age)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b9232c1de494875efe1858fc8390616d", "Panda", "110", "Harbor Escape (1983) (Panda)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b9336ed6d94a5cc81a16483b0a946a73", "Atari, Jerome Domurat, Michael Sierchio", "CX2667, CX2667P", "RealSports Soccer (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "b958d5fd9574c5cf9ece4b9421c28ecd", "Piero Cavina", "", "Multi-Sprite Game V1.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b95a6274ca0e0c773bfdc06b4c3daa42", "Paul Slocum", "", "3-D Corridor (29-03-2003) (Paul Slocum)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b98cc2c6f7a0f05176f74f0f62c45488", "Spectravideo", "SV-010", "CompuMate (1983) (Spectravideo)", "", "", "", "CM", "", "", "", "", "COMPUMATE", "COMPUMATE", "", "", "", "", "", "YES", "" }, { "b9b4612358a0b2c1b4d66bb146767306", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "23", "245", "", "" }, { "b9d1e3be30b131324482345959aed5e5", "Activision, Rex Bradford", "", "Kabobber (07-25-1983) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "b9f6fa399b8cd386c235983ec45e4355", "Parker Brothers, John Emerson", "931511", "Action Force (1983) (Parker Bros) (PAL)", "AKA G.I. Joe - Cobra Strike", "", "", "", "", "", "", "", "PADDLES", "", "", "01 55", "", "", "", "", "" }, { "b9f9c0fed0db08c34346317f3957a945", "SuperVision", "405, 427, 806, 808, 813, 816", "Chopper Command (SuperVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ba257438f8a78862a9e014d831143690", "U.S. Games Corporation - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV", "VC2002", "Squeeze Box (1983) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ba317f83cdfcd58cbc65aac1ccb87bc5", "", "", "Jammed (2001) (XYPE) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ba3a17efd26db8b4f09c0cf7afdf84d1", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "ba3b0eebccc7b791107de5b4abb671b4", "", "", "Thrust (V0.9) (2000) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ba657d940a11e807ff314bba2c8b389b", "Activision, John Van Ryzin", "AG-038-04", "Cosmic Commuter (1984) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bac28d06dfc03d3d2f4a7c13383e84ee", "Supergame", "", "Demon Attack (Supergame)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bae1a23f9b6acdadf465cfb330ba0acb", "Atari - GCC, Doug Macrae", "CX2677", "Dig Dug (1983) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bae66907c3200bc63592efe5a9a69dbb", "Spectravision - Spectravideo - Quelle", "SA-201 - 412.783 3", "Gangster Alley (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "baf4ce885aa281fd31711da9b9795485", "Atari, Douglas Neubauer", "CX26176", "Radar Lock (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb07f917611cde42b7d83746ee27147d", "", "", "Star Fire - Warping!! (13-04-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb18189021d58362d9e4d317cd2e28b7", "Activision, David Crane - Ariola", "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715", "Dragster (1980) (Activision) (PAL) (4K)", "AKA Dragster Rennen", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb5049e4558daade0f87fed69a244c59", "Atari, Brad Stewart", "CX2649, CX2649P", "Asteroids (1981) (Atari) (PAL) [no copyright]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "bb579404924c40ca378b4aff6ccf302d", "", "", "Lightbulb Lightens, The (PD) (Non Functional)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb6a5a2f7b67bee5d1f237f62f1e643f", "", "", "Demo Image Series #5 - Animegirl (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb745c893999b0efc96ea9029e3c62ca", "Play Video", "", "Planet Patrol (1982) (Play Video) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb756aa98b847dddc8fc170bc79f92b2", "", "", "Golf (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bb9f06b288b5275bc0d38b6731b2526a", "", "", "Star Fire - Meteor Dance 2 (18-11-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bbf8c7c9ed280151934aabe138e41ba7", "Amiga", "1130", "Power Play Arcade Video Game Album V (1984) (Amiga) (Prototype)", "Mogul Maniac, Surf's Up, Off Your Rocker, S.A.C. Alert", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc3057a35319aae3a5cd87a203736abe", "CCE", "C-845", "Time Warp (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc33c685e6ffced83abe7a43f30df7f9", "Dynacom", "", "Seaquest (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc4cf38a4bee45752dc466c98ed7ad09", "Atari, Douglas Neubauer, Mimi Nyden", "CX26136", "Solaris (1986) (Atari) (PAL)", "AKA Universe, Star Raiders II, The Last Starfighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc526185ad324241782dc68ba5d0540b", "", "", "Dodge Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc5389839857612cfabeb810ba7effdc", "Atari, Tod Frye", "CX2671", "SwordQuest - WaterWorld (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc6432cbed32c695658514c4eb41d905", "Manuel Polik", "", "Star Fire (MP) (2002) (PD)", "Won't work with Stella < V1.2", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc703ea6afb20bc089f04d8c9d79a2bd", "", "", "Gunfight 2600 - Not mergeable with Colbert wizardry... (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bc97d544f1d4834cc72bcc92a37b8c1b", "", "", "Sky Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bcb31f22856b0028c00d12f0e4c0a952", "Canal 3 - Intellivision", "", "Thunderground (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bccb4e2cfad5efc93f6d55dc992118ce", "Activision, Carol Shaw", "AX-020, AX-020-04", "River Raid (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bce4c291d0007f16997faa5c4db0a6b8", "Quelle", "292.651 7", "Weltraumtunnel (1983) (Quelle) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bce93984b920e9b56cf24064f740fe78", "Atari", "CX26163P", "Checkers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bcef7880828a391cf6b50d5a6dcef719", "Rainbow Vision - Suntek", "SS-009", "Bermuda, The (Rainbow Vision) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bd1bd6f6b928df17a702def0302f46f4", "", "", "Binary To Decimal Routine (2001) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bd39598f067a1193ae81bd6182e756d1", "Telegames", "", "Night Stalker (1988) (Telegames) (PAL)", "AKA Dark Cavern", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bd430c2193045c68d1a20a018a976248", "", "", "Pac Ghost Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bda1463e02ae3a6e1107ffe1b572efd2", "Atari, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bdb4b584ddc90c9d2ec7e21632a236b6", "Atari Freak 1", "", "Nitemare at Sunshine Bowl-a-Rama (Atari Freak 1) (Hack)", "Hack of Pac-Man Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bdbaeff1f7132358ea64c7be9e46c1ac", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11105", "Mega Force (1982) (20th Century Fox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bdc381baf7c252c63739c5e9ed087a5c", "", "", "Vertical Ship Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bdecc81f740200780db04a107c3a1eba", "Quelle", "874.254 6", "Super-Cowboy beim Rodeo (1983) (Quelle) (PAL)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bdf1996e2dd64baf8eff5511811ca6ca", "Tron", "", "H.E.R.O. (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "be060a704803446c02e6f039ab12eb91", "Parker Brothers, Rex Bradford, Sam Kjellman", "931501", "Star Wars - The Empire Strikes Back (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "be1922bd8e09d74da471287e1e968653", "Cropsy", "", "Hangman Pacman Demo (Cropsy) (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "be2870a0120fd28d25284e9ccdcbdc99", "", "", "Tomb Raider 2600 [REV 01] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "be35d8b37bbc03848a5f020662a99909", "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears", "CX2601 - 99801, 6-99801, 49-75124", "Combat (1977) (Atari) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "be3f0e827e2f748819dac2a22d6ac823", "Puzzy - Bit Corporation", "PG202", "Space Tunnel (1982) (Puzzy)", "AKA Cosmic Corridor, Le Tunnel de L'Estace", "", "", "", "", "", "", "", "", "", "", "", "", "34", "215", "", "" }, { "be41463cd918daef107d249f8cde3409", "", "", "Berzerk (Voice Enhanced) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "be561b286b6432cac71bccbae68002f7", "", "", "Counter Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "be929419902e21bd7830a7a7d746195d", "Activision, Garry Kitchen", "AX-025, AX-025-04", "Keystone Kapers (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "becd908f9d7bb361982c3dc02d6475c6", "Kyle Pittman", "", "THX-1138 (Kyle Pittman) (Hack)", "Hack of Berserk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bedfbde71fb606601f936b5b057f26f7", "Activision, Garry Kitchen - Ariola", "EAX-025, EAX-025-04I - 711 025-725", "Keystone Kapers (1983) (Activision) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "befce0de2012b24fd6cb8b53c17c8271", "", "", "Push (V0.03) (No Illegal Opcodes) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bf52327c2197d9d2c4544be053caded1", "HES", "AG-930-04, AZ-030", "Decathlon (HES) (PAL) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bf5e2079586cb307bf5eb2413e2e61af", "", "", "Star Fire - 1LK Intro (13-11-2002) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bf84f528de44225dd733c0e6a8e400a0", "CCE", "", "Demons to Diamonds (CCE)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 57", "", "", "", "", "" }, { "bf976cf80bcf52c5f164c1d45f2b316b", "Atari, Tod Frye, Mimi Nyden", "CX2657", "SwordQuest - FireWorld (1982) (Atari) (PAL)", "AKA Adventure II, SwordQuest II - FireWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bf9ddc5dd9056633d4ac0dac8b871dfe", "", "", "Star Fire - Cockpit View (10-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bfa58198c6b9cd8062ee76a2b38e9b33", "", "", "20 Sprites at Once Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bfb73aabb2489316cd5882c3cd11d9f9", "AtariAge, Chris Walton & Thomas Jentzsch", "165", "Star Castle Arcade (2014) (AtariAge)", "", "Homebrew", "", "", "", "", "", "", "", "SAVEKEY", "", "", "", "30", "", "YES", "" }, { "bfcabc6995ef42d0b6c06786993dc4d6", "", "", "Star Fire - Creating a Universe (09-09-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bff8f8f53a8aeb1ee804004ccbb08313", "", "", "Droid Demo 22 (David Conrad Schweinsberg) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "bffe34516aaa3cbf5d307eab382a7e95", "", "", "Euchre (Release Candidate) (PAL) (28-09-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c00734a2233ef683d9b6e622ac97a5c8", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26133", "A-Team, The (03-30-1984) (Atari) (Prototype)", "AKA Saboteur", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c00b65d1bae0aef6a1b5652c9c2156a1", "Atari, Joe Decuir - Sears", "CX2621 - 99806, 6-99806, 49-75104", "Video Olympics (1977) (Atari) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "AUTO 60", "", "", "", "", "" }, { "c02e1afa0671e438fd526055c556d231", "Atari", "", "A-Team (Atari) (Prototype) (PAL60)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "c032c2bd7017fdfbba9a105ec50f800e", "Activision, Charlie Heath", "", "Thwocker (04-09-1984) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c033dc1d7b6fde41b9cadce9638909bb", "", "", "Skeleton (V1.1) (06-09-2002) (Eric Ball)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c0589bb73858924389077fa3c2e9441a", "SOLID Corp. (D. Scott Williamson)", "CX2655-014", "Star Castle 2600 (SolidCorp) [014]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c05f367fa4767ceb27abadf0066df7f4", "", "", "TomInv (31-07-2001) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c08d0cee43077d3055febb00e5745c1d", "HES - Activision", "", "Super Hit Pak - River Raid, Sky Jinks, Grand Prix, Fishing Derby, Checkers (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c0a68837c60e15d1fc5a40c9a62894bc", "Arcadia Corporation, Kevin Norman", "7 AR-4103", "Killer Satellites (1983) (Arcadia) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c0d2434348de72fa6edcc6d8e40f28d7", "Sega - Beck-Tech, Steve Beck", "010-01", "Tapper (1984) (Sega)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "225", "", "" }, { "c118854d670289a8b5d5156aa74b0c49", "Jone Yuan Telephonic Enterprise Co", "", "Skiing (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c126656df6badfa519cc63e681fb3596", "Ron Corcoran", "", "Space Invaders (2002) (Ron Corcoran) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c150c76cbde2c9b5a97eb5399d46c64f", "", "", "Unknown Title (xxx00000 (200203)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c16c79aad6272baffb8aae9a7fff0864", "U.S. Games Corporation - JWDA, Sylvia Day, Todd Marshall, Robin McDaniel, Henry Will IV", "VC2001", "Gopher (1982) (U.S. Games)", "AKA Gopher Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c16fbfdbfdf5590cc8179e4b0f5f5aeb", "", "", "Wall Break (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c17bdc7d14a36e10837d039f43ee5fa3", "Spectravision - Spectravideo", "SA-203", "Cross Force (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c1a83f44137ea914b495fc6ac036c493", "Atari, Carla Meninsky", "CX2660", "Star Raiders (1982) (Atari) (PAL)", "Uses Joystick (left) and Keypad (right) Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "" }, { "c1b038ce5cb6d85e956c5509b0e0d0d8", "", "", "Rotating Colors Demo 2 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c1b1049b88bcd98437d8872d1d62ba31", "", "", "Demo Image Series #4 - Donald (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c1b7aeabc3ec41556d924c8372a9ba5b", "Atari, Robert C. Polaro", "", "Dukes of Hazard (1980) (Atari) (Prototype)", "AKA Stunt Cycle", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c1cb228470a87beb5f36e90ac745da26", "Activision, Bob Whitehead", "AX-015, AX-015-04", "Chopper Command (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c1e6e4e7ef5f146388a090f1c469a2fa", "Bomb - Onbase", "CA283", "Z-Tack (1983) (Bomb)", "AKA Base Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c1f209d80f0624dada5866ce05dd3399", "Telegames", "", "Deadly Discs (1988) (Telegames) (PAL)", "AKA TRON - Deadly Discs", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c1fdd44efda916414be3527a47752c75", "Parker Brothers, John Emerson", "PB5920", "G.I. Joe - Cobra Strike (1983) (Parker Bros)", "Uses the Paddle (left) and Joystick (right) Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "c20f15282a1aa8724d70c117e5c9709e", "Video Gems", "VG-02", "Surfer's Paradise (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c21450c21efb7715746e9fa87ad6f145", "Hozer Video Games", "", "Gunfight 2600 - It could've been soooo cool, but... (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c216b91f5db21a093ded6a5aaec85709", "Jone Yuan Telephonic Enterprise Co", "", "Dragster (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "c221607529cabc93450ef25dbac6e8d2", "Eckhard Stolberg", "", "Color Test (26-09-2002) (Eckhard Stolberg)", "", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "", "", "", "", "" }, { "c225379e7c4fb6f886ef9c8c522275b4", "Video Mania", "", "Frostbite (1983) (Video Mania)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c225abfb584960efe1f359fc94b73379", "", "", "Joustpong (21-09-2002) (Kirk Israel) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c2410d03820e0ff0a449fa6170f51211", "", "", "Pac-Man (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c246e05b52f68ab2e9aee40f278cd158", "Thomas Jentzsch", "", "Star Wars - Ewok Adventure (Thomas Jentzsch) (Prototype)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "240", "", "" }, { "c2778507b83d9540e9be5713758ff945", "", "", "Island Flyer Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c28b29764c2338b0cf95537cc9aad8c9", "", "", "Multi-Color Demo 4 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c29d17eef6b0784db4586c12cb5fd454", "Jone Yuan Telephonic Enterprise Co", "", "River Raid (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c29f8db680990cb45ef7fef6ab57a2c2", "Parker Brothers, Mike Brodie - Roklan, Paul Crowley", "PB5320", "Super Cobra (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c2a37f1c7603c5fd97df47d6c562abfa", "Roger Williams", "", "Bar-Score Demo (2001) (Roger Williams)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c2b5c50ccb59816867036d7cf730bf75", "Salu - Avantgarde Software, Michael Buetepage", "460741", "Ghostbusters II (1992) (Salu) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c2bcd8f2378c3779067f3a551f662bb7", "Activision, Bob Whitehead - Ariola", "EAG-002, EAG-002-04I, PAG-002 - 711 002-715", "Boxing (1980) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c2c7a11717e255593e54d0acaf653ee5", "", "", "Chopper Command (208 in 1) (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c2fbef02b6eea37d8df3e91107f89950", "Champ Games", "CG-02-N", "Conquest Of Mars (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c31a17942d162b80962cb1f7571cd1d5", "Home Vision - Gem International Corp. - VDI", "VCS83112", "Sky Alien (1983) (Home Vision) (PAL)", "AKA Sky Aliem", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c3205e3707f646e1a106e09c5c49c1bf", "", "", "Unknown Title (bin00003 (200206)) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c3472fa98c3b452fa2fd37d1c219fb6f", "Atari, Carla Meninsky - Sears", "CX2637 - 49-75158", "Dodge 'Em (1980) (Atari) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c370c3268ad95b3266d6e36ff23d1f0c", "Atari, Alan Miller", "CX2641, CX2641P", "Surround (1977) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c3a9550f6345f4c25b372c42dc865703", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (1989) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c3aeb796fdaf9429e8cd6af6346f337e", "", "", "If It's Not One Thing It's Another (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c3bbc673acf2701b5275e85d9372facf", "Atari, Robert C. Polaro", "CX26157", "Stunt Cycle (07-21-1980) (Atari) (Prototype)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c3e4aa718f46291311f1cce53e6ccd79", "", "", "Hangman Ghost 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c3ef5c4653212088eda54dc91d787870", "Activision, Bob Whitehead", "AG-002, CAG-002, AG-002-04", "Boxing (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c3f53993ade534b0982ca3a286c85bb5", "", "", "Full Screen Bitmap Drawing System (12-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c4060a31d61ba857e756430a0a15ed2e", "Thomas Jentzsch", "", "Pick 'n Pile (2003) (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "215", "YES", "" }, { "c41e7735f6701dd50e84ee71d3ed1d8f", "Dynacom", "", "Spider Fighter (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c43bd363e1f128e73ba5f0380b6fd7e3", "Atari, Chris Crawford", "", "Wizard (1980) (Atari) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c446288fe62c0c2737639fd788ae4a21", "", "", "Mark's Sound Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c450a285daa7a3b65188c2c3cf04fb3e", "Wizard Video Games", "007", "Halloween (1983) (Wizard Video Games) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c469151655e333793472777052013f4f", "", "", "Base Attack (Unknown) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c471b97446a85304bbac021c57c2cb49", "First Star Software, Alex Leavens, Shirley Ann Russell", "", "Boing! (1983) (First Star Software) (PAL)", "AKA Bubbles, Soap Suds, The Emphysema Game", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c47244f5557ae12c61e8e01c140e2173", "Atari - GCC, Mike Feinstein, John Allred", "CX2688, CX2688P", "Jungle Hunt (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c473b222b7c5308d0773326416094272", "", "", "Star Fire (28-11-2002) (MP) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c47b7389e76974fd0de3f088fea35576", "Funvision - Fund. International Co.", "", "Mighty Mouse (Funvision)", "AKA Gopher", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c482f8eebd45e0b8d479d9b71dd72bb8", "Retroactive", "", "Push (V0.03) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c49fe437800ad7fd9302f3a90a38fb7d", "Atari, Dan Hitchens, Mimi Nyden", "CX2697, CX2697P", "Mario Bros. (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c4b73c35bc2f54b66cd786f55b668a82", "Arcadia Corporation, Stephen Harland Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c4bbbb0c8fe203cbd3be2e318e55bcc0", "", "", "Atlantis (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c4bc8c2e130d76346ebf8eb544991b46", "Imagic", "", "Imagic Selector ROM (1982) (Imagic) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c4d888bcf532e7c9c5fdeafbb145266a", "", "", "Space Robot (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c504a71c411a601d1fc3173369cfdca4", "Retroactive", "", "Qb (V2.02) (Stella) (2001) (Retroactive)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c5124e7d7a8c768e5a18bde8b54aeb1d", "Imagic, Rob Fulop", "720104-2A, IA3204P, EIX-008-04I", "Cosmic Ark (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c517144e3d3ac5c06f2f682ebf212dd7", "Tigervision - Teldec", "7-008 - 3.60006 VG", "Miner 2049er (1983) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c529e63013698064149b9e0468afd941", "", "", "S.I.PLIX 2 (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "c52d9bbdc5530e1ef8e8ba7be692b01e", "Atari, Robert C. Polaro", "CX26130", "Holey Moley (02-29-1984) (Atari) (Prototype)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "c5301f549d0722049bb0add6b10d1e09", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari)", "Uses the Driving Controllers", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "", "", "", "" }, { "c5387fc1aa71f11d2fa82459e189a5f0", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp) (PAL)", "AKA Cosmic Corridor, Weltraum-Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "c541a5f6fc23b40a211196dd78233780", "Atari, Carla Meninsky - Sears", "CX2660 - 49-75187", "Star Raiders (1981) (Atari) (Prototype)", "Uses Joystick (left) and Keypad (right) Controllers", "Prototype", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "" }, { "c54b4207ce1d4bf72fadbb1a805d4a39", "Billy Eno", "", "Sniper (Feb 30) (2001) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c569e57dca93d3bee115a49923057fd7", "", "", "Pac-Space (Pac-Man Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "c58708c09ccb61625cda9d15ddcd8be6", "SPIKE the Percussionist", "", "NOIZ Invaders (SPIKE) (2002) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c5930d0e8cdae3e037349bfa08e871be", "Atari, Howard Scott Warshaw - Sears", "CX2655 - 49-75167", "Yars' Revenge (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c59633dbebd926c150fb6d30b0576405", "Telegames", "5861 A030", "Bogey Blaster (1988) (Telegames)", "AKA Air Raiders", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c5a76bafc4676edb76e0126fb9f0fb2d", "Charles Morgan", "", "Zero Patrol (Charles Morgan) (Hack)", "Hack of Moon Patrol", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c5bab953ac13dbb2cba03cd0684fb125", "SpiceWare - Darrell Spice Jr.", "", "Stay Frosty (SpiceWare)", "Part of Stella's Stocking 2007 Xmas compilation", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c5c7cc66febf2d4e743b4459de7ed868", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1983) (Atari) (PAL) [a]", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c5d2834bf98e90245e545573eb7e6bbc", "CCE", "", "Snoopy and the Red Baron (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c5dd8399257d8862f3952be75c23e0eb", "Atari - GCC", "CX2680", "RealSports Tennis (1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c5fe45f2734afd47e27ca3b04a90213c", "Atari, Brad Stewart", "CX2622, CX2622P", "Breakout (1978) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01", "", "", "", "", "" }, { "c63a98ca404aa5ee9fcff1de488c3f43", "Atari", "CX26145", "Venture (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c6556e082aac04260596b4045bc122de", "Atari - GCC, Dave Payne", "CX2669", "Vanguard (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c6688781f4ab844852f4e3352772289b", "Atari, Tod Frye", "CX2695", "Xevious (08-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c67ff409f28f44883bd5251cea79727d", "", "", "Gunfight 2600 - Music & Bugfixes 1 (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c689148ad9275667924ab334107b517e", "Jone Yuan Telephonic Enterprise Co", "", "Space Raid (Jone Yuan)", "AKA MegaMania", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c68a6bafb667bad2f6d020f879be1d11", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c6ae21caceaad734987cb24243793bd5", "CCE", "", "Frostbite (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c6c63da3bc2e47291f63280e057061d0", "128-in-1 Junior Console", "", "Human Cannonball (128-in-1 Junior Console) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c6cedb25b7d390b580ea8edb614b168b", "", "", "Star Fire - Radar Completed (22-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c6d48c6ae6461e0e82753540a985ac9e", "Ed Federmeyer", "", "Edtris (1994) (Ed Federmeyer)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c6d7fe7a46dc46f962fe8413c6f53fc9", "Parker Brothers, Mark Lesser", "PB5950", "Lord of the Rings (1983) (Parker Bros) (Prototype) [a]", "Journey to Rivendell (The Lord of the Rings I)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c6db733e0b108c2580a1d65211f06dbf", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (07-09-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c738fc3f5aae1e8f86f7249f6c82ac81", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari) (16K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 60", "", "", "", "", "" }, { "c73ae5ba5a0a3f3ac77f0a9e14770e73", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "c745487828a1a6a743488ecebc55ad44", "Rainbow Vision - Suntek", "SS-002", "Galactic (Rainbow Vision) (PAL)", "AKA The Challenge of.... Nexar", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c74bfd02c7f1877bbe712c1da5c4c194", "Thomas Jentzsch", "", "River Raid Tanks (Thomas Jentzsch) (Hack)", "Hack of River Raid", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c7600d72247c5dfa1ec1a88d23e6c85e", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (1 of 3) (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "c77c35a6fc3c0f12bf9e8bae48cba54b", "Xonox - K-Tel Software - Action Graphics, John Perkins, David Thiel", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox)", "", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c77d3b47f2293e69419b92522c6f6647", "Panda", "101", "Tank Brigade (1983) (Panda)", "AKA Tanks But No Tanks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c7900a7fe95a47eef3b325072ad2c232", "Larry Petit", "", "Super Congo Bongo (2003) (Larry Petit) (Hack)", "Hack of Bongo", "Hack", "", "", "", "", "", "", "", "", "", "", "", "34", "", "", "" }, { "c7d5819b26b480a49eb26aeb63cc831e", "Bit Corporation", "PGP210", "Ice Hockey (4 Game in One Light Green) (1983) (BitCorp) (PAL)", "AKA Hockey, Hockey", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c7e43ad79c5e5c029d9f5ffde23e32cf", "", "", "PAL-NTSC Detector (15-11-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c7eab66576696e11e3c11ffff92e13cc", "Atari - GCC", "CX2680, CX2680P", "RealSports Tennis (1983) (Atari) (PAL) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c7f13ef38f61ee2367ada94fdcc6d206", "Parker Brothers, Joe Gaucher", "PB5370", "Popeye (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c82ec00335cbb4b74494aecf31608fa1", "CCE", "", "E.T. - The Extra-Terrestrial (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c830f6ae7ee58bcc2a6712fb33e92d55", "Atari, Michael Kosaka, Carla Meninsky", "CX2687", "Tempest (01-05-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c866c995c0d2ca7d017fef0fc0c2e268", "Retroactive", "", "Qb (2.00) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c880c659cdc0f84c4a66bc818f89618e", "Thomas Jentzsch", "", "Open Sesame (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "20", "254", "YES", "" }, { "c8c7da12f087e8d16d3e6a21b371a5d3", "", "", "Demo Image Series #9 - Genius (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c8fa5d69d9e555eb16068ef87b1c9c45", "Atari", "CX26144", "Donkey Kong Junior (1987) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c9196e28367e46f8a55e04c27743148f", "Atari", "CX26163P", "Stampede (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c92cfa54b5d022637fdcbdc1ef640d82", "Retroactive", "", "Qb (V2.05) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "c9b7afad3bfd922e006a6bfc1d4f3fe7", "Atari, Larry Kaplan - Sears", "CX2628 - 6-99842, 49-75117", "Bowling (1979) (Atari)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c9c25fc536de9a7cdc5b9a916c459110", "Activision, Mike Lorenzen", "AX-023", "Oink! (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c9d02d3cfeef8b48fb71cb4520a4aa84", "", "", "Euchre (More for less) (PAL) (22-08-2002) (Erik Eid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c9e721eb29c940c2e743485b044c0a3f", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "c9f6e521a49a2d15dac56b6ddb3fb4c7", "Parker Brothers, Rex Bradford", "PB5000", "Star Wars - Jedi Arena (1983) (Parker Bros)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 50", "", "", "", "", "" }, { "ca09fa7406b7d2aea10d969b6fc90195", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ca4f8c5b4d6fb9d608bb96bc7ebd26c7", "M Network - APh Technological Consulting, Hal Finney, Glenn Hightower, Peter Kaminski - INTV", "MT4317", "Adventures of TRON (1983) (M Network)", "AKA Tron Joystick", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ca50cc4b21b0155255e066fcd6396331", "Suntek", "SS-031", "UFO Patrol (Suntek) (PAL)", "AKA X'Mission", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ca53fc8fd8b3c4a7df89ac86b222eba0", "CCE", "C-812", "Pac Man (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ca54de69f7cdf4d7996e86f347129892", "PlayAround - J.H.M.", "201", "Philly Flasher (1982) (PlayAround)", "Uses the Paddle Controllers, AKA Beat 'Em & Eat 'Em", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 45", "", "", "", "", "" }, { "ca7aaebd861a9ef47967d31c5a6c4555", "Atari, Bob Whitehead", "CX26163P", "Homerun (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "ca7abc774a2fa95014688bc0849eee47", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (1984) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ca7f166a94eed1a349dec6d6a358bcad", "Activision, Alan Miller - Ariola", "EAG-007, EAG-007-04I, PAG-007 - 711 007-720", "Tennis (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cac9928a84e1001817b223f0cecaa3f2", "Amiga - Video Soft, Jerry Lawson, Dan McElroy", "", "3-D Genesis (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cad982c9b45bc5eff34e4ea982d5f1ca", "", "", "Song (17-02-2003) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cade123747426df69570a2bc871d3baf", "Gakken", "011", "Marine Wars (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cae8f83c06831ec7bb6a3c07e98e9342", "Colin Hughes", "", "Tetris 2600 (Colin Hughes) [o1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cb18d8d5fbdcb1cd7bd36c5423348859", "", "", "RAM-Pong (NTSC) v1.0", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "cb24210dc86d92df97b38cf2a51782da", "Video Gems", "VG-01", "Missile Control (1983) (Video Gems) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cb4a7b507372c24f8b9390d22d54a918", "ITT Family Games", "554-37 338", "Peter Penguin (1983) (ITT Family Games) (PAL)", "AKA Frisco (Pumuckl-Serie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cb8399dc0d409ff1f531ef86b3b34953", "", "", "Demo Image Series #12 - Luigi And Mario (01-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cb9626517b440f099c0b6b27ca65142c", "Atari, Larry Kaplan - Sears", "CX2664 - 6-99818", "Brain Games (1978) (Atari) (4K)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "cb96b0cf90ab7777a2f6f05e8ad3f694", "Silvio Mogno", "", "Rainbow Invaders", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cb9b2e9806a7fbab3d819cfe15f0f05a", "Parker Brothers - JWDA, Todd Marshall, Robin McDaniel, Ray Miller", "931513", "Star Wars - Death Star Battle (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cba56e939252b05df7b7de87307d12ca", "", "", "Playfield Text Demo (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cbad928e10aeee848786cc55394fb692", "", "", "Fu Kung! (V0.06a Cuttle Cart Compatible) (15-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cbb0ee17c1308148823cc6da85bff25c", "", "", "Rotating Colors Demo 1 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cbc373fbcb1653b4c56bfabba33ea50d", "CCE", "", "Super Voleyball (CCE)", "AKA RealSports Volleyball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cbced209dd0575a27212d3eee6aee3bc", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2003", "Racquetball (1982) (Apollo) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cbd981a23c592fb9ab979223bb368cd5", "Atari, Carla Meninsky - Sears", "CX2660 - 49-75187", "Star Raiders (1982) (Atari)", "Uses Joystick (left) and Keypad (right) Controllers", "", "", "", "", "", "", "", "", "KEYBOARD", "", "", "", "", "", "", "" }, { "cbe5a166550a8129a5e6d374901dffad", "Atari, Carla Meninsky - Sears", "CX2610 - 49-75127", "Warlords (1981) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "AUTO 50", "", "", "", "", "" }, { "cbeafd37f15e0dddb0540dbe15c545a4", "", "", "Black and White Fast Scolling Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cc03c68b8348b62331964d7a3dbec381", "Jone Yuan Telephonic Enterprise Co", "", "Marauder (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cc12581e079cd18330a89902625b8347", "Dave Neuman", "", "Space Battle (PAL)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cc1939e4769d0c157ace326efcfdcf80", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (3 of 4) (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cc2973680c150886cce1ed8693c3aca2", "Quelle", "874.254 6", "Super-Cowboy beim Rodeo (1983) (Quelle) (PAL) (4K)", "AKA Stampede", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cc3d942c6958bd16b1c602623f59e6e1", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cc7138202cd8f6776212ebfc3a820ecc", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (03-30-1983) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "cc724ebe74a109e39c0b2784ddc980ca", "Atari, Jerome Domurat, Dave Staugas", "CX2682", "Krull (05-27-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cc74ddb45d7bc4d04c2e6f1907416699", "", "", "Colour Display Programme (1997) (Chris Cracknell)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cca33ae30a58f39e3fc5d80f94dc0362", "", "", "Okie Dokie (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ccb56107ff0492232065b85493daa635", "Bit Corporation", "PG206 [demonstration cartridge]", "Bobby Is Going Home (1983) (BitCorp) (PAL) [demo cart]", "AKA Bobby geht Heim", "", "", "", "", "", "", "", "", "", "", "", "", "42", "", "", "" }, { "ccb5fa954fb76f09caae9a8c66462190", "Answer Software Corporation - TY Associates", "ASC1001", "Malagai (1983) (Answer Software)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ccb807eb79b0ed0f5fdc460445ef703a", "", "", "Superman (Stunt_Cycle_Rules!) (Hack)", "Hack of Superman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ccbd36746ed4525821a8083b0d6d2c2c", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [no copyright]", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cccfe9e9a11b1dad04beba46eefb7351", "", "", "Poker Squares (V0.25) (PAL) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ccd6ce508eee4b3fca67212833edcd85", "Otto Versand", "746422", "Hot Wave (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Ram It", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd032ab6764b55438a7b0bfb5e78595a", "", "", "Hangman Pac-Man 4letter (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd139ae6d09f3665ad09eb79da3f9e49", "Eric Mooney", "", "Invaders by Erik Mooney (4-24-97) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd34b3b3ef9e485201e841ba71beb253", "Bradford W. Mott", "", "Hit HMOVE At Various Cycles After WSYNC Test (Bradford W. Mott) (1998) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd38ad19f51b1048d8e5e99c86a2a655", "", "", "Demo Image Series #5 - Flag (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd399bc422992a361ba932cc50f48b65", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (Preview) (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd3e26786136a4692fd2cb2dfbc1927e", "", "", "Multiple Moving Objects Demo 2 (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd4423bd9f0763409bae9111f888f7c2", "Jone Yuan Telephonic Enterprise Co", "", "River Raid (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd4ded1ede63c4dd09f3dd01bda7458c", "Future Video Games", "", "Laser Gate (Future Video Games) (PAL)", "AKA Innerspace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd568d6acb2f14477ebf7e59fb382292", "Videospielkassette - Ariola", "PGP235", "Fussball (Ariola) (PAL)", "AKA International Soccer", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd5af682685cfecbc25a983e16b9d833", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX26133", "A-Team, The (05-08-1984) (Atari) (Prototype)", "AKA Saboteur", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cd88ef1736497288c4533bcca339f881", "Sega - Teldec", "005-10", "Buck Rogers - Planet of Zoom (1983) (Sega) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "YES", "" }, { "cd8fa2e9f6255ef3d3b9b5a4f24a54f7", "", "", "Daredevil (V2) (Stunt_Cycle_Rules!) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "cd98be8a48ebf610c9609a688b9c57f2", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Arcadia) (Prototype)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cd9fea12051e414a6dfe17052067da8e", "Paul Slocum", "", "Marble Craze Demo (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "cda38714267978b9a8b0b24bee3529ae", "", "", "Space Instigators (V1.6) (17-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cdb81bf33d830ee4ee0606ee99e84dba", "Arcadia Corporation, Scott Nelson", "AR-4300", "Fireball (1982) (Arcadia) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "", "" }, { "cdc1a5c61d7488eadc9aba36166b253d", "Retroactive", "", "Qb (V0.12) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cddabfd68363a76cd30bee4e8094c646", "Computer Magic - CommaVid, John Bronstein", "CM-001", "MagiCard (1981) (CommaVid)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "ce17325834bf8b0a0d0d8de08478d436", "", "", "Boring Freeway (Hack)", "Hack of Freeway", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ce243747bf34a2de366f846b3f4ca772", "Home Vision - Gem International Corp. - VDI", "", "Jacky Jump (1983) (Home Vision) (PAL)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "ce4bbe11d682c15a490ae15a4a8716cf", "", "", "Okie Dokie (Older) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ce5cc62608be2cd3ed8abd844efb8919", "Atari - Bobco, Robert C. Polaro", "CX2663", "Road Runner (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ce64812eb83c95723b04fb56d816910b", "Retroactive", "", "Qb (V2.04) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ce6c4270f605ad3ce5e82678b0fc71f8", "", "", "Vertical Rainbow Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ce82a675c773ff21e0ffc0a4d1c90a71", "", "", "Defender 2 (Genesis)", "Genesis controller (C is smartbomb)", "Hack of Defender 2", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "ce8467ae2a3a5bc88ca72a2ce44ce28c", "SOLID Corp. (D. Scott Williamson)", "CX2655-015", "Star Castle 2600 (SolidCorp) (PAL) [015]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ce89529d6e98a13ddf3d84827bbdfe68", "", "", "Kung Fu Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ce904c0ae58d36d085cd506989116b0b", "Telegames", "5687 A279", "International Soccer (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cea9f72036dc6f7af5eff52459066290", "Retroactive", "", "Qb (2.07) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cedbd67d1ff321c996051eec843f8716", "Ultravision", "1044", "Karate (1982) (Ultravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cef01595000627ee50863d4290372c27", "", "", "Many Blue Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cef2287d5fd80216b2200fb2ef1adfa8", "Milton Bradley Company", "4363", "Spitfire Attack (1983) (Milton Bradley)", "AKA Flight Commander)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cf0c593c563c84fdaf0f741adb367445", "Retroactive", "", "Qb (V0.05) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cf3a9ada2692bb42f81192897752b912", "", "", "Air Raiders (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cf3c2725f736d4bcb84ad6f42de62a41", "Rainbow Vision - Suntek", "SS-009", "Bermuda, The (Rainbow Vision) (PAL) [a]", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cf507910d6e74568a68ac949537bccf9", "Sega, Jeff Lorenz", "003-01", "Thunderground (1983) (Sega)", "AKA Underground", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cf63ffac9da89ef09c6c973083061a47", "CCE", "C-859", "MASH (1983) (CCE)", "AKA M.A.S.H", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cf9069f92a43f719974ee712c50cd932", "Video Gems", "VG-04", "Mission Survive (1983) (Video Gems) (PAL)", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cfad2b9ca8b8fec7fb1611d656cc765b", "Bit Corporation", "PG207", "Mission 3,000 A.D. (1983) (BitCorp) (PAL) [demo cart]", "demonstration cartridge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cfb3260c603b0341d49ddfc94051ec10", "Dactari - Milmar", "", "Boxing (Dactari - Milmar)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfb83a3b0513acaf8be4cae1512281dc", "Starpath Corporation", "", "Going-Up (1983) (Starpath) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfc226d04d7490b69e155abd7741e98c", "Atari, Matthew L. Hubbard", "CX26159", "Double Dunk (1989) (Atari) (PAL)", "AKA Super Basketball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfce5596a7e8ca13529e9804cad693ef", "Canal 3 - Intellivision", "", "Tennis (Canal 3) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfd6a8b23d12b0462baf6a05ef347cd8", "Activision, Larry Kaplan", "AX-006", "Bridge (1980) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfdb4d0427a1ea8085c6bc6eb90259d8", "", "", "Gunfight 2600 - Release Candidate (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfe2185f84ce8501933beb5c5e1fd053", "", "", "Football (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfe62ed7125ff9fae99b4c8a367c0399", "Activision, Larry Miller", "AX-026, AX-026-04", "Enduro (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfee10bd7119f10b136921ced2ee8972", "", "", "Space Instigators (V1.8) (19-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cfef1a2d1f6a5ee7a5e1f43f3056f112", "", "", "Skeleton+ (05-05-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cff1e9170bdbc29859b815203edf18fa", "Retroactive", "", "Push (V0.01) (1998) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cff578e5c60de8caecbee7f2c9bbb57b", "George Veeder", "", "Suicide Adventure (George Veeder) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "cff9950d4e650094f65f40d179a9882d", "Paul Slocum", "", "Mr. Roboto (Paul Slocum) (Hack)", "Hack of Berzerk", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "cfffc4b97d01cc3e7b9f47575f7b11ec", "Xonox - K-Tel Software, Anthony R. Henderson", "99007, 6240", "Tomarc the Barbarian (1983) (Xonox) (PAL60)", "Genesis controller (B is jump and throw, C switches between players)", "Hack of Tomarc the Barbarian", "", "", "", "", "", "", "GENESIS", "", "", "", "PAL60", "", "", "", "" }, { "d00f6f8ba89559e4b20972a478fc0370", "Spiceware", "SW-01", "Medieval Mayhem (PAL)", "", "Homebrew", "STEREO", "", "", "", "", "", "PADDLES", "PADDLES", "", "AUTO 55", "", "", "", "", "" }, { "d010e3dfe7366e47561c088079a59439", "Retroactive", "", "Qb (V0.10) (Stella) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d026716b3c5be2c951cc4c064317c524", "", "", "Fu Kung! (V0.06) (14-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0498baca989e792db4b8270a02b9624", "", "", "Pac Ghost Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d071d2ec86b9d52b585cc0382480b351", "UA Limited", "", "Cat Trax (1983) (UA Limited) (1) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d078674afdf24a4547b4b32890fdc614", "Jone Yuan Telephonic Enterprise Co", "", "Laser Blast (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d078d25873c5b99f78fa267245a2af02", "Sega - Beck-Tech, Steve Beck, Phat Ho", "006-01", "Congo Bongo (1983) (Sega) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "26", "220", "", "" }, { "d08fccfbebaa531c4a4fa7359393a0a9", "Activision, David Crane", "", "Venetian Blinds Demo (1982) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d090836f0a4ea8db9ac7abb7d6adf61e", "Hozer Video Games", "", "Yahtzee (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d09935802d6760ae58253685ff649268", "Telesys, Don Ruffcorn", "1006", "Demolition Herby (1983) (Telesys)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d09a7504ee8c8717ac3e24d263e7814d", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d09f1830fb316515b90694c45728d702", "Imagic, Brad Stewart", "720105-1A, IA3400", "Fire Fighter (1982) (Imagic)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0a379946ed77b1b126230ca68461333", "Ataripoll", "", "Atari Invaders (Ataripoll) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0af33865512e9b6900714c26db5fa23", "Telegames", "", "Armor Ambush (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0b26e908370683ad99bc6b52137a784", "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo - RCA Video Jeux", "AP-2004", "Lost Luggage (1982) (Apollo) (PAL)", "AKA La valise piegee", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0b9df57bfea66378c0418ec68cfe37f", "20th Century Fox Video Games - Sirius, Grady Ward", "11002", "Beany Bopper (1982) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0b9f705aa5f61f47a748a66009ae2d2", "", "", "Synthcart (14-01-2002) (Paul Slocum)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "YES", "" }, { "d0cb28e1b7bd6c7f683a0917b59f707e", "Atari, Gary Palmer", "CX2661P", "Fun with Numbers (1980) (Atari) (PAL) (4K)", "AKA Basic Math", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0cdafcb000b9ae04ac465f17788ad11", "Quelle - Otto Versand", "732.273 8 - 600273, 781644", "Lilly Adventure (1983) (Quelle) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0e15a3ce322c5af60f07343594392af", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) (4K)", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d0e9beb2347595c6c7d158e9d83d2da8", "Retroactive", "", "Qb (2.00) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d100b11be34a1e5b7832b1b53f711497", "", "", "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d170317ae4c7d997a989c7d6567c2840", "Jone Yuan Telephonic Enterprise Co", "", "Stampede (Jone Yuan) (4K) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d175258b2973b917a05b46df4e1cf15d", "Suntek", "SS-032", "Walker (Suntek) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "230", "", "" }, { "d17a671029b1532b197defca5f3649a7", "Hozer Video Games", "", "Gunfight 2600 - Limit broken again! (2001) (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d17a8c440d6be79fae393a4b46661164", "", "", "Warring Worms (Beta 3) (2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d1a1841b7f2007a24439ac248374630a", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (1 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d1a9478b99d6a55e13a9fd4262da7cd4", "U.S. Games Corporation, Garry Kitchen - Vidtec", "VC1001", "Space Jockey (1982) (U.S. Games) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d1b4075925e8d3031a7616d2f02fdd1f", "", "", "Demo Image Series #7 - Two Marios (27-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d1c3520b57c348bc21d543699bc88e7e", "Gameworld", "133-002", "Warplock (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01", "", "", "", "YES", "" }, { "d1d704a7146e95709b57b6d4cac3f788", "Atari, Warren Robinett", "CX26163P", "Slot Racers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d20e61c86ed729780feca162166912ca", "Supergame", "32", "Pitfall (1984) (Supergame)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d223bc6f13358642f02ddacfaf4a90c9", "Rainbow Vision - Suntek", "SS-003", "Pac-Kong (Rainbow Vision) (PAL)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d245e2f27c84016041e9496b66b722fe", "", "", "Gunfight 2600 - The Final Kernel (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d25018349c544320bf3fd5092ee072bc", "Activision, Larry Miller", "AX-021", "Spider Fighter (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "d28afe0517a046265c418181fa9dd9a1", "", "", "Dodge 'Em (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d2901c34bb6496bb96c7bc78a9e6142a", "Greg Zumwalt", "", "Fish Revenge (2003) (Greg Zumwalt) (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d2c305a443dfc49e8430964d7c1bd1b7", "", "", "Star Fire - Advice on radar needed (16-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d2c4f8a4a98a905a9deef3ba7380ed64", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1001", "Sorcerer (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d2c8e6aa8172b16c8aa9aae739ac9c5e", "Activision, David Crane", "08-08-1980", "Laser Blast (08-08-1980) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d2c957dd7746521b51bb09fde25c5774", "Eckhard Stolberg", "", "Cubis (6K) (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d2d8c4f1ea7f347c8bcc7d24f45aa338", "", "", "20 Sprites at Once Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d2deddb77c8b823e4be9c57cb3c69adc", "Canal 3 - Intellivision", "C 3007", "Snoopy and the Red Baron (Canal 3)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d2f713c78a9ebba9da6d10aeefc6f20f", "Digivision", "", "Enduro (Digivision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d3171407c3a8bb401a3a62eb578f48fb", "ZiMAG - Emag - Vidco", "GN-080", "Spinning Fireball (1983) (ZiMAG) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d326db524d93fa2897ab69c42d6fb698", "Parker Brothers, Mike Brodie - Roklan, Paul Crowley", "931505", "Super Cobra (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d339b95f273f8c3550dc4daa67a4aa94", "", "", "Laser Blast (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d341d39774277cee6a1d378a013f92ac", "Xonox, John Perkins", "6230, 7210, 06004, 99004", "Artillery Duel (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "d3423d7600879174c038f53e5ebbf9d3", "U.S. Games Corporation - Western Technologies", "VC2005", "Piece o' Cake (1983) (U.S. Games)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 60", "", "", "", "", "" }, { "d3456b4cf1bd1a7b8fb907af1a80ee15", "Avalon Hill, Duncan Scott", "5003002", "Wall Ball (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d34b933660e29c0a0a04004f15d7e160", "", "", "Multi-Color Demo 5 (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d36308387241e98f813646f346e7f9f7", "King Atari", "", "Ghostbuster 2 (King Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d39e29b03af3c28641084dd1528aae05", "Funvision - Fund. Int'l Co.", "", "Spider Monster (1982) (Funvision) (PAL)", "AKA Spider Kong", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d3bb42228a6cd452c111c1932503cc03", "UA Limited", "", "Funky Fish (1983) (UA Limited) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "220", "YES", "" }, { "d44d90e7c389165f5034b5844077777f", "Parker Brothers, Larry Gelberg", "PB5065", "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "d45bf71871b196022829aa3b96bfcfd4", "Activision, Steve Cartwright", "AX-017, AX-017-04", "MegaMania (1982) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d45ebf130ed9070ea8ebd56176e48a38", "Sega, Jeff Lorenz", "001-01", "Tac-Scan (1983) (Sega)", "Uses the Paddle Controllers (right only)", "", "", "", "", "", "", "YES", "PADDLES", "", "YES", "AUTO 60", "", "31", "215", "YES", "" }, { "d47387658ed450db77c3f189b969cc00", "PlayAround - J.H.M.", "206", "Westward Ho (1982) (PlayAround) (PAL)", "AKA Custer's Revenge", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d4806775693fcaaa24cf00fc00edcdf3", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (1987) (Atari) (PAL)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "", "" }, { "d483f65468d9a265661917bae1a54f3e", "Joe Grand", "", "SCSIcide Pre-release 3 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d4942f4b55313ff269488527d84ce35c", "Atari - GCC, Mark Ackerman, Glenn Parker", "CX2675, CX2675P", "Ms. Pac-Man (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d49aff83f77a1b9041ad7185df3c2277", "", "", "Space Treat (60% complete) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d4aa89e96d2902692f5c45f36903d336", "", "", "Euchre (NTSC) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d4c590ccfb611a73b3331359700c01a3", "", "", "Sprite Movement Demo 2 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d541b20eae221a8ee321375e5971e766", "Arcadia Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d54cd41ecfd59e4b72d2c086152b9a75", "Amiga", "1110", "Power Play Arcade Video Game Album (1983) (Amiga) (Prototype)", "Ghost Attack, Genesis, Havoc", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5618464dbdc2981f6aa8b955828eeb4", "CCE", "C-829", "Megamania (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d563ba38151b8204c9f5c9f58e781455", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d573089534ca596e64efef474be7b6bc", "Parker Brothers, John Emerson", "931511", "Action Force (1983) (Parker Bros) (PAL) [a]", "AKA G.I. Joe - Cobra Strike", "", "", "", "", "", "", "", "PADDLES", "", "", "01 55", "", "", "", "", "" }, { "d57913088e0c49ac3a716bf9837b284f", "Activision, Garry Kitchen", "EAZ-032", "Pressure Cooker (1983) (Activision) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d57eb282d7540051bc9b5427cf966f03", "Atari Troll", "", "Custer's Viagra (Atari Troll) (Hack)", "Hack of Custer's Revenge", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d597d35c6022c590d6e75e865738558a", "", "", "Sprite Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5aa7472e7f2cc17e893a1a36f8dadf0", "", "", "Overhead Adventure Demo 5 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5c6b81212ad86fd9542a1fedaf57cae", "", "", "Sprite Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5d2d44fb73785996ccc24ae3a0f5cef", "Robby", "", "Grand Prix (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5e17022d1ecc20fd9b53dc464c302f1", "Activision, Carol Shaw", "EAX-020", "River Raid (1982) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "SECAM", "", "", "", "" }, { "d5e27051512c1e7445a9bf91501bda09", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5e5b3ec074fff8976017ef121d26129", "Star Game", "003", "River Raid (Star Game)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d5f965c159e26a1fb49a22a47fbd1dd0", "Supergame", "", "River Raid II (Supergame)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d605ed12f4eaaaec3dcd5aa909a4bad7", "", "", "Chronocolor Frame Demo (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d61629bbbe035f45552e31cef7d591b2", "", "", "Atari Logo Demo (PD) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d62283aed0f4199adb2333de4c263e9c", "Atari, Alan J. Murphy, Nick 'Sandy Maiwald' Turner", "CX2615", "Demons to Diamonds (1982) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 57", "", "", "", "", "" }, { "d62d7d1a974c31c5803f96a8c1552510", "", "", "StarMaster (Unknown) (PAL)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d632b74fea533d593af82cf16e7c5e4a", "", "", "Fu Kung! (V0.13) (01-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d65028524761ef52fbbdebab46f79d0f", "CCE", "", "Galaxian (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d65900fefa7dc18ac3ad99c213e2fa4e", "", "", "Grid and Purple Dot Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d69559f9c9dc6ef528d841bf9d91b275", "Activision, Alan Miller", "AX-016", "StarMaster (1982) (Activision)", "Use Color/BW switch to change between galactic chart and front views", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d6a44277c3eb4f9d039185e0ecf7bfa6", "", "", "Trick (1997) (Eckhard Stolberg)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d6acff6aed0f04690fe4024d58ff4ce3", "Spectravision - Spectravideo - Quelle", "SA-202 - 412.851 8", "Planet Patrol (1982) (Spectravision) (PAL) [different spaceship]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d6b8beeb05e5b730084d4b8f381bbf8d", "", "", "208 in 1 Game Select ROM (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d6d1ddd21e9d17ea5f325fa09305069c", "Funvision - Fund. International Co.", "", "Time Warp (1982) (Funvision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d6d5dd8fd322d3cf874e651e7b6c1657", "", "", "How to Draw a Playfield (1997) (Nick Bensema) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d6dc9b4508da407e2437bfa4de53d1b2", "Bomb - Onbase", "CA283", "Z-Tack (1983) (Bomb) (PAL)", "AKA Base Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d726621c676552afa503b7942af5afa2", "Atari, Bob Whitehead", "CX26163P", "Blackjack (32 in 1) (1988) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "", "", "63", "", "", "" }, { "d73ad614f1c2357997c88f37e75b18fe", "Goliath", "7", "Space Tunnel (1983) (Goliath) (PAL)", "AKA Cosmic Corridor", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d74a81fcd89c5cf0bd4c88eb207ebd62", "", "", "Poker Squares (V0.00a) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d763e3a9cdcdd56c715ec826106fab6a", "Activision, David Crane", "AG-001", "Dragster (1980) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "27", "", "", "" }, { "d7759fa91902edd93f1568a37dc70cdb", "Atari, Robert C. Polaro", "CX26157", "Stunt Cycle (1980) (Atari) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d782543818b6320e4f60d77da2b596de", "Atari", "CX26163P", "Fishing Derby (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d787ec6785b0ccfbd844c7866db9667d", "Retroactive", "", "Qb (V0.04) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d7891b0faa4c7f764482762d0ed427a5", "", "", "Bars and Text Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d79df06894e3c1585a47c2807332b319", "", "", "Star Fire - Explosions! (10-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d7b58303ec8d8c4dbcbf54d3b9734c7e", "", "", "Paddle Demo (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "", "", "", "", "", "" }, { "d7dd56677e4ec1e6627419478a4a9668", "", "", "Shadow Keep (Fixed) (04-03-2003) (Andrew Towers)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d7f5bf138cfc7feab7b8ef1534c8b477", "", "", "Eric Bergstrom's KC-135 (Radar Map) (Aaron Bergstrom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d816fea559b47f9a672604df06f9d2e3", "Atari, Gary Palmer", "CX26163P", "Fun with Numbers (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d81bb6965e6c99b3be99ffd8978740e4", "", "", "Gunfight 2600 - The Final Kernel Part 3 (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d82675ce67caf16afe5ed6b6fac8aa37", "", "", "Robot City (V0.23) (13-11-2002) (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d8295eff5dcc43360afa87221ea6021f", "Spectravideo", "SA-212", "Mangia' (1983) (Spectravideo) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d82c8a58098a6b46c5b81c16180354d1", "Dennis Debro", "", "Climber 5 (30-10-2002) (Dennis Debro) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d85f1e35c5445ac898746719a3d93f09", "Quelle", "731.503 9", "Tom's Eierjagd (1983) (Quelle) (PAL)", "AKA Play Farm", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d86deb100c6abed1588aa84b2f7b3a98", "Atari, Bob Whitehead - Sears", "CX2625 - 6-99827, 49-75114", "Football (1979) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d88691c995008b9ab61a44bb686b32e4", "", "", "Warring Worms (07-02-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d89fedded0436fdeda7c3c37e2fb7cf1", "", "", "Surround (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d8acaa980cda94b65066568dd04d9eb0", "CCE", "", "Sea Hunt (CCE)", "AKA Skindiver", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d8b2c81cea5af04f795eb3dc6573d72b", "", "", "Tunnel Demo 2 (27-03-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d8df256c0d89e494a9fb3e9abb8e44ac", "Imagic, Michael Greene", "IA3312P", "No Escape! (1982) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d8e4c8e2d210270cd1e0f6d1b4582b91", "Imagic, Mark Klein", "EIZ-003-04I", "Subterranea (1983) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d90205e29bb73a4cdf28ea7662ba0c3c", "Thomas Jentzsch", "", "Boulderdash Demo (Brighter Version) (09-12-2002) (TJ)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d912312349d90e9d41a9db0d5cd3db70", "CCE", "C-818", "Star Voyager (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d9548ad44e67edec202d1b8b325e5adf", "Apollo - Games by Apollo, Dan Oliver - RCA Video Jeux", "AP-2002", "Space Cavern (1982) (Apollo) (PAL)", "AKA Les guerriers de l'espace", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d97e3d0b4575ce0b9a6132e19cfeac6e", "Fabrizio Zavagli", "", "Space Treat (061002) (PD)", "Won't work with Stella < V1.2", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d97fd5e6e1daacd909559a71f189f14b", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (04-20-1983) (M Network) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d9ab6b67a17da51e5ad13717e93fa2e2", "", "", "Turbo (Coleco) Prototype Fake v0.1 (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d9b49f0678776e04916fa5478685a819", "Activision, John Van Ryzin - Ariola", "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720", "H.E.R.O. (1984) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "d9bd343533b61389b270c0787210943b", "Atari, Douglas 'Solaris' Neubauer", "CX26134", "Last Starfighter (1984) (Atari) (Prototype)", "Genesis controller (C switches to map mode)", "Hack of Last Starfighter (Solaris prototype)", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "d9c9cece2e769c7985494b1403a25721", "SOLID Corp. (D. Scott Williamson)", "CX2655*", "Star Castle 2600 (SolidCorp)", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "d9da2ae7c7894a29b43b3c6b79f3b7a2", "Atari, Rob Fulop", "CX2633, CX2633P", "Night Driver (1980) (Atari) (PAL) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 65", "", "", "", "YES", "" }, { "d9fbf1113114fb3a3c97550a0689f10f", "ZiMAG - Emag - Vidco", "713-111 - GN-050", "Pizza Chef (1983) (ZiMAG) (Prototype)", "AKA Pizza Time", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da0fb2a484d0d2d8f79d6e063c94063d", "", "", "Air Raiders (1982) (Unknown) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da4e3396aa2db3bd667f83a1cb9e4a36", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da5096000db5fdaa8d02db57d9367998", "Digitel", "", "River Raid (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da6465a34d2e44d26aa9a2a0cd1bce4d", "Absolute Entertainment, Alex DeMeo", "AG-041-04", "Title Match Pro Wrestling (1987) (Absolute) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da64f33d0521d5c9958e5d2d4434ff95", "", "", "Star Fire - Return of the Starfield (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da66d75e4b47fab99733529743f86f4f", "Digitel", "", "Chopper Command (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "da732c57697ad7d7af414998fa527e75", "Atari - Glenn Axworthy", "CX26129", "Midnight Magic (1986) (Atari) (PAL)", "AKA Pinball Wizard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "da79aad11572c80a96e261e4ac6392d0", "Salu - Ubi Soft, Dennis M. Kiss", "460673", "Pick 'n' Pile (1990) (Salu) (PAL)", "", "", "", "", "", "", "", "YES", "", "", "", "", "", "40", "256", "YES", "" }, { "da7a17dcdaa62d6971393c0a6faf202a", "", "", "Flag Capture (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dab844deed4c752632b5e786b0f47999", "", "", "Super Challenge Baseball (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dac38b4dd3da73bb7b2e9d70c61d2b7c", "", "", "Hangman Monkey Biglist3 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dac5c0fe74531f077c105b396874a9f1", "Atari - GCC", "CX2680", "RealSports Tennis (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dac762e4d01d445bdef20b7771f6570e", "Atari, Carla Meninsky, Ed Riddle - Sears", "CX2611 - 99821, 49-75149", "Indy 500 (1977) (Atari) (4K) [a]", "Uses the Driving Controllers", "", "", "", "", "", "", "", "DRIVING", "DRIVING", "", "45", "", "28", "", "", "" }, { "dad2ab5f66f98674f12c92abcfbf3a20", "", "", "Blue and White Sprite Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "daeb54957875c50198a7e616f9cc8144", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11005", "Mega Force (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "daef7d8e5a09981c4aa81573d4dbb380", "Adam Thornton", "", "Lord of the Rings (Adam Thornton) (Hack)", "Hack of Dark Mage", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "dafc3945677ccc322ce323d1e9930beb", "Atari", "", "A-Team (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "db1753cc702c18d3917ec7f3b0e8659f", "", "", "Frame Counter 2 (2001) (Jake Patterson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "db339aea2b65b84c7cfe0eeab11e110a", "", "", "Chronocolor Frame Demo 2 (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "db4eb44bc5d652d9192451383d3249fc", "CBS Electronics - E.F. Dreyer - VSS, Ed Salvo", "4L 2738 0000", "Mountain King (1983) (CBS Electronics)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "db5073bd75eb05f7d62a7268396d1e77", "Atari", "CX26163P", "Golf (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "db76f7a0819659d9e585f2cdde9175c7", "Xonox", "99005, 6220, 6250", "Robin Hood (1983) (Xonox) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "db80d8ef9087af4764236f7b5649fa12", "M Network, Steve Crandall, Patricia Lewis Du Long", "MT4646", "Rocky & Bullwinkle (1983) (Mattel) (Prototype) (4K)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "db971b6afc9d243f614ebf380af0ac60", "Gammation, Robert L. Esken Jr.", "", "Gamma-Attack (1983) (Gammation)", "Uses right joystick controller", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "220", "", "" }, { "dba2692a216cb6c262c78f8b111a813e", "", "", "Star Fire (08-10-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dba270850ae997969a18ee0001675821", "Greg Troutman", "", "Dark Mage (Greg Troutman) (PD) (4K)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "dbabb80e92ff18d8eecf615c0539151e", "", "", "Sprite Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dbb10b904242fcfb8428f372e00c01af", "Atari, John Dunn", "CX2631, CX2631P", "Superman (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dbc7485ad5814d466de780a3e7ed3b46", "Kyle Pittman", "", "Pink Floyd (Kyle Pittman) (PD)", "Hack of Adventures of Tron (Mattel)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dbc8829ef6f12db8f463e30f60af209f", "Data Age", "DA1001", "Encounter at L-5 (1982) (Data Age)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 50", "", "", "", "", "" }, { "dbdaf82f4f0c415a94d1030271a9ef44", "CCE", "", "Kaboom! (CCE)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "dbdd21e1ee3d72119e8cd14d943c585b", "", "", "Slot Machine (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dc13df8420ec69841a7c51e41b9fbba5", "Atari, Mimi Nyden, Steve Woita", "CX26132", "Garfield (06-21-1984) (Atari) (Prototype)", "AKA Garfield on the Run", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dc33479d66615a3b09670775de4c2a38", "Suntek", "SS-033", "I.Q. Memory Teaser (Suntek) (PAL)", "AKA IQ 180", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dc6aa0bb21a6e66e80e75ba5edc5c0dd", "", "", "Star Fire - Kernel Done (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dc81c4805bf23959fcf2c649700b82bf", "Imagic, Michael Greene", "720055-2A, IA3312P", "No Escape! (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dc905b22de0f191a029df13eddfcabc4", "Atari, Warren Robinett", "", "Elf Adventure (05-02-83) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dca90ea1084a2fdbe300d7178ca1a138", "Imagic, Dennis Koble", "IA3000P", "Trick Shot (1982) (Imagic) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "dca941dab5c6f859b71883b13ade9744", "", "", "Hangman Pac-Man Biglist2 (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dcba0e33aa4aed67630a4b292386f405", "Retroactive", "", "Qb (V2.08) (Half Speed Version) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "dcc2956c7a39fdbf1e861fc5c595da0d", "M Network - APh Technological Consulting, David Rolfe - INTV", "MT5664", "Frogs and Flies (1982) (M Network)", "AKA Frogs 'n' Flies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dcec46a98f45b193f07239611eb878c2", "", "", "Bars and Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd08e18cfee87a0e7fc19a684b36e124", "Atari - GCC, Kevin Osborn", "CX2689, CX2689P", "Kangaroo (1983) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd0cbe5351551a538414fb9e37fc56e8", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99006, 6220", "Sir Lancelot (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd0de0f61af2a2a4878e377b880a3933", "SOLID Corp. (D. Scott Williamson)", "CX2655-013", "Star Castle 2600 (SolidCorp) [013]", "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "dd10b5ee37fdbf909423f2998a1f3179", "", "", "Space Instigators (V1.9) (21-10-2002) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd1422ffd538e2e33b339ebeef4f259d", "Atari, Tod Frye", "", "Red Vs. Blue (1981) (Atari) (Prototype)", "RealSports Football Beta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd17711a30ad60109c8beace0d4a76e8", "", "", "Karate (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "dd4f4e0fbd81762533e39e6f5b55bb3a", "", "", "Turbo WIP (TJ)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd7598b8bcb81590428900f71b720efb", "Xonox - K-Tel Software - Computer Magic", "99005, 6220, 6250", "Robin Hood (1983) (Xonox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "dd7884b4f93cab423ac471aa1935e3df", "Atari, Brad Stewart - Sears", "CX2649, 49-75163", "Asteroids (1981) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "dd8a2124d4eda200df715c698a6ea887", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (3 of 3) (1982) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dd92d6ad50976f881d86b52d38616118", "SpkSoft", "", "River Raid (SpkSoft) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dda23757407c4e217f64962c87ad0c82", "Atari Freak 1", "", "Nitemare at Sunshine Bowl-a-Rama (Atari Freak 1) (Hack) [a]", "Hack of Pac-Man Jr.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ddd1efc1862cd3eb3baf4cba81ff5050", "", "", "Max3 (2001) (Maxime Beauvais) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de0173ed6be9de6fd049803811e5f1a8", "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson", "99008, 6240", "Motocross Racer (1983) (Xonox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de07e9cb43ad8d06a35f6506e22c62e9", "", "", "Oh No! (Version 4) (22-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de1a636d098349be11bbc2d090f4e9cf", "", "", "Pressure Gauge (Hozer Video Games)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de1e9fb700baf8d2e5ae242bffe2dbda", "Activision - Imagineering, Mike Reidel", "EAK-043-04I", "Commando (1988) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de24f700fd28d5b8381de13abd091db9", "CCE", "", "Plaque Attack (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de29e46dbea003c3c09c892d668b9413", "Coleco - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen", "4L1717, 4L1718, 4L1719, 4L2277", "Carnival (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de3d0e37729d85afcb25a8d052a6e236", "Spectravision - Spectravideo", "SA-204", "Tapeworm (1982) (Spectravision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "de4436eaa41e5d7b7609512632b90078", "Activision, David Crane", "AX-014, AX-014-04", "Grand Prix (1982) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de5aab22e5aba5edcb29a3e7491ff319", "Star Game", "001", "Donkey Kong (Star Game)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "de61a0b171e909a5a4cfcf81d146dbcb", "Rainbow Vision - Suntek", "SS-005", "Tom Boy (Rainbow Vision) (PAL)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de62f8a30298e2325249fe112ecb5c10", "CCE", "C-810", "Enduro (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de78b3a064d374390ac0710f95edde92", "Bomb - Onbase", "CA281", "Assault (1983) (Bomb)", "AKA Sky Alien", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "de7a64108074098ba333cc0c70eef18a", "", "", "Nuts (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "37", "", "", "" }, { "de7bca4e569ad9d3fd08ff1395e53d2d", "Thomas Jentzsch", "", "Thrust (V1.22) (2000) (TJ)", "Won't work with Stella < V1.2, supports Booster Grip", "New Release", "", "", "", "", "", "", "BOOSTERGRIP", "", "", "", "", "", "", "", "" }, { "de8443ff47283e7b274a7838cb071fb6", "Atari, Lou Harp", "CX26122", "Sinistar (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dea0ade296f7093e71185e802b500db8", "CCE", "", "Fishing Derby (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "deb39482e77f984d4ce73be9fd8adabd", "Activision, David Lubar", "AK-048-04", "River Raid II (1988) (Activision) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ded26e1cb17f875a9c17515c900f9933", "", "", "Space Treat (29-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df12953b919844dad2070ed2e70c9fa2", "Amiga - Video Soft", "3135", "S.A.C. Alert (1983) (Amiga) (Prototype) (PAL)", "Uses Joyboard", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df2745d585238780101df812d00b49f4", "Bit Corporation", "PG202", "Space Tunnel (1982) (BitCorp)", "AKA Cosmic Corridor, Weltraum-Tunnel", "", "", "", "", "", "", "", "", "", "", "", "", "", "222", "", "" }, { "df3e6a9b6927cf59b7afb626f6fd7eea", "", "", "Tuby Bird (208 in 1) (Unknown) (PAL)", "AKA Dolphin", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df40af244a8d68b492bfba9e97dea4d6", "Franklin Cruz", "", "Asteroids 2 (Franlin Cruz) (Hack)", "Hack of Asteroids", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "df5cc5cccdc140eb7107f5b8adfacda1", "Cracker Jack Productions", "", "Lumberman (Cracker Jack) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "df62a658496ac98a3aa4a6ee5719c251", "Atari, Tom Reuterdahl - Sears", "CX2626 - 6-99829, 49-75116", "Miniature Golf (1979) (Atari)", "AKA Arcade Golf", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df6a28a89600affe36d94394ef597214", "Apollo - Games by Apollo, Dan Oliver", "AP-2002", "Space Cavern (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df6a46714960a3e39b57b3c3983801b5", "Puzzy - Bit Corporation", "PG201", "Sea Monster (1982) (Puzzy) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df753cb87d3af4d03f694ab848638108", "CBS Electronics, Bob Curtiss", "4L1845, 4L1852, 4L1853, 4L1854", "Solar Fox (1983) (CBS Electronics) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "df95e4af466c809619299f49ece92365", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (06-03-1983) (Atari) (Prototype) (PAL)", "Uses Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "dfad86dd85a11c80259f3ddb6151f48f", "HES - Imagineering, David Lubar", "535", "My Golf (1990) (HES) (PAL) [fixed]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dfafa3fa58f5cc3f0342cca475df6095", "", "", "Space Treat (V1.1 Beta) (24-12-2002) (Fabrizio Zavagli)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dfc03ef371cf5163f54c50d8ee73c8cf", "Atari, Gary Palmer", "CX2661", "Fun with Numbers (1980) (Atari) (4K)", "AKA Basic Math", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dfc3dbbb39f05d7dd8ee3ac987478970", "", "", "Imagic Selector ROM (1982) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dfcdd6f593bb7b05dbc2e8e1fc6ee0de", "", "", "Gunfight 2600 - Scenarios complete (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dfe034297200dff672df9533ed1449a9", "", "", "Sprite Movement Demo 1 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "dfe6aa7443bb813cefa35a4cf4887422", "", "", "This Planet Sucks (Greg Troutman) [a1]", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "dff33523ccd2fdc8912e84cab8e0d982", "", "", "Fu Kung! (V0.03) (10-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e01e00504e6d4b88fa743c0bbe8a96e5", "", "", "Qb (Special Edition, some bugfixes) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e020f612255e266a8a6a9795a4df0c0f", "Telegames - VSS", "7062 A305", "Universal Chaos (1988) (Telegames) (PAL)", "AKA Targ", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e02156294393818ff872d4314fc2f38e", "Sancho - Tang's Electronic Co.", "TEC005", "Dice Puzzle (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e0221c95aa657f5764eeeb64c8429258", "", "", "Tomb Raider 2600 [REV 02] (Montezuma's Revenge Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e03b0b091bea5bc9d3f14ee0221e714d", "CBS Electronics, Bob Curtiss", "4L1852, 4L1853, 4L1854, 4L1855", "Solar Fox (1983) (CBS Electronics) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e040df95a055b18ebdb094e904cb71b2", "", "", "Score Demo (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e04f1c1e4401d584d3f4343410a5bcc4", "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin", "007", "Halloween (1983) (Wizard Video Games) (Prototype) [a]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e0b24c3f40a46cda52e29835ab7ad660", "Quelle - Otto Versand", "626.502 9 - 746381", "Top Gun (1983) (Quelle) (PAL)", "AKA Air Raiders", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e0cf2dcc4c1348c468f5bb1e421c9164", "", "", "Invader Sprites in a Line Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e0de3773f5b867795db557be7b8a703e", "", "", "Boulderdash (13 Blocks Wide) (02-04-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e0eff071f578ecf19edc2ab276644e46", "", "", "Gas Gauge Demo (2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1029676edb3d35b76ca943da7434da8", "Atari, Robert C. Polaro, Alan J. Murphy - Sears", "CX2609 - 49-75186", "Defender (10-30-1981) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e10bf1af6bf3b4a253c5bef6577fe923", "Rob Kudla", "", "Space Invaders (1978) (Atari) [h1]", "Hack of Space Invaders (Atari)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e10d2c785aadb42c06390fae0d92f282", "Parker Brothers, Dawn Stockbridge", "PB5910", "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "225", "", "" }, { "e1143b72a30d4d3fee385eec38b4aa4d", "", "", "Word Zapper (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e12e32dee68201b6765fcd0ed54d6646", "Atari, Larry Kaplan", "CX2612, CX2612P", "Street Racer (1977) (Atari) (PAL)", "Uses the Paddle Controllers (swapped)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 75", "", "", "", "", "" }, { "e13818a5c0cb2f84dd84368070e9f099", "CCE", "C-839", "Misterious Thief, A (1983) (CCE)", "AKA A Mysterious Thief", "", "", "", "", "", "", "", "", "", "", "", "", "", "216", "YES", "" }, { "e13c7627b2e136b9c449d9e8925b4547", "Atari, Alan Miller - Sears", "CX2624 - 6-99826, 49-75113", "Basketball (1978) (Atari) (4K)", "", "Common", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1486c7822c07117b4f94a32e5ed68c1", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (06-14-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e14dc36b24fe22c04fa076e298f2e15f", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (16K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "e14feddeb82f5160ed5cf9ca4078e58d", "", "", "SpaceMaster X-7 (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e150f0d14f013a104b032305c0ce23ef", "Spectravision - Spectravideo", "SA-205", "China Syndrome (1982) (Spectravision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e15b5525cf8f77297b322838df8d999c", "", "", "Sprite Demo 0 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e171558c51bb3bac97bfa79fa2c1a19c", "", "", "Warring Worms (Tim Strauss Edition) (20-12-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e17699a54c90f3a56ae4820f779f72c4", "Quelle", "465.302 8", "Vogel Flieh (1983) (Quelle) (PAL)", "AKA Dolphin", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e18abe87035379c56b435bfe8175077b", "Grimlock", "", "Rumble 2600 (Grimlock) (Hack)", "Hack of Mario Bros.", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1a51690792838c5c687da80cd764d78", "20th Century Fox, John Russell", "", "Alligator People (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1b90f1e01b1a316d7bbf141525cc00e", "", "", "Sky Jinks (Unknown) (PAL) (4K) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1d5c8213e82820128fa9c4775f1e166", "Jess Ragan", "", "Jungle King (2003) (Jess Ragan) (Hack)", "Hack of Jungle Hunt", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1d79e4e7c150f3861256c541ec715a1", "", "", "Space Jockey (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1e09e2f280e8e142121a377d0dc1b46", "Thomas Jentzsch", "", "Thrust (V1.21) (2000) (TJ)", "Won't work with Stella < V1.2, bugfixed", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1efe2ef7664bb6758b1a22ff8ea16a1", "Dynacom", "", "Enduro (1983) (Dynacom)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e1f88da6da8a7d521ca1dcbf2bc6978b", "Activision, Bob Whitehead - Ariola", "EAG-005, PAG-005, EAG-005-04B - 711 005-715", "Skiing (1980) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e21ee3541ebd2c23e817ffb449939c37", "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec", "7-001", "King Kong (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "", "", "" }, { "e237ee91514d5ed535c95a14fc608c11", "Activision, Matthew L. Hubbard, Bob Whitehead", "AX-024", "Dolphin (1983) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e2389c0be5b5b84e0d3ca36ec7e67514", "Retroactive", "", "Qb (V2.09) (NTSC) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e24d7d879281ffec0641e9c3f52e505a", "Parker Brothers, Mark Lesser", "PB5950", "Lord of the Rings (1983) (Parker Bros) (Prototype)", "Journey to Rivendell (The Lord of the Rings I)", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e25e173740f7ecc0e23025445c4591f3", "Greg Zumwalt", "", "Comitoid (Greg Zumwalt)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e275cbe7d4e11e62c3bfcfb38fca3d49", "M Network - APh Technological Consulting, Ken Smith - INTV", "MT5658", "Super Challenge Football (1982) (M Network)", "AKA Pro Football", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e28113d10c0c14cc3b5f430b0d142fcb", "CCE", "C-816", "Keystone Kappers (1983) (CCE) [a]", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e2846af3e4d172b251ab77cbdd01761e", "Steve Engelhardt", "", "Adventure Plus (2003) (Steve Engelhardt) (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e2904748da63dfefc8816652b924b642", "Jone Yuan Telephonic Enterprise Co", "", "Catch Time (Jone Yuan)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e2b682f6e6d76b35c180c7d847e93b4f", "", "", "Dodge Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e2c1b60eaa8eda131632d73e4e0c146b", "Atari - GCC, Mark Ackerman, Noellie Alito", "CX2692", "Moon Patrol (07-04-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e2c89f270f72cd256ed667507fa038a2", "Starpath Corporation, Stephen H. Landrum", "AR-4101", "Communist Mutants from Space (1982) (Arcadia) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e2ca84a2bb63d1a210ebb659929747a9", "Telesys, Don 'Donyo' Ruffcorn", "1002", "Cosmic Creeps (1982) (Telesys) (PAL)", "AKA Space Maze, Spaze Maze", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e2eccbbe963f80f291cb1f18803bf557", "Atari, Joe Decuir, Steve Mayer, Larry Wagner", "CX26163P", "Combat (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "40", "256", "", "" }, { "e314b42761cd13c03def744b4afc7b1b", "Activision, David Crane, Dan Kitchen", "AZ-108-04", "Ghostbusters (1985) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e34c236630c945089fcdef088c4b6e06", "Activision, David Crane - Ariola", "EAB-035-04 - 711 035-721", "Pitfall II (1984) (Activision) (PAL)", "Lost Caverns", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e3533684a7ef930a7fbd0c4dd8ec4847", "CCE", "C-856", "Pimball (1983) (CCE)", "AKA Video Pinball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e3600be9eb98146adafdc12d91323d0f", "Atari, Carol Shaw", "CX2618, CX2618P", "3-D Tic-Tac-Toe (1980) (Atari) (PAL)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e363e467f605537f3777ad33e74e113a", "Atari, Bob Whitehead - Sears", "CX2603 - 99803, 49-75601", "Star Ship (1977) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e377c3af4f54a51b85efe37d4b7029e6", "20th Century Fox Video Games, Steve Beck", "11035", "Save the Whales (1983) (20th Century Fox) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e37c8055d70979af354251ebe9f1b7dd", "HES", "", "Mega Funpak - Gorf, P. Patrol, Pacman, Skeet Shoot (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e38dc1f81a02e325562cd285123f579b", "Atari - GCC, Mike Feinstein", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e39843c56b7a4a08b18fa7949ec3ee6b", "", "", "Joshua Invaders (Hack)", "Hack of Space Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e39a13b13dc82c5fdbfbbfd55ba1230e", "", "", "Analog Clock (Additional Frame Info) (V0.0) (20-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e3c0451d29dad724231bc5818ec4bae0", "", "", "Single-Scanline Positioning Demo 1 (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e3c35eac234537396a865d23bafb1c84", "TechnoVision - Video Technology", "TVS1001", "Nuts (1983) (TechnoVision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "45", "", "", "" }, { "e3ed4ba3361756970f076e46e9cad1d2", "", "", "Tennis (Unknown) (PAL) (4K) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e40a818dac4dd851f3b4aafbe2f1e0c1", "Atari, Bill Aspromonte, Dr. Lee Salk", "CX26135", "Peek-A-Boo (1984) (Atari) (Prototype)", "Uses the Keypad Controllers", "Prototype", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "e42b937c30c617241ca9e01e4510c3f6", "", "", "Pitfall! (No Walls Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e434c0e161dd3c3fb435eb6bad2e182c", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681", "Battlezone (05-02-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e49ac0ec879a0d7820bc2598fc2cfcd4", "CCE", "", "Kaboom! (CCE) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "e4a0b28befaaa2915df1fa01238b1e29", "", "", "Gunfight 2600 - Red River (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e4afe157c09962cf39cdb25845d83d47", "Activision, David Crane - Ariola", "EAG-009, PAG-009 - 711 009-720", "Freeway (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e4b12deaafd1dbf5ac31afe4b8e9c233", "Adam Thornton", "", "Lord of the Rings (Adam Thornton) (Hack) [a]", "Hack of Dark Mage", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e4bff1d5df70163c0428a1ead309c22d", "Atari, Robert C. Polaro, Alan J. Murphy", "CX2609, CX2609P", "Defender (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e4c00beb17fdc5881757855f2838c816", "20th Century Fox Video Games - Sirius, Ed Hodapp", "11004", "Deadly Duck (1982) (20th Century Fox)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e4c2077a18e3c27f4819aa7757903aa0", "", "", "Many Blue Bars Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e4c666ca0c36928b95b13d33474dbb44", "Arcadia Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Arcadia)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e4d41f2d59a56a9d917038682b8e0b8c", "Cody Pittman", "", "Kiss Meets Pacman (Cody Pittman) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "e4e9125a8741977583776729359614e1", "SnailSoft", "", "Comitoid beta 4 (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e505bd8e59e31aaed20718d47b15c61b", "Funvision - Fund. Int'l Co.", "", "Space War (1982) (Funvision) (PAL)", "AKA Condor Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e51030251e440cffaab1ac63438b44ae", "Parker Brothers - On-Time Software, Joe Gaucher, Louis Marbel", "PB5110", "James Bond 007 (1984) (Parker Bros)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e51c23389e43ab328ccfb05be7d451da", "Arcadia Corporation, Scott Nelson", "13", "Sweat! - The Decathlon Game (1983) (Arcadia) (Prototype)", "Uses the Paddle Controllers (left only)", "Prototype", "", "", "", "", "", "", "PADDLES", "", "", "", "", "", "", "", "" }, { "e5359cbbbff9c6d7fe8aeff5fb471b46", "CCE", "C-849", "Boom Bang (1983) (CCE)", "AKA Crackpots", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e549f1178e038fa88dc6d657dc441146", "Atari, Bob Whitehead - Sears", "CX2625 - 6-99827, 49-75114", "Football (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e556e07cc06c803f2955986f53ef63ed", "Coleco - Individeo, Ed Temple", "2665", "Front Line (1984) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e558be88eef569f33716e8e330d2f5bc", "Shock Vision", "", "Keystone Kapers (Shock Vision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e56da674188ba2f02c7a0a343a01236f", "", "", "This Planet Sucks Demo 4 (Greg Troutman) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "36", "", "", "" }, { "e5a6e0bb7d56e2f08b237e15076e5699", "", "", "Color Table Display Helper (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e5bacf526036d3c8c99db5b030cf00e7", "", "", "Starmaster (Genesis)", "Genesis controller (C switches to map mode)", "Hack of Starmaster", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "e5d5085123a98c1e61818caa2971e999", "", "", "Euchre (PAL) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e5d72ff8bab4450be57785cc9e83f3c0", "Telegames", "6082 A145", "Kung Fu Superkicks (1988) (Telegames) (PAL)", "AKA Chuck Norris Superkicks", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e5ecd78edd24326a968809decbc7b916", "Imagic, Bob Smith", "720020-1A, IA3611", "Cheese (Dragonfire Beta) (05-21-1982) (Imagic) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e5f17b3e62a21d0df1ca9aee1aa8c7c5", "CommaVid, John Bronstein", "CM-003", "Cosmic Swarm (1982) (CommaVid)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e5f360226dc552aba3e7e9b202330f48", "Supercat", "", "Mega Bitmap Demo (2007) (Supercat)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e5f84930aa468db33c0d0f7b26dd8293", "CCE", "C-826", "Grand Prix (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e5fcc62e1d73706be7b895e887e90f84", "", "", "Air-Sea Battle (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "40", "260", "", "" }, { "e600f5e98a20fafa47676198efe6834d", "Parker Brothers - Roklan", "PB5080", "Gyruss (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e609e8a007127b8fcff79ffc380da6b1", "", "", "Multi-Sprite Game V2.3 (Piero Cavina) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e61210293b14c9c4ecc91705072c6a7e", "Gameworld", "133-005", "Bugs (1983) (Gameworld) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 50", "", "", "", "", "" }, { "e62e60a3e6cb5563f72982fcd83de25a", "Jone Yuan Telephonic Enterprise Co", "", "End of the World (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "240", "", "" }, { "e63a87c231ee9a506f9599aa4ef7dfb9", "Tigervision, Warren Schwader", "7-003", "Threshold (1982) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "22", "", "", "" }, { "e63efdfda9a4003dcd77a854a781a06a", "Paul Slocum", "", "Combat Rock (PD) (Hack) [a]", "Hack of Combat", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e643aaec9a9e1c8ab7fe1eae90bc77d7", "Roger Williams", "", "Asymmetric Playfield (Roger Williams)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e64a8008812327853877a37befeb6465", "Answer Software Corporation - TY Associates", "ASC1002", "Gauntlet (1983) (Answer Software)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e6508b878145187b87b9cded097293e7", "", "", "Oystron (V2.8) (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e66e5af5dea661d58420088368e4ef0d", "Activision, Bob Whitehead", "AG-011", "Stampede (1981) (Activision) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e6d5948f451a24994dfaaca51dfdb4e1", "Jone Yuan Telephonic Enterprise Co", "", "Football (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e6de4ef9ab62e2196962aa6b0dedac59", "Imagic, Wilfredo Aguilar, Michael Becker, Dennis Koble", "720113-2A, 13206", "Solar Storm (1983) (Imagic) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "", "", "01 45", "", "", "", "", "" }, { "e6e5bb0e4f4350da573023256268313d", "Thomas Jentzsch", "", "Missile Control (Thomas Jentzsch)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e6f49a1053c79211f82be4d90dc9fe3d", "", "", "Gunfight 2600 - Little progress... (2001) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e723ad8f406cb258b89681ef4cef0eff", "Thomas Jentzsch", "", "Sadoom (TJ) (PAL) (Hack)", "Hack of Kaboom!", "Hack", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "e72eb8d4410152bdcb69e7fba327b420", "Atari, Douglas Neubauer, Mimi Nyden", "CX26136", "Solaris (1986) (Atari)", "AKA Universe, Star Raiders II, The Last Starfighter", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e72ee2d6e501f07ec5e8a0efbe520bee", "Imagic, Dave Johnson", "720119-2A, 13211, EIX-004-04I", "Quick Step! (1983) (Imagic) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e73838c43040bcbc83e4204a3e72eef4", "CCE", "", "Apples and Dolls (CCE)", "AKA I Want My Mommy", "", "", "", "", "", "", "", "", "", "", "", "", "", "215", "YES", "" }, { "e74022cfe31ec8908844718dfbdedf7a", "", "", "Space Treat (30-12-2002) (Fabrizio Zavagli) [a2]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e77ec259e1387bc308b0534647a89198", "Parker Brothers, David Lamkins, Laura Nikolich", "931503", "Spider-Man (1982) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e77f332b71f13884c84771e7a121182d", "Jone Yuan Telephonic Enterprise Co", "", "Hey! Stop! (Jone Yuan)", "AKA Keystone Kapers", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e784a9d26707cfcd170a4c1c60422a72", "Quelle", "147.443 6", "Gefecht im All (1983) (Quelle) (PAL)", "AKA Space Jockey", "", "", "", "", "", "", "", "", "", "", "", "", "64", "", "", "" }, { "e7864caaf9ec49ed67b1904ce8602690", "", "", "Donkey Kong 2K3 Pic (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e7a758bb0b43d0f7004e92b9abf4bc83", "", "", "Troll's Adventure (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e7dd8c2e6c100044002c1086d02b366e", "Activision, Steve Cartwright - Ariola", "EAX-013, PAX-013, 711 013-720", "Barnstorming (1982) (Activision) (PAL)", "AKA Die tollkeuhnen Flieger", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e7f005ddb6902c648de098511f6ae2e5", "Spectravideo - Universum", "SV-010", "CompuMate (1983) (Spectravideo) (PAL)", "", "", "", "CM", "", "", "", "", "", "", "", "", "", "", "", "YES", "80" }, { "e800e4aec7c6c54c9cf3db0d1d030058", "", "", "Qb (2.06) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e80a4026d29777c3c7993fbfaee8920f", "", "", "Frisco (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e823b13751e4388f1f2a375d3560a8d7", "Arcadia Corporation, Stephen Harland Landrum", "AR-4105", "Official Frogger (Preview) (1983) (Arcadia) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "32", "", "", "" }, { "e879b7093ac4cfad74c88d636ca97d00", "", "", "Poker Squares (V0.0f) (2001) (B. Watson)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e88340f5bd2f03e2e9ce5ecfa9c644f5", "", "", "Lock 'n' Chase (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e8a3473bf786cf796d1336d2d03a0008", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (12-05-1983) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e8aa36e3d49e9bfa654c25dcc19c74e6", "Atari, Joe Decuir, Larry Caplan, Steve Mayer, Larry Wagner", "CX2601, CX2601P", "Combat (1977) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "260", "", "" }, { "e8e7b9bdf4bf04930c2bcaa0278ee637", "", "", "Boring Taz (Hack)", "Hack of Taz", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e8f7679359c4f532f5d5e93af7d8a985", "", "", "Hangman Invader Original Words (Hack)", "Hack of Hangman", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e9034b41741dcee64ab6605aba9de455", "Digivision", "", "Phanton Tank (Digivision)", "AKA Tanks But No Tanks", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "e908611d99890733be31733a979c62d8", "Atari, Dan Hitchens, Mimi Nyden", "CX2697", "Mario Bros. (1983) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e91d2ecf8803ae52b55bbf105af04d4b", "Atari, Howard Scott Warshaw", "CX2655, CX2655P", "Yars' Revenge (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e923001015bedd7901569f035d9c592c", "", "", "Adventure II (Hack)", "Hack of Adventure", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e927ecf80f3784d745abd8368d78f2f3", "", "", "Space Instigators (V1.8) (19-10-2002) (CT) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e932f44fad2a66b6d5faec9addec208e", "", "", "Atari Logo Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e94632b0d863dd76459d689a9865bb33", "Jone Yuan Telephonic Enterprise Co", "", "Combat (Jone Yuan) (4K)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e957eb4612d6bd5940d3492dfa749668", "", "", "Tunnel Demo (27-03-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e959b5a2c882ccaacb43c32790957c2d", "", "", "Phantom II & Pirate (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e97eafd0635651d3999cece953c06bd5", "", "", "M.A.S.H (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e9be3e8e4a7e73dd63ed4235a3a1a25f", "", "", "MMetall (Hack)", "Hack of Miniature Golf", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e9c5d04643855949a23ff29349af74ea", "", "", "SCSIcide (Score Hack 2) (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e9c71f8cdba6037521c9a3c70819d171", "Action Hi Tech - Hi-Score", "", "Bank Heist (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e9cb18770a41a16de63b124c1e8bd493", "Parker Brothers, Joe Gaucher", "931519", "Popeye (1983) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "e9e646f730b8400cd5da08c849ef3e3b", "Tron", "", "Enduro (Tron)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e9e6ad30549a6e2cd89fe93b7691d447", "Atari - Bobco, Robert C. Polaro", "CX26140, CX26140P", "Desert Falcon (05-27-1987) (Atari) (Prototype) (PAL)", "AKA Nile Flyer, Sphinx", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "e9f25c7af4f27c9e1b5b8f6fe6141e8c", "Champ Games", "CG-03-N", "Scramble (NTSC)", "Compatible with Genesis controller", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ea38fcfc06ad87a0aed1a3d1588744e4", "Atari, Lou Harp", "CX26122", "Sinistar (1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ea6d40db5498d6386571a76df448aa4c", "", "", "Vertical Playfield Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ea7e25ade3fe68f5b786ee0aa82b1fe5", "", "", "Galatic (208 in 1) (Unknown) (PAL)", "AKA Challenge of.... Nexar, The", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ea832e2cb6aae6f525f07452c381fa48", "", "", "Polar to Cartesian and VV (2001) (Roger Williams)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ea86176b27ab0da8cce8f0179884bfaa", "", "", "Demo Image Series #10 - It's Art (28-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eaacfcdc1d4ee1258429b7ae7f084125", "Telegames", "6057 A227", "Quest for Quintana Roo (1989) (Telegames)", "Genesis controller (B is action button, C chooses tool or weapon)", "Hack of Quest for Quintana Roo", "", "", "", "", "", "", "GENESIS", "", "", "", "", "", "", "", "" }, { "ead60451c28635b55ca8fea198444e16", "Sancho - Tang's Electronic Co.", "TEC004", "Nightmare (1983) (Sancho) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "eada0dd61ce13f8317de774dc1e68604", "", "", "2600 Digital Clock (Demo 1) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eae0c06ee61c63b81cd016096fc901b0", "Joe Grand", "", "SCSIcide (v1.0) (2001) (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eae6a5510055341d3abeb45667bb3e9b", "HES", "", "Wall Defender (HES) (PAL)", "AKA Wall Break", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eaf744185d5e8def899950ba7c6e7bb5", "Atari", "CX26172", "Xenophobe (1991) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eafe8b40313a65792e88ff9f2fe2655c", "Eric Ball", "ELB004", "Skeleton+ (NTSC)", "Stereo sound", "Homebrew", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eb3d680699f8762f71f38e28e321234d", "", "", "Fu Kung! (V0.01) (08-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eb4252faff7a4f2ba5284a98b8f78d1a", "", "", "John K Harvey's Equalizer (NTSC) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "eb46e99ec15858f8cd8c91cef384ce09", "Goliath - Hot Shot", "83-113", "Ground Zero (1983) (Goliath) (PAL)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eb503cc64c3560cd78b7051188b7ba56", "Star Game", "043", "Moto Laser (Star Game)", "AKA Mega Force", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eb634650c3912132092b7aee540bbce3", "Atari, Eric Manghise, Mimi Nyden, Joseph Tung", "CX2640", "RealSports Baseball (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "eb6d6e22a16f30687ade526d7a6f05c5", "Atari", "CX26150P", "Q-bert (1987) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eb71743c6c7ccce5b108fad70a326ad9", "", "", "Euchre (25-11-2001) (Erik Eid) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eb7934360658a29c50aeaff20bfda23b", "Activision, John Van Ryzin", "EAZ-036-04", "H.E.R.O. (1984) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "SECAM", "", "", "", "" }, { "eb92193f06b645df0b2a15d077ce435f", "Starpath Corporation, Steve Hales, Stephen H. Landrum", "4 AR-4102", "Suicide Mission (1982) (Starpath) (PAL)", "AKA Meteoroids", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "eb9712e423b57f0b07ccd315bb9abf61", "Retroactive", "", "Qb (V2.04) (PAL) (2001) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "eb9f8b84c193d9d93a58fca112aa39ed", "", "", "Register Twiddler Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ebcb084a91d41865b2c1915779001ca7", "JVP", "", "Bob Is Going Home (JVP)", "AKA Bobby Is Going Home", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ebcbc8a181a738e13df6216e5c329230", "Activision, Steve Cartwright", "AX-022", "Seaquest (1983) (Activision) (16K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ebd2488dcace40474c1a78fa53ebfadf", "Skill Screen Games, Herman Quast", "SSG001", "Extra Terrestrials (1984) (SSG)", "The only Canadian-designed and manufactured Atari 2600 game from the 1980's", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ebf2dff78a08733251bf3838f02f7938", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype) [a2]", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "23", "240", "", "" }, { "ebf9038e927e6a0db3e0d170c59911e6", "", "", "Pac-2600 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ec26fdc87b1d35f1d60ea89cda4f4dd4", "", "", "Star Fire - Crash Scene (04-11-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ec3beb6d8b5689e867bafb5d5f507491", "U.S. Games Corporation - Vidtec - JWDA, Todd Marshall, Henry Will IV", "VC1003", "Word Zapper (1982) (U.S. Games)", "AKA Word Grabber", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ec407a206b718a0a9f69b03e920a0185", "Quelle", "876.482 1", "Landung in der Normandie (1983) (Quelle) (PAL)", "AKA Commando Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ec5c861b487a5075876ab01155e74c6c", "Apollo - Games by Apollo, Ed Salvo, Byron Parks", "AP-2001", "Spacechase (1982) (Apollo)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ece463abde92e8b89bcd867ec71751b8", "Puzzy - Bit Corporation", "PG205", "Dancing Plate (1982) (Puzzy) (PAL)", "AKA Dishaster", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ece908d77ab944f7bac84322b9973549", "", "", "Tom Boy (Unknown) (PAL60)", "AKA Pitfall!", "", "", "", "", "", "", "", "", "", "", "", "PAL60", "", "", "", "" }, { "ecf51385384b468834611d44a8429c03", "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer", "11105", "Mega Force (1982) (20th Century Fox) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ecfa04523dde82fe42cdc7315a8f61b6", "Activision, David Crane - Ariola", "EAG-004, PAG-004 - 711 004-715", "Fishing Derby (1980) (Activision) (PAL) (4K)", "AKA Schneller als der Hai", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed014beeeb77dbb2bbcf9b5f6850b2f4", "", "", "Green Bar Text Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed0451010d022b96a464febcba70b9c4", "PlayAround - J.H.M.", "203", "Knight on the Town (1982) (PlayAround) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ed0ab909cf7b30aff6fc28c3a4660b8e", "Panda", "105", "Stunt Man (1983) (Panda)", "AKA Nightmare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed1306436ce237afc5a7ed3f77134202", "HES", "771-341", "2 Pak Special - Dolphin, Pigs 'n' Wolf (1990) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed1492d4cafd7ebf064f0c933249f5b0", "CCE", "", "Video Cube (CCE)", "AKA Atari Video Cube", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed1a784875538c7871d035b7a98c2433", "", "", "Save Our Ship (Unknown) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "37", "", "", "" }, { "ed2218b3075d15eaa34e3356025ccca3", "Atari, Richard Maurer", "CX2635, CX2635P", "Maze Craze (1980) (Atari) (PAL)", "AKA A Game of Cops 'n Robbers", "", "", "", "", "", "", "", "", "", "", "", "PAL", "", "", "", "" }, { "ed5ccfc93ad4561075436ee42a15438a", "Atari, Tom Reuterdahl", "CX2626, CX2626P", "Miniature Golf (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ed8f319e82d355832195eb7715644795", "Activision, Larry Kaplan, David Crane", "AG-010, AG-010-04", "Kaboom! (1981) (Activision) (8K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "ed9999911b406dc5f75c850dcc17bdf4", "", "", "Star Fire - Shootable (Friendlier Collision Detection) (26-09-2002) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eddef10fdc0029301064115ae0cd41d4", "CCE", "", "Freeway (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ede4ab11ca346bd023b2c21d941e0c50", "Activision, David Crane", "EAZ-030", "Decathlon (1983) (Activision) (SECAM)", "", "", "", "", "", "", "", "", "", "", "", "", "SECAM", "", "", "", "" }, { "ede7e8bf865b0afb4744f86d13624f9a", "", "", "Demo Image Series #2 - Clown (19-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "edf69b123e06eaf8663cc78d8aeba06e", "SpkSoft 98", "", "River Raid (SpkSoft 98) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee28424af389a7f3672182009472500c", "Atari, Carol Shaw - Ralph Lauren", "", "Polo (1978) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee456542b93fa8d7e6a8c689b5a0413c", "", "", "Chronocolor Donkey Kong Clean (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee4c186123d31a279ed7a84d3578df23", "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner", "CX2608", "Super Breakout (1982 - 1981) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 45", "", "", "", "", "" }, { "ee659ae50e9df886ac4f8d7ad10d046a", "Exus Corporation", "", "Video Reflex (1983) (Exus)", "AKA Foot Craz", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee6665683ebdb539e89ba620981cb0f6", "Coleco", "2658", "Berenstain Bears (1983) (Coleco)", "Uses the KidVid Controller", "Unbelievably Rare", "", "", "", "", "", "", "", "", "", "", "", "25", "", "", "" }, { "ee67dc0b01746372d2b983d88f48e24f", "", "", "Scroller Demo (02-01-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee681f566aad6c07c61bbbfc66d74a27", "Activision", "", "Unknown Activision Game (10-29-1982) (Activision) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee6cbedf6c0aac90faa0a8dbc093ffbe", "CCE", "", "My Golf (CCE) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee8027d554d14c8d0b86f94737d2fdcc", "Canal 3 - Intellivision", "", "Yars' Revenge (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "ee84bdc5dae268e227e407c7b5e6b6b7", "", "", "Marilyn Monroe Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ee9caee4eb958284fb10c277b14537f1", "Carrere Video, Garry Kitchen - Teldec", "USC1001", "Space Jockey (1983) (Carrere Video) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "59", "", "", "" }, { "eea0da9b987d661264cce69a7c13c3bd", "Coleco", "2454", "Zaxxon (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eeb92f3f46df841487d1504f2896d61a", "Cody Pittman", "", "Corys Adventure (Cody Pittman) (Hack)", "Hack of Pac-Man", "Hack", "", "", "", "", "", "", "", "", "", "", "", "33", "", "", "" }, { "eec61cc4250df70939d48fe02d7122ac", "Activision, Bob Whitehead - Ariola", "EAG-005, PAG-005, EAG-005-04B - 711 005-715", "Skiing (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eed9eaf1a0b6a2b9bc4c8032cb43e3fb", "Atari - Axlon, Steve DeFrisco", "CX26192", "Klax (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "eee7695ae3eea7818321df0b790b31f3", "", "", "Sound Paddle V2 (Dennis Caswell & Jim Nitchals) (PD)", "Uses the Paddle Controllers", "", "", "", "", "", "", "YES", "PADDLES", "", "", "01", "", "", "", "", "" }, { "ef263d40a23483ab339cac44d9515a56", "Thomas Jentzsch", "", "Fatal Run (TJ)", "NTSC Conversion", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ef3a4f64b6494ba770862768caf04b86", "Activision, Bob Whitehead", "AG-034-04", "Private Eye (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ef60b06fddb675b0d783afbfa5fc5232", "", "", "Many Blue Bars and Text Demo 4 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ef66af190840871409fe1702d2483554", "Andrew Davie, Paul Slocum, Christopher Tumber", "", "DiscoTech (12-02-2003) (Andrew Davie)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ef71e9fb0d8d477226d8d42261fbf0a7", "Piero Cavina", "", "Multi-Sprite Demo V2.0 (Piero Cavina) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ef76ea05655a0b62cb1018c92b9b4b7d", "Gakken", "010", "Strategy X (1983) (Gakken) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "efa1098c7d091b940c2543abe372f036", "Scott Stilphen", "", "E.T. The Extra-Terrestrial (Scott Stilphen) (Hack)", "Hack of E.T. The Extra-Terrestrial", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "efb47d70b2965ce689e2c5757616b286", "", "", "Time Test Demo (Eckhard Stolberg) (PAL) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "efd387430a35a659ff569a9a0ec22209", "Atari - GCC", "CX26118", "Millipede (1984) (Atari) (Prototype) (PAL)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "efefc02bbc5258815457f7a5b8d8750a", "CBS Electronics, Richard K. Balaska Jr.", "4L 2520 5000", "Tunnel Runner (1983) (CBS Electronics) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "efffafc17b7cb01b9ca35324aa767364", "", "", "Circus Atari (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f02ba8b5292bf3017d10553c9b7b2861", "Atari", "CX26172", "Xenophobe (1991) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f032b2f2d8323404a6b4541f92dd1825", "", "", "Many Blue Bars and Text Demo 3 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f047df70d3d08e331122cd2de61d6af8", "Dave Neuman", "", "Space Battle (NTSC)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f04ee80011d95798006378643650aaa7", "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel", "CX26114", "Pigs in Space (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0536303f49006806bac3aec15738336", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (4 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0541d2f7cda5ec7bab6d62b6128b823", "Atari, Paul Donaldson", "", "Bionic Breakthrough (1984) (Atari) (Prototype)", "Uses Mindlink Controller (left only)", "Prototype", "", "", "", "", "", "", "MINDLINK", "", "", "", "", "", "", "", "" }, { "f060826626aac9e0d8cda0282f4b7fc3", "Atari, David Crane - Sears", "CX2605 - 6-99822, 49-75109", "Outlaw (1978) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0631c6675033428238408885d7e4fde", "Paul Slocum", "", "Test Cart (2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f066bea7ab0a37b83c83c924a87c5b67", "", "", "Air Raiders (1982) (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0a6e99f5875891246c3dbecbf2d2cea", "Atari, James Andreasen - Sears", "CX2654 - 49-75141", "Haunted House (1982) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0b7db930ca0e548c41a97160b9f6275", "Atari, Larry Wagner, Bob Whitehead - Sears", "CX2645 - 49-75181", "Video Chess (1979) (Atari)", "AKA Computer Chess", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0cacae1d1b79ee92f0dc035f42e0560", "", "", "Boring Donkey Kong (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0d393dbf4164a688b2346770c9bbd12", "", "", "Racquetball (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f0daaa966199ef2b49403e9a29d12c50", "", "", "Mr. Postman (Unknown)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f0e0addc07971561ab80d9abe1b8d333", "Imagic, Rob Fulop", "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04", "Demon Attack (1982) (Imagic)", "AKA Death from Above", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f10e3f45fb01416c87e5835ab270b53a", "Video Game Cartridge - Ariola", "TP-607", "Ski Run (Ariola) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1127ade54037236e75a133b1dfc389d", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (Preview) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f11cfab087fcbd930ab8b0becc5b2e5a", "Canal 3 - Intellivision", "", "River Raid (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f12afbffa080dd3b2801dd14d4837cf6", "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira", "CX26110", "Crystal Castles (01-04-1984) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f137211537438b1fce3d811baef25457", "", "", "Incoming (02-10-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1489e27a4539a0c6c8529262f9f7e18", "Champ Games", "CG-01-P", "Lady Bug (PAL60)", "", "Homebrew", "", "", "", "A", "", "", "", "", "", "", "PAL60", "", "", "YES", "" }, { "f14d5e96ec3380aef57a4b70132c6677", "Goliath - Hot Shot", "83-414", "Pac Kong (1983) (Goliath) (PAL)", "AKA Inca Gold", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1554569321dc933c87981cf5c239c43", "Atari - Glenn Axworthy", "CX26129", "Midnight Magic (1986) (Atari)", "AKA Pinball Wizard", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f16c709df0a6c52f47ff52b9d95b7d8d", "Atari, Alan Miller - Sears", "CX2662 - 6-99811", "Hangman (1978) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1929bb9b5db22d98dd992aa3fe72920", "", "", "Cube Conquest (Improved Interlace) (Billy Eno) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f19aba18f86e415812480ad2be221425", "Chris Larkin", "", "Solaris Trainer (2002) (Chris Larkin) (Hack)", "Hack of Solaris", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1a0a23e6464d954e3a9579c4ccd01c8", "20th Century Fox, Douglas 'Dallas North' Neubauer", "11006", "Alien (1982) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f1ae6305fa33a948e36deb0ef12af852", "Andreas Dietrich", "", "Donkey Kong VCS (2017) (1.0)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f1b2ea568b3e156e3f2849dac83591f6", "", "", "Sprite Demo (1997) (Bob Colbert) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1b7edff81ceef5af7ae1fa76c8590fc", "Atari, Richard Maurer", "CX2632, CX2632P", "Space Invaders (1980) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1beca5a198cf08190487e5c27b8e540", "", "", "Fu Kung! (V0.16) (2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1e375d921858467166e53bcec05803f", "Jeffry Johnston", "", "Radial Pong - Version 3 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f1eeeccc4bba6999345a2575ae96508e", "Video Gems", "VG-03", "Steeplechase (1983) (Video Gems) (PAL)", "", "", "", "", "", "A", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f1fe06ebe2900eac4cdd17799389a102", "Atari, Jim Huether", "CX26163P", "Sky Diver (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f20675c8b98518367b9f5b8ee6f7c8ea", "Atari", "CX26163P", "Stampede (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f20bd756f3990e06c492f53cd0168e68", "", "", "Skeleton+ (03-05-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f21813aa050437f0dbc8479864acec6d", "", "", "Sneak 'n Peek (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f240ba9f8092d2e8a4c7d82c554bf509", "Quelle", "463.860 7", "Strahlen der Teufelsvoegel (1983) (Quelle) (PAL)", "AKA Atlantis", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f280976d69d6e27a48506bd6bad11dcd", "Atari, Larry Kaplan", "CX2664, CX2664P", "Brain Games (1978) (Atari) (PAL)", "Uses Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "f283cc294ece520c2badf9da20cfc025", "Atari - CCW, Christopher H. Omarzu", "CX26104", "Big Bird's Egg Catch (1983) (Atari) (PAL)", "Uses Kids/Keypad Controllers", "Rare", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "f28c07767b3e90a2689ade5b5e305874", "Canal 3 - Intellivision", "C 3014", "Keystone Kapers (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f2d40c70cf3e1d03bc112796315888d9", "Atari - CCW, Michael Callahan, Preston Stuart", "CX26103", "Alpha Beam with Ernie (1983) (Atari) (PAL)", "Uses Keypad Controllers", "Rare", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "f2d4d6187903cac2d5ea8ed90dad120d", "Digimax", "", "River Raid II (Digimax)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f2e4fb2d3600c0f76d05864e658cc57b", "", "", "Marble Craze (Kernel) (17-02-2002) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f2f2cb35fdef063c966c1f5481050ea2", "", "", "Ram It (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f2f59629d7341c97644405daeac08845", "Jone Yuan Telephonic Enterprise Co", "", "Bobby Is Going Home (Jone Yuan)", "2600 Screen Search Console", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f303630a2d7316787aecd67fff6b2e33", "AtariAge - Fred Quimby", "", "Gingerbread Man (Fred Quimby)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3213a8a702b0646d2eaf9ee0722b51c", "Atari, Carol Shaw - Sears", "CX2618 - 49-75123", "3-D Tic-Tac-Toe (1980) (Atari) (4K)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f33f1d0f7819c74148dacb48cbf1c597", "Retroactive", "", "Qb (2.00) (Retroactive) (Stella)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f344ac1279152157d63e64aa39479599", "Tigervision", "7-012", "Espial (1984) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f34dd3b8156aaf113cb621b2e51d90b8", "Joe Grand", "", "SCSIcide Pre-release 5 (Joe Grand)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f34f08e5eb96e500e851a80be3277a56", "Atari, Brad Stewart - Sears", "CX2622 - 6-99813, 49-75107", "Breakout (1978) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 60", "", "", "", "", "" }, { "f367e58667a30e7482175809e3cec4d4", "ZiMAG - Emag - Vidco", "708-111 - GN-040", "Cosmic Corridor (1983) (ZiMAG)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "f38358cd8f5ecfedffd5aca1aa939f18", "Universal Gamex Corporation, Alan Roberts", "1005", "X-Man (1983) (Universal) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "f39e4bc99845edd8621b0f3c7b8c4fd9", "AtariAge", "", "Toyshop Trouble (AtariAge)", "F8 Emulator Release", "", "", "", "", "", "", "", "", "PADDLES", "", "", "", "32", "", "", "" }, { "f3c431930e035a457fe370ed4d230659", "", "", "Crackpots (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3cd0f886201d1376f3abab2df53b1b9", "Commavid, Ben Burch", "CM-010", "Rush Hour (1983) (Commavid) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3dfae774f3bd005a026e29894db40d3", "Otto Versand", "649635", "See Saw (Double-Game Package) (1983) (Otto Versand) (PAL)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3f5f72bfdd67f3d0e45d097e11b8091", "Sears Tele-Games, Marilyn Churchill, Matthew L. Hubbard", "CX2647 - 49-75142", "Submarine Commander (1982) (Sears)", "AKA Seawolf 3", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f3f92aad3a335f0a1ead24a0214ff446", "", "", "Spectrum Color Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f4204fc92d17ed4cb567c40361ad58f1", "Inky", "", "Beanie Baby Bash (Inky) (Hack)", "Hack of Beany Bopper", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f4469178cd8998cb437fa110a228eaca", "Digitel", "", "Frostbite (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f45644ff82b533a781a1ee50f2e95f3c", "", "", "Overhead Adventure Demo 6 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f457674cef449cfd85f21db2b4f631a7", "U.S. Games Corporation - JWDA, Todd Marshall, Wes Trager, Henry Will IV", "VC1004", "Commando Raid (1982) (U.S. Games)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f473f99e47d4026a7a571184922ebf04", "Philip R. Frey", "", "Donkey Claus (Philip R. Frey) (Hack)", "Hack of Donkey Kong", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f48022230bb774a7f22184b48a3385af", "Atari, Rob Fulop - Sears", "CX2633 - 49-75119", "Night Driver (1980) (Atari) (4K)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 65", "", "", "", "YES", "" }, { "f48735115ec302ba8bb2d2f3a442e814", "", "", "Dishaster (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f49a34f1fdd7dc147cbf96ce2ce71b76", "", "", "Qb (Special Edition) (PAL) (Retroactive)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f4ab6bd5f80d8988141edde4c84b23b5", "Atari, Alan Miller", "CX2624, CX2624P", "Basketball (1978) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f4b8a47a95b61895e671c3ec86ffd461", "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart", "PB5540", "Star Wars - The Arcade Game (01-03-1984) (Parker Bros) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f4c2e50b01dff99bddbe037b3489511c", "", "", "Hypnotic (V0.04) (2001) (Inkling) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f4c6621f1a0b4d27081123c08d7d1497", "CCE", "C-838", "Immies & Aggies (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f4cf6881b65c424095dc25dc987f151f", "", "", "128 in 1 Game Select ROM (Unknown)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f4dabd5bcc603e8464a478208037d423", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (08-21-1984) (Coleco) (Prototype)", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f526d0c519f5001adb1fc7948bfbb3ce", "Mythicon, Bill Bryner, Bruce de Graaf", "MA1003", "Star Fox (1983) (Mythicon)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f52f40299fd238c6ffd9e6107050dc76", "Activision, Bob Whitehead - Ariola", "EAG-011, PAG-011 - 711 011-715", "Stampede (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f539e32bf6ce39c8ca47cb0cdd2c5cb8", "Control Video Corporation", "", "GameLine Master Module ROM (1983) (Control Video)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f542b5d0193a3959b54f3c4c803ba242", "Atari, Tom Rudadahl - Sears", "CX2634 - 49-75121", "Golf (1980) (Atari) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f5445b52999e229e3789c39e7ee99947", "Atari, Jim Huether", "CX26163P", "Flag Capture (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f5a2f6efa33a3e5541bc680e9dc31d5b", "Suntek", "SS-022", "Motocross (Suntek) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f5a3e051730d45fea518f2e8b926565b", "Robby", "", "Keystone Kapers (Robby)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f5aa6bd10f662199c42e43863a30106c", "", "", "Music Kit (V1.0) - Song Player (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f5d103a9ae36d1d4ee7eef657b75d2b3", "Starpath Corporation, Stephen H. Landrum", "9 AR-4105", "Official Frogger, The (Preview) (1983) (Starpath)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "", "" }, { "f613aad84d2163d6b197b220bfec1b7e", "", "", "X-Doom V.27 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f661f129644f338b13d9f4510d816c03", "Atari, David Crane", "CX26163P", "Outlaw (32 in 1) (1988) (Atari) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f6676e3fe901eb8515fc7ae310302c3c", "Activision, David Crane", "AG-008", "Laser Blast (1981) (Activision) (8K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f67181b3a01b9c9159840b15449b87b0", "Atari, Nick 'Sandy Maiwald' Turner", "CX2665", "Frog Pond (08-27-1982) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f687ec4b69611a7f78bd69b8a567937a", "Activision, Alan Miller - Ariola", "EAZ-028 - 711 028-725", "Robot Tank (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f69a39b215852a0c2764d2a923c1e463", "", "", "Move a Blue Blob Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f69bb58b815a6bdca548fa4d5e0d5a75", "Atari, Larry Kaplan", "CX26163P", "Bowling (32 in 1) (1988) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f69d4fcf76942fcd9bdf3fd8fde790fb", "CCE", "", "Aquaventure (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f6a282374441012b01714e19699fc62a", "ZiMAG - Emag - Vidco", "710-111 - GN-010", "I Want My Mommy (1983) (ZiMAG)", "", "", "", "", "", "", "", "", "", "", "", "", "", "30", "", "YES", "" }, { "f6a9ea814d15b85bffe980c927df606b", "", "", "Missile Command (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f6b5ebb65cbb2981af4d546c470629d7", "Coleco - Individeo, Ed Temple", "", "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype) [a]", "Adventures in the Park", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f6c13e816e58c8c62f82b2c8b91a2d67", "", "", "Scrolling Playfield 2 (Junkosoft) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f6d512bef1bf253dc935d0e13c3d1462", "", "", "Slot Racers (Unknown) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f6daebc0424fa0f8d9aaf26c86df50f4", "Brian Watson", "", "Color Tweaker (V1.0) (2001) (B. Watson)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f6efa00ae99aaf33e427b674bcfd834d", "", "", "2600 Digital Clock (Demo 3) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f6f1b27efc247a0e8d473ddb4269ff9e", "Quelle", "429.663 8", "Schnapp die Apfeldiebe (1983) (Quelle) (PAL)", "AKA Plaque Attack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f70e3f3bb2d19ec2aaec8f78dc43744f", "Jone Yuan Telephonic Enterprise Co", "", "Pooyan (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "215", "", "" }, { "f714a223954c28eccf459295517dcae6", "", "", "Big - Move This Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f724d3dd2471ed4cf5f191dbb724b69f", "Atari, Jerome Domurat, Howard Scott Warshaw", "CX2659", "Raiders of the Lost Ark (1982) (Atari)", "Console ports are swapped", "", "", "", "", "", "", "YES", "", "", "", "", "", "", "", "", "" }, { "f736864442164b29235e8872013180cd", "Telegames - VSS", "6057 A227", "Quest for Quintana Roo (1988) (Telegames) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f73d2d0eff548e8fc66996f27acf2b4b", "CCE", "C-813", "Pitfall (1983) (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7424985bac41067502b4a05b64cb75a", "Activision, Steve Cartwright", "AX-027", "Plaque Attack (1983) (Activision)", "Genesis controller (B is fire up, C is fire down)", "Hack of Plaque Attack", "", "", "", "", "", "", "GENESIS", "GENESIS", "", "", "", "", "", "", "" }, { "f74ad642552385c3daa203a2a6fc2291", "Eckhard Stolberg", "", "Cubis (1997) (Eckhard Stolberg)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "20", "", "", "" }, { "f750b5d613796963acecab1690f554ae", "Manuel Polik", "", "Gunfight 2600 (MP)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f75872946e82ad74d48eae5bc28f5f0e", "Sears Tele-Games, Jim Huether", "CX2614 - 49-75126", "Steeplechase (04-15-1980) (Sears) (Prototype)", "Uses the Paddle Controllers", "Prototype", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "", "", "", "", "", "" }, { "f777444fc21a5925e066b68b1d350575", "", "", "Marble Craze (Kernel Works) (Paul Slocum)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f77f5fc3893da5d00198e4cd96544aad", "Canal 3 - Intellivision", "", "Stampede (Canal 3)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7856e324bc56f45b9c8e6ff062ec033", "Atari, Jerome Domurat, Michael Sierchio", "CX2667", "RealSports Soccer (1983) (Atari) [no opening tune]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f78c125b5da483c41e51522947d6c4ce", "", "", "Sound Paddle V1 (Dennis Caswell & Jim Nitchals) (PD)", "Uses the Paddle Controllers", "", "", "", "", "", "", "YES", "PADDLES", "", "", "01", "", "", "", "", "" }, { "f7a138eed69665b5cd1bfa796a550b01", "Tigervision - Teldec", "7-012 - 3.60016 VC", "Espial (1984) (Tigervision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7a651972d78f9ba485b14690452d4be", "Paul Slocum", "", "Homestar Runner Demo #2 (2004-03-29)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "f7af41a87533524d9a478575b0d873d0", "Quelle", "495.663 7", "Spiderman (1983) (Quelle) (PAL)", "AKA Spider-Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7d6592dcb773c81c278140ed4d01669", "Activision, David Crane, Dan Kitchen", "EAG-108-04, EAZ-108-04B", "Ghostbusters (1985) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7e07080ed8396b68f2e5788a5c245e2", "Video Game Cartridge - Ariola", "TP-617", "Farmyard Fun (Ariola)", "AKA Play Farm", "", "", "", "", "", "", "", "", "", "", "", "", "", "215", "", "" }, { "f7f50d9c9d28bcc9f7d3075668b7ac89", "Activision, David Crane - Ariola", "EAG-008, PAG-008, EAG-008-04I - 711 008-720", "Laser Blast (1981) (Activision) (PAL) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f7fac15cf54b55c5597718b6742dbec2", "Spiceware", "SW-01", "Medieval Mayhem (NTSC)", "", "Homebrew", "STEREO", "", "", "", "", "", "PADDLES", "PADDLES", "", "AUTO 55", "", "", "", "", "" }, { "f802fa61011dd9eb6f80b271bac479d0", "Suntek", "SS-023", "Mole Hunter (Suntek) (PAL)", "AKA Topy", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f80cf77164079d774b9b0fae33dffca9", "", "", "Fu Kung! (V0.15) (Negative Version) (05-02-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8240e62d8c0a64a61e19388414e3104", "Activision, Steve Cartwright", "AX-013", "Barnstorming (1982) (Activision)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f825c538481f9a7a46d1e9bc06200aaf", "Atari, Richard Maurer - Sears", "CX2635 - 49-75157", "Maze Craze (1980) (Atari)", "AKA A Game of Cops 'n Robbers", "", "", "", "", "", "", "", "", "", "", "", "NTSC", "", "", "", "" }, { "f844f4c6f3baaaf5322657442d6f29eb", "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner", "CX26111", "Snoopy and the Red Baron (1983) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f847fb8dba6c6d66d13724dbe5d95c4d", "Absolute Entertainment, David Crane", "AG-042-02, AG-042-04", "Skate Boardin' (1987) (Absolute)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8582bc6ca7046adb8e18164e8cecdbc", "", "", "Panda Chase (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "256", "", "" }, { "f8648d0c6ad1266434f6c485ff69ec40", "CCE", "", "Oink! (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8811d45a9935cca90c62f924712f8e6", "Jone Yuan Telephonic Enterprise Co", "", "Chopper Command (Jone Yuan) (Hack)", "2600 Screen Search Console", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8b2a6a4d73ebff10d805a9b59041986", "Activision, Larry Kaplan - Ariola", "EAX-006, PAX-006 - 771 006-720", "Bridge (1980) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8bfd99163d2c4ec688357786e6fba28", "", "", "Eckhard Stolberg's Scrolling Text Demo 2 (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8c1c4a41303bd40b0d6c81bfaf8573b", "HES", "773-891", "2 Pak Special - Dungeon Master, Creature Strike (1992) (HES) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f8ff34b53d86f55bd52d7a520af6d1dc", "", "", "Big Dig (04-04-2003) (CT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "f90b5da189f24d7e1a2117d8c8abc952", "Atari, David Crane - Sears", "CX2653 - 6-99823, 49-75111", "Slot Machine (1979) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f91fb8da3223b79f1c9a07b77ebfa0b2", "Atari, Alan J. Murphy, Nick 'Sandy Maiwald' Turner - Sears", "CX2615 - 49-75140", "Demons to Diamonds (1982) (Atari)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "YES", "10 57", "", "", "", "", "" }, { "f93d7fee92717e161e6763a88a293ffa", "20th Century Fox Video Games - Lazer Micro Systems - Dunhill Electronics, B. Winston Hendrickson, Randall Hyde, Mark V. Rhoads, John Simonds", "11013", "Porky's (1983) (20th Century Fox)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9420173efcb4b9f2b01c2a7b595cca7", "CCE", "", "Laser Blast (CCE) (4K)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f954381f9e0f2009d1ac40dedd777b1a", "Thomas Jentzsch", "", "Robot City (V0.18) (01-09-2002) (TJ)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9655ed51462ecfc690c7b97cec649f9", "Andrew Wallace", "", "Laseresal 2002 (PAL) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f965cc981cbb0822f955641f8d84e774", "Answer Software Corporation - TY Associates", "ASC2001", "Confrontation (1983) (Answer) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "220", "YES", "" }, { "f9660ebed66fee8bdfdf07b4faa22941", "VGS", "", "Vanguard (VGS)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9677b2ec8728a703eb710274474613d", "Atari, Ian Shepard", "CX2604, CX2604P", "Space War (1978) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f97dee1aa2629911f30f225ca31789d4", "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, Jim Jacob", "5005002", "Out of Control (1983) (Avalon Hill)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "216", "", "" }, { "f98d2276d4a25b286135566255aea9d0", "Digitel", "", "Name This Game (1983) (Digitel)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f98d869f287d2ce4f8fb36e0686929d9", "", "", "Skeleton+ (17-04-2003) (Eric Ball) (NTSC)", "", "", "STEREO", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f992a39b46aa48188fab12ad3809ae4a", "", "", "Sky Jinks (Unknown) (PAL) (Hack)", "", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9967369943209b4788d4e92cefc0795", "Atari", "CX26163P", "Fishing (32 in 1) (1988) (Atari) (PAL) (4K)", "AKA Fishing Derby", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9cef637ea8e905a10e324e582dd39c2", "CCE", "", "Private Eye (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9d51a4e5f8b48f68770c89ffd495ed1", "Atari, Tod Frye, Mimi Nyden", "CX2657", "SwordQuest - FireWorld (1982) (Atari)", "AKA Adventure II, SwordQuest II - FireWorld", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9da42f91a1c5cfa344d2ff440c6f8d4", "ZUT", "", "Pac Invaders (ZUT)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9de91d868d6ebfb0076af9063d7195e", "", "", "Maze Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "f9e99596345a84358bc5d1fbe877134b", "Activision, Larry Kaplan, David Crane - Ariola", "EAG-010, PAG-010 - 711 010-720", "Kaboom! (1981) (Activision) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "01 50", "", "", "", "", "" }, { "fa0570561aa80896f0ead05c46351389", "Tigervision", "7-008", "Miner 2049er (1983) (Tigervision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "28", "214", "", "" }, { "fa1b060fd8e0bca0c2a097dcffce93d3", "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams", "CX26101", "Oscar's Trash Race (1984) (Atari)", "Uses the Keypad Controllers", "", "", "", "", "", "", "", "KEYBOARD", "KEYBOARD", "", "", "", "", "", "", "" }, { "fa2be8125c3c60ab83e1c0fe56922fcb", "Camelot - DSD, Michael Doherty, Clyde Hager - Johnson & Johnson", "", "Tooth Protectors (1983) (Camelot)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "fa3de71841c0841db6a741884a6b6b2f", "", "", "Warring Worms (17-02-2002) (Billy Eno)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa4404fabc094e3a31fcd7b559cdd029", "Atari, Alan J. Murphy, Robert C. Polaro", "CX26100", "Bugs Bunny (1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa529ec88eca679f6d5fd0ccb2120e46", "", "", "20 Sprites at Once Demo 1 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa6fe97a10efb9e74c0b5a816e6e1958", "ZiMAG - Emag - Vidco", "707-111 - GN-030", "Tanks But No Tanks (1983) (ZiMAG)", "AKA Phantom Tank", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa73f3c77ba76763e00e12d5458b6c5d", "Probe 2000, Roger Booth, Todd Marshall, Robbin Daniels, Jim Wickstead", "3152VC", "Pursuit of the Pink Panther (Probe) (Prototype)", "AKA Adventures of the Pink Panther", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa7ce62e7fd77e02b3e2198d70742f80", "Atari, Peter C. Niday", "CX26108", "Donald Duck's Speedboat (04-18-1983) (Atari) (Prototype) (PAL)", "AKA Donald Duck's Regatta", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa7e11a3dbea4365975cd2f094e61d25", "Tim Snider", "", "Mystery Science Theater 2600 (1999) (Tim Snider) (Hack)", "Hack of Megamania", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fa98d48cd609c9babc819e0a1bd8d598", "AtariAge (Chris Walton)", "", "Juno First (2009) (PAL60)", "AtariVox supported", "Homebrew", "", "", "", "", "", "", "", "ATARIVOX", "", "", "PAL60", "", "", "YES", "" }, { "fabca526d57de46768b392f758f1a008", "", "", "Laseresal 2600 (16-12-2001) (Andrew Wallace) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fac28963307b6e85082ccd77c88325e7", "CCE", "", "Berzerk (CCE)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fadb89f9b23beb4d43a7895c532757e2", "Galaga Games", "", "River Raid (1984) (Galaga Games) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fae0b86934a7c5a362281dffebdb43a0", "Retroactive", "", "Qb (2.07) (Retroactive) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "faebcb2ef1f3831b2fc1dbd39d36517c", "Atari, Jerome Domurat, Steve Woita", "CX2696", "Asterix (1984) (Atari) (PAL)", "AKA Taz", "Extremely Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "faed2ef6b44894f8c83f2b50891c35c6", "CCE", "", "Super Baseball (CCE)", "AKA RealSports Baseball", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "faffd84f3a8eceee2fa5ea5b0a3e6678", "Suntek", "SS-025", "Spectracube Invasion (Suntek) (PAL)", "AKA Immies & Aggies", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb09ee4ccd47ae74a3c314f0d8a40344", "", "", "Titans (SnailSoft)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb0c32ef7af5b45486db663510094be8", "", "", "Demo Image Series #15 - Three Marios (NTSC) (Non-Interleave) (06-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb0e84cee4c108d24253bcb7e382cffd", "", "", "Interleaved ChronoColour Demo (SECAM) (05-03-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb27afe896e7c928089307b32e5642ee", "M Network - APh Technological Consulting, Jeff Ronne, Brett Stutz - INTV", "MT5662", "TRON - Deadly Discs (1983) (M Network)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb4ca865abc02d66e39651bd9ade140a", "Arcadia Corporation, Brian McGhie", "AR-4104", "Rabbit Transit (1983) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb531febf8e155328ec0cd39ef77a122", "", "", "Worm War I (208 in 1) (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "fb5c8af97bd8ffe88323656f462645a7", "", "", "Interlace Demo (Glenn Saunders)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "fb833ed50c865a9a505a125fc9d79a7e", "ITT Family Games", "", "Pumuckl I (1983) (ITT Family Games) (PAL)", "AKA Panda Chase", "", "", "", "", "", "", "", "", "", "", "", "", "", "220", "", "" }, { "fb884ffd89013331a6f01ae3f6abd214", "Activision, David Crane", "", "Venetian Blinds Demo (1982) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb88c400d602fe759ae74ef1716ee84e", "20th Century Fox Video Games, Bill Aspromonte", "11031", "Crash Dive (1983) (20th Century Fox)", "AKA Voyage to the Bottom of the Sea", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb91da78455d9b1606913fbf8c859772", "", "", "Split Screen (Ballblazer) Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fb91dfc36cddaa54b09924ae8fd96199", "Parker Brothers, Mark Lesser", "PB5590", "Frogger II (1984) (Parker Bros) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "fbac6476e7b2b20d246202af81662c88", "Starpath Corporation, Stephen H. Landrum", "AR-4400", "Dragonstomper (Preview) (1982) (Starpath) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fbb0151ea2108e33b2dbaae14a1831dd", "Thomas Jentzsch", "", "Robot Tank TV (Thomas Jentzsch) (Hack)", "Uses two simultaneous Joystick Controllers, Hack of Robot Tank", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fbb4f3debf48dc961b559384467f2057", "Digitel", "", "River Raid III (1985) (Digitel)", "AKA River Raid", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fbd6102e17a5c02c6e1911381b7203f9", "", "", "Star Fire - Warping!! (10-04-2003) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fbe554aa8f759226d251ba6b64a9cce4", "Atari - GCC, Mike Feinstein, Brad Rice", "CX2681, CX2681P", "Battlezone (1983) (Atari) (PAL)", "", "Uncommon", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fbfebee9c14694719e3eda4854dc42ee", "Jake Patterson", "", "Baubles 3 (Jake Patterson) (PD)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fc2104dd2dadf9a6176c1c1c8f87ced9", "Coleco - Woodside Design Associates, Harley H. Puthuff Jr.", "2663", "Time Pilot (1983) (Coleco)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fc2233fc116faef0d3c31541717ca2db", "Atari, Tod Frye", "CX2646", "Pac-Man (1982) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fc24a94d4371c69bc58f5245ada43c44", "Atari - Axlon, Steve DeFrisco", "CX26170", "Secret Quest (1989) (Atari)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fc6052438f339aea373bbc999433388a", "Atari, David Crane", "CX2653P", "Slot Machine (1979) (Atari) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fc668a2251dd79cbd903d4fa0e558f96", "", "", "Thrust (V1.1) (2000) (TJ) [a1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fc92d74f073a44bc6e46a3b3fa8256a2", "", "", "Megademo (19xx) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fc9c1652fe3a2cade6188f4d3692481f", "Andrew Davies", "", "Andrew Davies early notBoulderDash demo (NTSC)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "fca4a5be1251927027f2c24774a02160", "Activision, John Van Ryzin", "AZ-036-04", "H.E.R.O. (1984) (Activision)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fcbbd0a407d3ff7bf857b8a399280ea1", "ZiMAG - Emag - Vidco", "GN-070", "Mysterious Thief, A (1983) (ZiMAG) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "fcbdf405f0fc2027b0ea45bb5af94c1a", "Amiga - Video Soft, Michael K. Glass, Jerry Lawson", "", "3-D Ghost Attack (1983) (Amiga) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fcea12625c071ddc49f4e409f4038c60", "Fabrizio Zavagli", "", "Balls! (16-09-2002) (Fabrizio Zavagli)", "", "Homebrew", "", "", "", "", "", "", "", "", "", "", "", "", "", "YES", "" }, { "fcf8e306f6615f74feba5cb25550038c", "", "", "Blue Dot Demo (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd0e5148162e8ec6719445d559f018a9", "Activision, Steve Cartwright - Ariola", "EAX-022, EAX-022-04I - 711 022-720", "Seaquest (1983) (Activision) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd10915633aea4f9cd8b518a25d62b55", "Atari, John Dunn", "CX2631, CX2631P", "Superman (1979) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd16949913aaab5beaefed73bf2ca67c", "Atari - GCC, John Allred, Mike Feinstein", "CX2688", "Jungle Hunt (02-03-1983) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd4f5536fd80f35c64d365df85873418", "Atari - Bobco, Robert C. Polaro", "CX26140", "Desert Falcon (1987) (Atari)", "AKA Nile Flyer, Sphinx", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd6e507b5df68beeeddeaf696b6828fa", "", "", "Boxing (Unknown) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd7464edaa8cc264b97ba0d13e7f0678", "HES", "771-333", "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd78f186bdff83fbad7f97cb583812fe", "Amiga - Video Soft", "3125", "Surf's Up (1983) (Amiga) (Prototype) [a2]", "Uses the Joyboard controller", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd8b4ee0d57605b35e236e814f706ff1", "Atari - GCC, Mike Feinstein, John Mracek", "CX2673, CX2673P", "Phoenix (1982) (Atari) (PAL) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fd9b321cee5fbb32c39ba3ca5d9ec7cf", "Jeffry Johnston", "", "Radial Pong - Version 5 (Jeffry Johnston) (PD)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fdd4995a50395db14f518f63c2d63438", "", "", "Oh No! (Version 3) (18-01-2003) (AD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fde42e39710e75e9e4d4d75440f8e4e5", "", "", "Coke Zero (v1.0) (PAL)", "", "", "", "", "", "", "", "", "", "", "", "", "", "35", "", "", "" }, { "fdf0de38517e0cf7f0885f98ccc95836", "Arcadia Corporation, Dennis Caswell", "AR-4200", "Escape from the Mindmaster (2 of 4) (1982) (Arcadia)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fdf6680b2b1e8054293a39700a765692", "", "", "Alpha Demo - The Beta Demo 2 (2000) (MP)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fe0b7f27e3ad50bbf9ff468ee56d553d", "", "", "Lines Demo (Eckhard Stolberg) (PAL) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fe0bc4bb92c1c4de7d5706aaa8d8c10d", "", "", "Sprite Demo 2 (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fe3b461d4c8b179fe68bc77760294c25", "Atari, Joe Decuir", "CX2621, CX2621P", "Video Olympics (1977) (Atari) (PAL) (4K)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "", "", "", "", "", "" }, { "fe67087f9c22655ce519616fc6c6ef4d", "Atari - Zip Technology, Randy Bowker, Bruce Williams", "CX26142", "Crack'ed (11-28-1988) (Atari) (Prototype)", "", "Prototype", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fe6abc0f63e31e2646c9c600926b5b7f", "Atari", "CX26137", "4 in 1 (02-19-1987) (Atari) (Prototype)", "Home Run, Canyon Bomber, Sky Diver, Night Driver", "Prototype", "", "4IN1", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fe870018332a0221eb59fb18b0c6bccc", "", "", "Incoming (08-11-2002) (Ben Larson) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fe9ae625d924b54c9f8a14ac9a0f6c6d", "BG Dodson", "", "High Bid! (BG Dodson) (Hack)", "Hack of Pepsi Invaders", "Hack", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "feba8686fd0376015258d1152923958a", "", "", "Super Circus (Unknown) (PAL)", "AKA Circus Atari", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fec0c2e2ab0588ed20c750b58cf3baa3", "Activision - Cheshire Engineering, David Rolfe, Larry Zwick", "EAZ-037-04, EAZ-037-04I", "Beamrider (1984) (Activision) (PAL)", "", "Rare", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "fece458a8023a809a5006867feca40e8", "", "", "SCSIcide (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "feec54aac911887940b47fe8c9f80b11", "Atari, Rob Fulop", "CX2633, CX2633P", "Night Driver (1980) (Atari) (PAL)", "Uses the Paddle Controllers (left only)", "", "", "", "", "", "", "", "PADDLES", "", "", "AUTO 65", "", "", "", "YES", "" }, { "feedcc20bc3ca34851cd5d9e38aa2ca6", "Atari, David Crane - Sears", "CX2607 - 6-99828, 49-75115", "Canyon Bomber (1979) (Atari)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXDR", "", "YES", "10", "", "", "", "", "" }, { "ff3bd0c684f7144aeaa18758d8281a78", "Atari, Bob Whitehead", "CX2651", "Blackjack (1977) (Atari) (PAL)", "Uses the Paddle Controllers", "Rare", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "" }, { "ff5a9e340d96df6f5a5b6eb038e923bd", "", "", "Space Shuttle (1983) (Activision) [t1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ff7627207e8aa03730c35c735a82c26c", "Atari, Bob Whitehead", "CX26163P", "Blackjack (32 in 1) (1988) (Atari) (PAL)", "Uses the Paddle Controllers", "", "", "", "", "", "", "", "PADDLES_IAXIS", "", "", "", "", "", "", "", "" }, { "ff86fc8ffa717bb095e8471638c1c31c", "Arcadia Corporation, Dennis Caswell", "AR-4302", "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia) (PAL)", "Uses Paddle Controllers", "", "", "", "", "", "", "", "PADDLES", "PADDLES", "", "01 56", "", "", "", "", "" }, { "ff87d58125ae517eb7b09a0475a1ccdc", "", "", "SCSIcide (Score Hack 1) (24-02-2001) (Joe Grand) (PD)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ffb1cd548563158ce33f9d10268187e7", "Erik Eid", "", "Euchre (Beta) (NTSC) (12-09-2002) (Erik Eid)", "", "New Release", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ffc0ff4305dd46b4b459885bd1818e2e", "Barry Laws Jr.", "", "Star Wars - The Battle of Alderaan (Star Strike Hack)", "Hack of Star Strike (Mattel)", "New Release (Hack)", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ffdc0eb3543404eb4c353fbdddfa33b6", "CCE", "C-827", "Chopper Command (1983) (CCE) [a]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ffe51989ba6da2c6ae5a12d277862e16", "Atari - Sears", "CX2627 - 6-99841", "Human Cannonball (1979) (Atari) (4K)", "AKA Cannon Man", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" }, { "ffebb0070689b9d322687edd9c0a2bae", "", "", "Spitfire Attack (1983) (Milton Bradley) [h1]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" } }; #endif stella-5.1.1/src/emucore/Device.hxx000066400000000000000000000074551324334165500172010ustar00rootroot00000000000000//============================================================================ // // MM MM 6666 555555 0000 2222 // MMMM MMMM 66 66 55 00 00 22 22 // MM MMM MM 66 55 00 00 22 // MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator" // MM MM 66 66 55 00 00 22 // MM MM 66 66 55 55 00 00 22 // MM MM 6666 5555 0000 222222 // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DEVICE_HXX #define DEVICE_HXX class System; #include "Console.hxx" #include "Serializable.hxx" #include "bspf.hxx" /** Abstract base class for devices which can be attached to a 6502 based system. @author Bradford W. Mott */ class Device : public Serializable { public: Device() : mySystem(nullptr) { } virtual ~Device() = default; public: /** Reset device to its power-on state. *DO NOT* call this method until the device has been attached to the System. In fact, it should never be necessary to call this method directly at all. */ virtual void reset() = 0; /** Notification method invoked by the system when the console type has changed. It may be necessary to override this method for devices that want to know about console changes. @param timing Enum representing the new console type */ virtual void consoleChanged(ConsoleTiming timing) { } /** Install device in the specified system. Invoked by the system when the device is attached to it. @param system The system the device should install itself in */ virtual void install(System& system) = 0; /** Save the current state of this device to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ virtual bool save(Serializer& out) const override = 0; /** Load the current state of this device from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ virtual bool load(Serializer& in) override = 0; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ virtual string name() const override = 0; public: /** Get the byte at the specified address @return The byte at the specified address */ virtual uInt8 peek(uInt16 address) { return 0; } /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ virtual bool poke(uInt16 address, uInt8 value) { return false; } /** Query the given address for its disassembly flags @param address The address to modify */ virtual uInt8 getAccessFlags(uInt16 address) const { return 0; } /** Change the given address type to use the given disassembly flags @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ virtual void setAccessFlags(uInt16 address, uInt8 flags) { } protected: /// Pointer to the system the device is installed in or the null pointer System* mySystem; private: // Following constructors and assignment operators not supported Device(const Device&) = delete; Device(Device&&) = delete; Device& operator=(const Device&) = delete; Device& operator=(Device&&) = delete; }; #endif stella-5.1.1/src/emucore/Driving.cxx000066400000000000000000000124571324334165500173750ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Event.hxx" #include "System.hxx" #include "Driving.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Driving::Driving(Jack jack, const Event& event, const System& system) : Controller(jack, event, system, Controller::Driving), myCounter(0), myGrayIndex(0), myLastYaxis(0), myControlID(-1), myControlIDX(-1), myControlIDY(-1) { if(myJack == Left) { myCCWEvent = Event::JoystickZeroLeft; myCWEvent = Event::JoystickZeroRight; myFireEvent = Event::JoystickZeroFire; myXAxisValue = Event::SALeftAxis0Value; myYAxisValue = Event::SALeftAxis1Value; } else { myCCWEvent = Event::JoystickOneLeft; myCWEvent = Event::JoystickOneRight; myFireEvent = Event::JoystickOneFire; myXAxisValue = Event::SARightAxis0Value; myYAxisValue = Event::SARightAxis1Value; } // Digital pins 3 and 4 are not connected myDigitalPinState[Three] = myDigitalPinState[Four] = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Driving::update() { // Make sure direct gray codes from Stelladaptor stay in sync with // simulated gray codes generated by PC keyboard or PC joystick myCounter = (myGrayIndex << 2) | (myCounter & 3); // Digital events (from keyboard or joystick hats & buttons) myDigitalPinState[Six] = (myEvent.get(myFireEvent) == 0); int d_axis = myEvent.get(myXAxisValue); if(myEvent.get(myCCWEvent) != 0 || d_axis < -16384) myCounter--; else if(myEvent.get(myCWEvent) != 0 || d_axis > 16384) myCounter++; // Mouse motion and button events if(myControlID > -1) { int m_axis = myEvent.get(Event::MouseAxisXValue); if(m_axis < -2) myCounter--; else if(m_axis > 2) myCounter++; if(myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)) myDigitalPinState[Six] = false; } else { // Test for 'untied' mouse axis mode, where each axis is potentially // mapped to a separate driving controller if(myControlIDX > -1) { int m_axis = myEvent.get(Event::MouseAxisXValue); if(m_axis < -2) myCounter--; else if(m_axis > 2) myCounter++; if(myEvent.get(Event::MouseButtonLeftValue)) myDigitalPinState[Six] = false; } if(myControlIDY > -1) { int m_axis = myEvent.get(Event::MouseAxisYValue); if(m_axis < -2) myCounter--; else if(m_axis > 2) myCounter++; if(myEvent.get(Event::MouseButtonRightValue)) myDigitalPinState[Six] = false; } } // Only consider the lower-most bits (corresponding to pins 1 & 2) myCounter &= 0x0f; myGrayIndex = myCounter >> 2; // Stelladaptor is the only controller that should set this int yaxis = myEvent.get(myYAxisValue); // Only overwrite gray code when Stelladaptor input has changed // (that means real changes, not just analog signal jitter) if((yaxis < (myLastYaxis - 1024)) || (yaxis > (myLastYaxis + 1024))) { myLastYaxis = yaxis; if(yaxis <= -16384-4096) myGrayIndex = 3; // up else if(yaxis > 16384+4096) myGrayIndex = 1; // down else if(yaxis >= 16384-4096) myGrayIndex = 2; // up + down else if(yaxis < 16384-4096) myGrayIndex = 0; // no movement } // Gray codes for rotation static constexpr uInt8 graytable[] = { 0x03, 0x01, 0x00, 0x02 }; // Determine which bits are set uInt8 gray = graytable[myGrayIndex]; myDigitalPinState[One] = (gray & 0x1) != 0; myDigitalPinState[Two] = (gray & 0x2) != 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Driving::setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { // When the mouse emulates a single driving controller, only the X-axis is // used, and both mouse buttons map to the same 'fire' event if(xtype == Controller::Driving && ytype == Controller::Driving && xid == yid) { myControlID = ((myJack == Left && xid == 0) || (myJack == Right && xid == 1) ) ? xid : -1; myControlIDX = myControlIDY = -1; } else { // Otherwise, each axis can be mapped to a separate driving controller, // and the buttons map to separate (corresponding) controllers myControlID = -1; if(myJack == Left) { myControlIDX = (xtype == Controller::Driving && xid == 0) ? 0 : -1; myControlIDY = (ytype == Controller::Driving && yid == 0) ? 0 : -1; } else // myJack == Right { myControlIDX = (xtype == Controller::Driving && xid == 1) ? 1 : -1; myControlIDY = (ytype == Controller::Driving && yid == 1) ? 1 : -1; } } return true; } stella-5.1.1/src/emucore/Driving.hxx000066400000000000000000000062321324334165500173740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DRIVING_HXX #define DRIVING_HXX #include "Control.hxx" #include "Event.hxx" /** The standard Atari 2600 Indy 500 driving controller. @author Bradford W. Mott */ class Driving : public Controller { public: /** Create a new Indy 500 driving controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ Driving(Jack jack, const Event& event, const System& system); virtual ~Driving() = default; public: /** Update the entire digital and analog pin state according to the events currently set. */ void update() override; /** Determines how this controller will treat values received from the X/Y axis and left/right buttons of the mouse. Since not all controllers use the mouse the same way (or at all), it's up to the specific class to decide how to use this data. In the current implementation, the left button is tied to the X axis, and the right one tied to the Y axis. @param xtype The controller to use for x-axis data @param xid The controller ID to use for x-axis data (-1 for no id) @param ytype The controller to use for y-axis data @param yid The controller ID to use for y-axis data (-1 for no id) @return Whether the controller supports using the mouse */ bool setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; private: // Counter to iterate through the gray codes uInt32 myCounter; // Index into the gray code table uInt32 myGrayIndex; // Y axis value from last yaxis event that was used to generate a new // gray code int myLastYaxis; // Pre-compute the events we care about based on given port // This will eliminate test for left or right port in update() Event::Type myCWEvent, myCCWEvent, myFireEvent, myXAxisValue, myYAxisValue; // Controller to emulate in normal mouse axis mode int myControlID; // Controllers to emulate in 'specific' mouse axis mode int myControlIDX, myControlIDY; private: // Following constructors and assignment operators not supported Driving() = delete; Driving(const Driving&) = delete; Driving(Driving&&) = delete; Driving& operator=(const Driving&) = delete; Driving& operator=(Driving&&) = delete; }; #endif stella-5.1.1/src/emucore/Event.hxx000066400000000000000000000104051324334165500170500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef EVENT_HXX #define EVENT_HXX #include "bspf.hxx" #include "StellaKeys.hxx" /** @author Bradford W. Mott */ class Event { public: /** Enumeration of all possible events in Stella, including both console and controller event types as well as events that aren't technically part of the emulation core */ enum Type { NoType, ConsoleOn, ConsoleOff, ConsoleColor, ConsoleBlackWhite, ConsoleLeftDiffA, ConsoleLeftDiffB, ConsoleRightDiffA, ConsoleRightDiffB, ConsoleSelect, ConsoleReset, ConsoleLeftDiffToggle, ConsoleRightDiffToggle, ConsoleColorToggle, Console7800Pause, JoystickZeroUp, JoystickZeroDown, JoystickZeroLeft, JoystickZeroRight, JoystickZeroFire, JoystickZeroFire5, JoystickZeroFire9, JoystickOneUp, JoystickOneDown, JoystickOneLeft, JoystickOneRight, JoystickOneFire, JoystickOneFire5, JoystickOneFire9, PaddleZeroDecrease, PaddleZeroIncrease, PaddleZeroAnalog, PaddleZeroFire, PaddleOneDecrease, PaddleOneIncrease, PaddleOneAnalog, PaddleOneFire, PaddleTwoDecrease, PaddleTwoIncrease, PaddleTwoAnalog, PaddleTwoFire, PaddleThreeDecrease, PaddleThreeIncrease, PaddleThreeAnalog, PaddleThreeFire, KeyboardZero1, KeyboardZero2, KeyboardZero3, KeyboardZero4, KeyboardZero5, KeyboardZero6, KeyboardZero7, KeyboardZero8, KeyboardZero9, KeyboardZeroStar, KeyboardZero0, KeyboardZeroPound, KeyboardOne1, KeyboardOne2, KeyboardOne3, KeyboardOne4, KeyboardOne5, KeyboardOne6, KeyboardOne7, KeyboardOne8, KeyboardOne9, KeyboardOneStar, KeyboardOne0, KeyboardOnePound, Combo1, Combo2, Combo3, Combo4, Combo5, Combo6, Combo7, Combo8, Combo9, Combo10, Combo11, Combo12, Combo13, Combo14, Combo15, Combo16, SALeftAxis0Value, SALeftAxis1Value, SARightAxis0Value, SARightAxis1Value, MouseAxisXValue, MouseAxisYValue, MouseButtonLeftValue, MouseButtonRightValue, ChangeState, LoadState, SaveState, TakeSnapshot, Quit, PauseMode, OptionsMenuMode, CmdMenuMode, TimeMachineMode, DebuggerMode, LauncherMode, Fry, VolumeDecrease, VolumeIncrease, UIUp, UIDown, UILeft, UIRight, UIHome, UIEnd, UIPgUp, UIPgDown, UISelect, UINavPrev, UINavNext, UIOK, UICancel, UIPrevDir, LastType }; public: /** Create a new event object */ Event() { clear(); } public: /** Get the value associated with the event of the specified type */ Int32 get(Type type) const { return myValues[type]; } /** Set the value associated with the event of the specified type */ void set(Type type, Int32 value) { myValues[type] = value; } /** Clears the event array (resets to initial state) */ void clear() { for(uInt32 i = 0; i < LastType; ++i) myValues[i] = Event::NoType; for(uInt32 i = 0; i < KBDK_LAST; ++i) myKeyTable[i] = false; } /** Get the keytable associated with this event */ const bool* getKeys() const { return myKeyTable; } /** Set the value associated with the event of the specified type */ void setKey(StellaKey key, bool state) { myKeyTable[key] = state; } private: // Array of values associated with each event type Int32 myValues[LastType]; // Array of keyboard key states bool myKeyTable[KBDK_LAST]; private: // Following constructors and assignment operators not supported Event(const Event&) = delete; Event(Event&&) = delete; Event& operator=(const Event&) = delete; Event& operator=(Event&&) = delete; }; #endif stella-5.1.1/src/emucore/EventHandler.cxx000066400000000000000000002334461324334165500203550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #include "bspf.hxx" #include "Base.hxx" #include "CommandMenu.hxx" #include "Console.hxx" #include "DialogContainer.hxx" #include "Event.hxx" #include "FrameBuffer.hxx" #include "TIASurface.hxx" #include "FSNode.hxx" #include "Launcher.hxx" #include "TimeMachine.hxx" #include "Menu.hxx" #include "OSystem.hxx" #include "Joystick.hxx" #include "Paddles.hxx" #include "PointingDevice.hxx" #include "PropsSet.hxx" #include "ListWidget.hxx" #include "ScrollBarWidget.hxx" #include "Settings.hxx" #include "Sound.hxx" #include "StateManager.hxx" #include "Switches.hxx" #include "M6532.hxx" #include "MouseControl.hxx" #include "PNGLibrary.hxx" #include "Version.hxx" #include "EventHandler.hxx" #ifdef CHEATCODE_SUPPORT #include "Cheat.hxx" #include "CheatManager.hxx" #endif #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::EventHandler(OSystem& osystem) : myOSystem(osystem), myOverlay(nullptr), myState(EventHandlerState::NONE), myAllowAllDirectionsFlag(false), myFryingFlag(false), myUseCtrlKeyFlag(true), mySkipMouseMotion(true), myIs7800(false), myAltKeyCounter(0), myContSnapshotInterval(0), myContSnapshotCounter(0) { // Erase the key mapping array for(int i = 0; i < KBDK_LAST; ++i) for(int m = 0; m < kNumModes; ++m) myKeyTable[i][m] = Event::NoType; // Erase the 'combo' array for(int i = 0; i < kComboSize; ++i) for(int j = 0; j < kEventsPerCombo; ++j) myComboTable[i][j] = Event::NoType; // Create joystick handler (to handle all joystick functionality) myJoyHandler = make_unique(osystem); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::~EventHandler() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::initialize() { // Make sure the event/action mappings are correctly set, // and fill the ActionList structure with valid values setKeymap(); setComboMap(); setActionMappings(kEmulationMode); setActionMappings(kMenuMode); myUseCtrlKeyFlag = myOSystem.settings().getBool("ctrlcombo"); Joystick::setDeadZone(myOSystem.settings().getInt("joydeadzone")); Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense")); Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense")); PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense")); // Set quick select delay when typing characters in listwidgets ListWidget::setQuickSelectDelay(myOSystem.settings().getInt("listdelay")); // Set number of lines a mousewheel will scroll ScrollBarWidget::setWheelLines(myOSystem.settings().getInt("mwheel")); // Integer to string conversions (for HEX) use upper or lower-case Common::Base::setHexUppercase(myOSystem.settings().getBool("dbg.uhex")); // Default phosphor blend Properties::setDefault(Display_PPBlend, myOSystem.settings().getString("tv.phosblend")); // Toggle 7800 mode set7800Mode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::reset(EventHandlerState state) { setEventState(state); myOSystem.state().reset(); setContinuousSnapshots(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::addJoystick(StellaJoystick* stick) { #ifdef JOYSTICK_SUPPORT if(!myJoyHandler->add(stick)) return; setActionMappings(kEmulationMode); setActionMappings(kMenuMode); ostringstream buf; buf << "Added joystick " << stick->ID << ":" << endl << " " << stick->about() << endl; myOSystem.logMessage(buf.str(), 1); // We're potentially swapping out an input device behind the back of // the Event system, so we make sure all Stelladaptor-generated events // are reset for(int i = 0; i < 2; ++i) { for(int j = 0; j < 2; ++j) myEvent.set(SA_Axis[i][j], 0); for(int j = 0; j < 4; ++j) myEvent.set(SA_Button[i][j], 0); for(int j = 0; j < 12; ++j) myEvent.set(SA_Key[i][j], 0); } #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::removeJoystick(int id) { #ifdef JOYSTICK_SUPPORT myJoyHandler->remove(id); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::mapStelladaptors(const string& saport) { #ifdef JOYSTICK_SUPPORT myJoyHandler->mapStelladaptors(saport); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::toggleSAPortOrder() { #ifdef JOYSTICK_SUPPORT const string& saport = myOSystem.settings().getString("saport"); if(saport == "lr") { mapStelladaptors("rl"); myOSystem.frameBuffer().showMessage("Stelladaptor ports right/left"); } else { mapStelladaptors("lr"); myOSystem.frameBuffer().showMessage("Stelladaptor ports left/right"); } #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::set7800Mode() { if(myOSystem.hasConsole()) myIs7800 = myOSystem.console().switches().toggle7800Mode(myOSystem.settings()); else myIs7800 = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::poll(uInt64 time) { // Process events from the underlying hardware pollEvent(); // Update controllers and console switches, and in general all other things // related to emulation if(myState == EventHandlerState::EMULATION) { myOSystem.console().riot().update(); // Now check if the StateManager should be saving or loading state // (for rewind and/or movies if(myOSystem.state().mode() != StateManager::Mode::Off) myOSystem.state().update(); #ifdef CHEATCODE_SUPPORT for(auto& cheat: myOSystem.cheat().perFrame()) cheat->evaluate(); #endif // Handle continuous snapshots if(myContSnapshotInterval > 0 && (++myContSnapshotCounter % myContSnapshotInterval == 0)) takeSnapshot(uInt32(time) >> 10); // not quite milliseconds, but close enough } else if(myOverlay) { // Update the current dialog container at regular intervals // Used to implement continuous events myOverlay->updateTime(time); } // Turn off all mouse-related items; if they haven't been taken care of // in the previous ::update() methods, they're now invalid myEvent.set(Event::MouseAxisXValue, 0); myEvent.set(Event::MouseAxisYValue, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleTextEvent(char text) { // Text events are only used in GUI mode if(myOverlay) myOverlay->handleTextEvent(text); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleKeyEvent(StellaKey key, StellaMod mod, bool state) { // Swallow KBDK_TAB under certain conditions // See commments on 'myAltKeyCounter' for more information #ifdef BSPF_UNIX if(myAltKeyCounter > 1 && key == KBDK_TAB) { myAltKeyCounter = false; return; } #endif bool handled = true; // Immediately store the key state myEvent.setKey(key, state); // An attempt to speed up event processing; we quickly check for // Control or Alt/Cmd combos first if(StellaModTest::isAlt(mod) && state) { #ifdef BSPF_MAC_OSX // These keys work in all states if(key == KBDK_Q) { handleEvent(Event::Quit, 1); } else #endif if(key == KBDK_TAB) { // Swallow Alt-Tab, but remember that it happened myAltKeyCounter = 1; return; } else if(key == KBDK_RETURN) { myOSystem.frameBuffer().toggleFullscreen(); } // State rewinding must work in pause mode too else if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) { switch(key) { case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, false); return; case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states enterTimeMachineMenuMode((StellaModTest::isShift(mod) && state) ? 10 : 1, true); return; case KBDK_DOWN: // Alt-down rewinds to start of list enterTimeMachineMenuMode(1000, false); return; case KBDK_UP: // Alt-up rewinds to end of list enterTimeMachineMenuMode(1000, true); return; default: handled = false; break; } } // These only work when in emulation mode if(!handled && myState == EventHandlerState::EMULATION) { handled = true; switch(key) { case KBDK_EQUALS: myOSystem.frameBuffer().changeWindowedVidMode(+1); break; case KBDK_MINUS: myOSystem.frameBuffer().changeWindowedVidMode(-1); break; case KBDK_LEFTBRACKET: myOSystem.sound().adjustVolume(-1); break; case KBDK_RIGHTBRACKET: myOSystem.sound().adjustVolume(+1); break; case KBDK_PAGEUP: // Alt-PageUp increases YStart myOSystem.console().changeYStart(+1); break; case KBDK_PAGEDOWN: // Alt-PageDown decreases YStart myOSystem.console().changeYStart(-1); break; case KBDK_1: // Alt-1 turns off NTSC filtering myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_OFF); break; case KBDK_2: // Alt-2 turns on 'composite' NTSC filtering myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_COMPOSITE); break; case KBDK_3: // Alt-3 turns on 'svideo' NTSC filtering myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_SVIDEO); break; case KBDK_4: // Alt-4 turns on 'rgb' NTSC filtering myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_RGB); break; case KBDK_5: // Alt-5 turns on 'bad' NTSC filtering myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_BAD); break; case KBDK_6: // Alt-6 turns on 'custom' NTSC filtering myOSystem.frameBuffer().tiaSurface().setNTSC(NTSCFilter::PRESET_CUSTOM); break; case KBDK_7: // Alt-7 changes scanline intensity for NTSC filtering if(mod & KBDM_SHIFT) myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(-5); else myOSystem.frameBuffer().tiaSurface().setScanlineIntensity(+5); break; case KBDK_8: // Alt-8 turns toggles scanline interpolation myOSystem.frameBuffer().tiaSurface().toggleScanlineInterpolation(); break; case KBDK_9: // Alt-9 selects various custom adjustables for NTSC filtering if(myOSystem.frameBuffer().tiaSurface().ntscEnabled()) { if(mod & KBDM_SHIFT) myOSystem.frameBuffer().showMessage( myOSystem.frameBuffer().tiaSurface().ntsc().setPreviousAdjustable()); else myOSystem.frameBuffer().showMessage( myOSystem.frameBuffer().tiaSurface().ntsc().setNextAdjustable()); } break; case KBDK_0: // Alt-0 changes custom adjustables for NTSC filtering if(myOSystem.frameBuffer().tiaSurface().ntscEnabled()) { if(mod & KBDM_SHIFT) myOSystem.frameBuffer().showMessage( myOSystem.frameBuffer().tiaSurface().ntsc().decreaseAdjustable()); else myOSystem.frameBuffer().showMessage( myOSystem.frameBuffer().tiaSurface().ntsc().increaseAdjustable()); } break; case KBDK_Z: if(mod & KBDM_SHIFT) myOSystem.console().toggleP0Collision(); else myOSystem.console().toggleP0Bit(); break; case KBDK_X: if(mod & KBDM_SHIFT) myOSystem.console().toggleP1Collision(); else myOSystem.console().toggleP1Bit(); break; case KBDK_C: if(mod & KBDM_SHIFT) myOSystem.console().toggleM0Collision(); else myOSystem.console().toggleM0Bit(); break; case KBDK_V: if(mod & KBDM_SHIFT) myOSystem.console().toggleM1Collision(); else myOSystem.console().toggleM1Bit(); break; case KBDK_B: if(mod & KBDM_SHIFT) myOSystem.console().toggleBLCollision(); else myOSystem.console().toggleBLBit(); break; case KBDK_N: if(mod & KBDM_SHIFT) myOSystem.console().togglePFCollision(); else myOSystem.console().togglePFBit(); break; case KBDK_COMMA: myOSystem.console().toggleFixedColors(); break; case KBDK_PERIOD: if(mod & KBDM_SHIFT) myOSystem.console().toggleCollisions(); else myOSystem.console().toggleBits(); break; case KBDK_I: // Alt-i decreases phosphor blend myOSystem.console().changePhosphor(-1); break; case KBDK_O: // Alt-o increases phosphor blend myOSystem.console().changePhosphor(+1); break; case KBDK_P: // Alt-p toggles phosphor effect myOSystem.console().togglePhosphor(); break; case KBDK_J: // Alt-j toggles scanline jitter myOSystem.console().toggleJitter(); break; case KBDK_L: myOSystem.frameBuffer().toggleFrameStats(); break; case KBDK_T: // Alt-t toggles Time Machine myOSystem.state().toggleTimeMachine(); break; case KBDK_S: if(myContSnapshotInterval == 0) { ostringstream buf; uInt32 interval = myOSystem.settings().getInt("ssinterval"); if(mod & KBDM_SHIFT) { buf << "Enabling snapshots every frame"; interval = 1; } else { buf << "Enabling snapshots in " << interval << " second intervals"; interval *= uInt32(myOSystem.frameRate()); } myOSystem.frameBuffer().showMessage(buf.str()); setContinuousSnapshots(interval); } else { ostringstream buf; buf << "Disabling snapshots, generated " << (myContSnapshotCounter / myContSnapshotInterval) << " files"; myOSystem.frameBuffer().showMessage(buf.str()); setContinuousSnapshots(0); } break; default: handled = false; break; } } else handled = false; } else if(StellaModTest::isControl(mod) && state && myUseCtrlKeyFlag) { // These keys work in all states if(key == KBDK_Q) { handleEvent(Event::Quit, 1); } // These only work when in emulation mode else if(myState == EventHandlerState::EMULATION) { switch(key) { case KBDK_0: // Ctrl-0 switches between mouse control modes if(myMouseControl) myOSystem.frameBuffer().showMessage(myMouseControl->next()); break; case KBDK_1: // Ctrl-1 swaps Stelladaptor/2600-daptor ports toggleSAPortOrder(); break; case KBDK_F: // (Shift) Ctrl-f toggles NTSC/PAL/SECAM mode myOSystem.console().toggleFormat(mod & KBDM_SHIFT ? -1 : 1); break; case KBDK_G: // Ctrl-g (un)grabs mouse if(!myOSystem.frameBuffer().fullScreen()) { myOSystem.frameBuffer().toggleGrabMouse(); myOSystem.frameBuffer().showMessage(myOSystem.frameBuffer().grabMouseEnabled() ? "Grab mouse enabled" : "Grab mouse disabled"); } break; case KBDK_L: // Ctrl-l toggles PAL color-loss effect myOSystem.console().toggleColorLoss(); break; case KBDK_P: // Ctrl-p toggles different palettes myOSystem.console().togglePalette(); break; case KBDK_R: // Ctrl-r reloads the currently loaded ROM myOSystem.reloadConsole(); break; case KBDK_PAGEUP: // Ctrl-PageUp increases Height myOSystem.console().changeHeight(+1); break; case KBDK_PAGEDOWN: // Ctrl-PageDown decreases Height myOSystem.console().changeHeight(-1); break; case KBDK_S: // Ctrl-s saves properties to a file { string filename = myOSystem.baseDir() + myOSystem.console().properties().get(Cartridge_Name) + ".pro"; ofstream out(filename); if(out) { out << myOSystem.console().properties(); myOSystem.frameBuffer().showMessage("Properties saved"); } else myOSystem.frameBuffer().showMessage("Error saving properties"); break; } default: handled = false; break; } } else handled = false; } else handled = false; // Don't pass the key on if we've already taken care of it if(handled) return; // Handle keys which switch eventhandler state // Arrange the logic to take advantage of short-circuit evaluation if(!(StellaModTest::isControl(mod) || StellaModTest::isShift(mod) || StellaModTest::isAlt(mod)) && !state && eventStateChange(myKeyTable[key][kEmulationMode])) return; // Otherwise, let the event handler deal with it switch(myState) { case EventHandlerState::EMULATION: handleEvent(myKeyTable[key][kEmulationMode], state); break; case EventHandlerState::PAUSE: switch(myKeyTable[key][kEmulationMode]) { case Event::TakeSnapshot: case Event::DebuggerMode: handleEvent(myKeyTable[key][kEmulationMode], state); break; default: break; } break; default: if(myOverlay) myOverlay->handleKeyEvent(key, mod, state); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleMouseMotionEvent(int x, int y, int xrel, int yrel) { // Determine which mode we're in, then send the event to the appropriate place if(myState == EventHandlerState::EMULATION) { if(!mySkipMouseMotion) { myEvent.set(Event::MouseAxisXValue, xrel); myEvent.set(Event::MouseAxisYValue, yrel); } mySkipMouseMotion = false; } else if(myOverlay) myOverlay->handleMouseMotionEvent(x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y) { // Determine which mode we're in, then send the event to the appropriate place if(myState == EventHandlerState::EMULATION) { switch(b) { case MouseButton::LEFT: myEvent.set(Event::MouseButtonLeftValue, int(pressed)); break; case MouseButton::RIGHT: myEvent.set(Event::MouseButtonRightValue, int(pressed)); break; default: return; } } else if(myOverlay) myOverlay->handleMouseButtonEvent(b, pressed, x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleJoyEvent(int stick, int button, uInt8 state) { const StellaJoystick* joy = myJoyHandler->joy(stick); if(!joy) return; // Stelladaptors handle buttons differently than regular joysticks switch(joy->type) { case StellaJoystick::JT_REGULAR: // Handle buttons which switch eventhandler state if(state && eventStateChange(joy->btnTable[button][kEmulationMode])) return; // Determine which mode we're in, then send the event to the appropriate place if(myState == EventHandlerState::EMULATION) handleEvent(joy->btnTable[button][kEmulationMode], state); else if(myOverlay) myOverlay->handleJoyEvent(stick, button, state); break; // Regular button // These events don't have to pass through handleEvent, since // they can never be remapped case StellaJoystick::JT_STELLADAPTOR_LEFT: case StellaJoystick::JT_STELLADAPTOR_RIGHT: // The 'type-2' here refers to the fact that 'StellaJoystick::JT_STELLADAPTOR_LEFT' // and 'StellaJoystick::JT_STELLADAPTOR_RIGHT' are at index 2 and 3 in the JoyType // enum; subtracting two gives us Controller 0 and 1 if(button < 2) myEvent.set(SA_Button[joy->type-2][button], state); break; // Stelladaptor button case StellaJoystick::JT_2600DAPTOR_LEFT: case StellaJoystick::JT_2600DAPTOR_RIGHT: // The 'type-4' here refers to the fact that 'StellaJoystick::JT_2600DAPTOR_LEFT' // and 'StellaJoystick::JT_2600DAPTOR_RIGHT' are at index 4 and 5 in the JoyType // enum; subtracting four gives us Controller 0 and 1 if(myState == EventHandlerState::EMULATION) { switch(myOSystem.console().leftController().type()) { case Controller::Keyboard: if(button < 12) myEvent.set(SA_Key[joy->type-4][button], state); break; default: if(button < 4) myEvent.set(SA_Button[joy->type-4][button], state); } switch(myOSystem.console().rightController().type()) { case Controller::Keyboard: if(button < 12) myEvent.set(SA_Key[joy->type-4][button], state); break; default: if(button < 4) myEvent.set(SA_Button[joy->type-4][button], state); } } break; // 2600DAPTOR button default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleJoyAxisEvent(int stick, int axis, int value) { const StellaJoystick* joy = myJoyHandler->joy(stick); if(!joy) return; // Stelladaptors handle axis differently than regular joysticks switch(joy->type) { case StellaJoystick::JT_REGULAR: if(myState == EventHandlerState::EMULATION) { // Every axis event has two associated values, negative and positive Event::Type eventAxisNeg = joy->axisTable[axis][0][kEmulationMode]; Event::Type eventAxisPos = joy->axisTable[axis][1][kEmulationMode]; // Check for analog events, which are handled differently // We'll pass them off as Stelladaptor events, and let the controllers // handle it switch(int(eventAxisNeg)) { case Event::PaddleZeroAnalog: myEvent.set(Event::SALeftAxis0Value, value); break; case Event::PaddleOneAnalog: myEvent.set(Event::SALeftAxis1Value, value); break; case Event::PaddleTwoAnalog: myEvent.set(Event::SARightAxis0Value, value); break; case Event::PaddleThreeAnalog: myEvent.set(Event::SARightAxis1Value, value); break; default: { // Otherwise, we know the event is digital if(value > Joystick::deadzone()) handleEvent(eventAxisPos, 1); else if(value < -Joystick::deadzone()) handleEvent(eventAxisNeg, 1); else { // Treat any deadzone value as zero value = 0; // Now filter out consecutive, similar values // (only pass on the event if the state has changed) if(joy->axisLastValue[axis] != value) { // Turn off both events, since we don't know exactly which one // was previously activated. handleEvent(eventAxisNeg, 0); handleEvent(eventAxisPos, 0); } } joy->axisLastValue[axis] = value; break; } } } else if(myOverlay) { // First, clamp the values to simulate digital input // (the only thing that the underlying code understands) if(value > Joystick::deadzone()) value = 32000; else if(value < -Joystick::deadzone()) value = -32000; else value = 0; // Now filter out consecutive, similar values // (only pass on the event if the state has changed) if(value != joy->axisLastValue[axis]) { myOverlay->handleJoyAxisEvent(stick, axis, value); joy->axisLastValue[axis] = value; } } break; // Regular joystick axis // Since the various controller classes deal with Stelladaptor // devices differently, we send the raw X and Y axis data directly, // and let the controller handle it // These events don't have to pass through handleEvent, since // they can never be remapped case StellaJoystick::JT_STELLADAPTOR_LEFT: case StellaJoystick::JT_STELLADAPTOR_RIGHT: // The 'type-2' here refers to the fact that 'StellaJoystick::JT_STELLADAPTOR_LEFT' // and 'StellaJoystick::JT_STELLADAPTOR_RIGHT' are at index 2 and 3 in the JoyType // enum; subtracting two gives us Controller 0 and 1 if(axis < 2) myEvent.set(SA_Axis[joy->type-2][axis], value); break; // Stelladaptor axis case StellaJoystick::JT_2600DAPTOR_LEFT: case StellaJoystick::JT_2600DAPTOR_RIGHT: // The 'type-4' here refers to the fact that 'StellaJoystick::JT_2600DAPTOR_LEFT' // and 'StellaJoystick::JT_2600DAPTOR_RIGHT' are at index 4 and 5 in the JoyType // enum; subtracting four gives us Controller 0 and 1 if(axis < 2) myEvent.set(SA_Axis[joy->type-4][axis], value); break; // 2600-daptor axis default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleJoyHatEvent(int stick, int hat, int value) { const StellaJoystick* joy = myJoyHandler->joy(stick); if(!joy) return; // Preprocess all hat events, converting to Stella JoyHat type // Generate multiple equivalent hat events representing combined direction // when we get a diagonal hat event if(myState == EventHandlerState::EMULATION) { handleEvent(joy->hatTable[hat][int(JoyHat::UP)][kEmulationMode], value & EVENT_HATUP_M); handleEvent(joy->hatTable[hat][int(JoyHat::RIGHT)][kEmulationMode], value & EVENT_HATRIGHT_M); handleEvent(joy->hatTable[hat][int(JoyHat::DOWN)][kEmulationMode], value & EVENT_HATDOWN_M); handleEvent(joy->hatTable[hat][int(JoyHat::LEFT)][kEmulationMode], value & EVENT_HATLEFT_M); } else if(myOverlay) { if(value == EVENT_HATCENTER_M) myOverlay->handleJoyHatEvent(stick, hat, JoyHat::CENTER); else { if(value & EVENT_HATUP_M) myOverlay->handleJoyHatEvent(stick, hat, JoyHat::UP); if(value & EVENT_HATRIGHT_M) myOverlay->handleJoyHatEvent(stick, hat, JoyHat::RIGHT); if(value & EVENT_HATDOWN_M) myOverlay->handleJoyHatEvent(stick, hat, JoyHat::DOWN); if(value & EVENT_HATLEFT_M) myOverlay->handleJoyHatEvent(stick, hat, JoyHat::LEFT); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleSystemEvent(SystemEvent e, int, int) { switch(e) { case SystemEvent::WINDOW_EXPOSED: myOSystem.frameBuffer().update(); break; case SystemEvent::WINDOW_FOCUS_GAINED: // Used to handle Alt-x key combos; sometimes the key associated with // Alt gets 'stuck' and is passed to the core for processing if(myAltKeyCounter > 0) myAltKeyCounter = 2; break; #if 0 case SystemEvent::WINDOW_MINIMIZED: if(myState == EventHandlerState::EMULATION) enterMenuMode(EventHandlerState::OPTIONSMENU); break; #endif default: // handle other events as testing requires // cerr << "handleSystemEvent: " << e << endl; break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleEvent(Event::Type event, Int32 state) { // Take care of special events that aren't part of the emulation core // or need to be preprocessed before passing them on switch(event) { //////////////////////////////////////////////////////////////////////// // If enabled, make sure 'impossible' joystick directions aren't allowed case Event::JoystickZeroUp: if(!myAllowAllDirectionsFlag && state) myEvent.set(Event::JoystickZeroDown, 0); break; case Event::JoystickZeroDown: if(!myAllowAllDirectionsFlag && state) myEvent.set(Event::JoystickZeroUp, 0); break; case Event::JoystickZeroLeft: if(!myAllowAllDirectionsFlag && state) myEvent.set(Event::JoystickZeroRight, 0); break; case Event::JoystickZeroRight: if(!myAllowAllDirectionsFlag && state) myEvent.set(Event::JoystickZeroLeft, 0); break; case Event::JoystickOneUp: if(!myAllowAllDirectionsFlag && state) myEvent.set(Event::JoystickOneDown, 0); break; case Event::JoystickOneDown: if(!myAllowAllDirectionsFlag && state) myEvent.set(Event::JoystickOneUp, 0); break; case Event::JoystickOneLeft: if(!myAllowAllDirectionsFlag && state) myEvent.set(Event::JoystickOneRight, 0); break; case Event::JoystickOneRight: if(!myAllowAllDirectionsFlag && state) myEvent.set(Event::JoystickOneLeft, 0); break; //////////////////////////////////////////////////////////////////////// case Event::Fry: if(myUseCtrlKeyFlag) myFryingFlag = bool(state); return; case Event::VolumeDecrease: if(state) myOSystem.sound().adjustVolume(-1); return; case Event::VolumeIncrease: if(state) myOSystem.sound().adjustVolume(+1); return; case Event::SaveState: if(state) myOSystem.state().saveState(); return; case Event::ChangeState: if(state) myOSystem.state().changeState(); return; case Event::LoadState: if(state) myOSystem.state().loadState(); return; case Event::TakeSnapshot: if(state) takeSnapshot(); return; case Event::LauncherMode: if((myState == EventHandlerState::EMULATION || myState == EventHandlerState::CMDMENU || myState == EventHandlerState::DEBUGGER) && state) { // Go back to the launcher, or immediately quit if(myOSystem.settings().getBool("exitlauncher") || myOSystem.launcherUsed()) myOSystem.createLauncher(); else handleEvent(Event::Quit, 1); } return; case Event::Quit: if(state) { saveKeyMapping(); saveJoyMapping(); myOSystem.quit(); } return; //////////////////////////////////////////////////////////////////////// // A combo event is simply multiple calls to handleEvent, once for // each event it contains case Event::Combo1: case Event::Combo2: case Event::Combo3: case Event::Combo4: case Event::Combo5: case Event::Combo6: case Event::Combo7: case Event::Combo8: case Event::Combo9: case Event::Combo10: case Event::Combo11: case Event::Combo12: case Event::Combo13: case Event::Combo14: case Event::Combo15: case Event::Combo16: for(int i = 0, combo = event - Event::Combo1; i < kEventsPerCombo; ++i) if(myComboTable[combo][i] != Event::NoType) handleEvent(myComboTable[combo][i], state); return; //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // Events which relate to switches() case Event::ConsoleColor: if(state && !myIs7800) { myEvent.set(Event::ConsoleBlackWhite, 0); myOSystem.frameBuffer().showMessage("Color Mode"); } break; case Event::ConsoleBlackWhite: if(state && !myIs7800) { myEvent.set(Event::ConsoleColor, 0); myOSystem.frameBuffer().showMessage("BW Mode"); } break; case Event::ConsoleColorToggle: if(state && !myIs7800) { if(myOSystem.console().switches().tvColor()) { myEvent.set(Event::ConsoleBlackWhite, 1); myEvent.set(Event::ConsoleColor, 0); myOSystem.frameBuffer().showMessage("BW Mode"); } else { myEvent.set(Event::ConsoleBlackWhite, 0); myEvent.set(Event::ConsoleColor, 1); myOSystem.frameBuffer().showMessage("Color Mode"); } myOSystem.console().switches().update(); } return; case Event::ConsoleLeftDiffA: if(state) { myEvent.set(Event::ConsoleLeftDiffB, 0); myOSystem.frameBuffer().showMessage("Left Difficulty A"); } break; case Event::ConsoleLeftDiffB: if(state) { myEvent.set(Event::ConsoleLeftDiffA, 0); myOSystem.frameBuffer().showMessage("Left Difficulty B"); } break; case Event::ConsoleLeftDiffToggle: if(state) { if(myOSystem.console().switches().leftDifficultyA()) { myEvent.set(Event::ConsoleLeftDiffA, 0); myEvent.set(Event::ConsoleLeftDiffB, 1); myOSystem.frameBuffer().showMessage("Left Difficulty B"); } else { myEvent.set(Event::ConsoleLeftDiffA, 1); myEvent.set(Event::ConsoleLeftDiffB, 0); myOSystem.frameBuffer().showMessage("Left Difficulty A"); } myOSystem.console().switches().update(); } return; case Event::ConsoleRightDiffA: if(state) { myEvent.set(Event::ConsoleRightDiffB, 0); myOSystem.frameBuffer().showMessage("Right Difficulty A"); } break; case Event::ConsoleRightDiffB: if(state) { myEvent.set(Event::ConsoleRightDiffA, 0); myOSystem.frameBuffer().showMessage("Right Difficulty B"); } break; case Event::ConsoleRightDiffToggle: if(state) { if(myOSystem.console().switches().rightDifficultyA()) { myEvent.set(Event::ConsoleRightDiffA, 0); myEvent.set(Event::ConsoleRightDiffB, 1); myOSystem.frameBuffer().showMessage("Right Difficulty B"); } else { myEvent.set(Event::ConsoleRightDiffA, 1); myEvent.set(Event::ConsoleRightDiffB, 0); myOSystem.frameBuffer().showMessage("Right Difficulty A"); } myOSystem.console().switches().update(); } return; //////////////////////////////////////////////////////////////////////// case Event::NoType: // Ignore unmapped events return; default: break; } // Otherwise, pass it to the emulation core myEvent.set(event, state); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::handleConsoleStartupEvents() { bool update = false; if(myOSystem.settings().getBool("holdreset")) { handleEvent(Event::ConsoleReset, 1); update = true; } if(myOSystem.settings().getBool("holdselect")) { handleEvent(Event::ConsoleSelect, 1); update = true; } const string& holdjoy0 = myOSystem.settings().getString("holdjoy0"); update = update || holdjoy0 != ""; if(BSPF::containsIgnoreCase(holdjoy0, "U")) handleEvent(Event::JoystickZeroUp, 1); if(BSPF::containsIgnoreCase(holdjoy0, "D")) handleEvent(Event::JoystickZeroDown, 1); if(BSPF::containsIgnoreCase(holdjoy0, "L")) handleEvent(Event::JoystickZeroLeft, 1); if(BSPF::containsIgnoreCase(holdjoy0, "R")) handleEvent(Event::JoystickZeroRight, 1); if(BSPF::containsIgnoreCase(holdjoy0, "F")) handleEvent(Event::JoystickZeroFire, 1); const string& holdjoy1 = myOSystem.settings().getString("holdjoy1"); update = update || holdjoy1 != ""; if(BSPF::containsIgnoreCase(holdjoy1, "U")) handleEvent(Event::JoystickOneUp, 1); if(BSPF::containsIgnoreCase(holdjoy1, "D")) handleEvent(Event::JoystickOneDown, 1); if(BSPF::containsIgnoreCase(holdjoy1, "L")) handleEvent(Event::JoystickOneLeft, 1); if(BSPF::containsIgnoreCase(holdjoy1, "R")) handleEvent(Event::JoystickOneRight, 1); if(BSPF::containsIgnoreCase(holdjoy1, "F")) handleEvent(Event::JoystickOneFire, 1); if(update) myOSystem.console().riot().update(); #ifdef DEBUGGER_SUPPORT if(myOSystem.settings().getBool("debug")) enterDebugMode(); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::eventStateChange(Event::Type type) { bool handled = true; switch(type) { case Event::PauseMode: if(myState == EventHandlerState::EMULATION) setEventState(EventHandlerState::PAUSE); else if(myState == EventHandlerState::PAUSE) setEventState(EventHandlerState::EMULATION); else handled = false; break; case Event::OptionsMenuMode: if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) enterMenuMode(EventHandlerState::OPTIONSMENU); else handled = false; break; case Event::CmdMenuMode: if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) enterMenuMode(EventHandlerState::CMDMENU); else if(myState == EventHandlerState::CMDMENU) leaveMenuMode(); else handled = false; break; case Event::TimeMachineMode: if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE) enterTimeMachineMenuMode(0, false); else if(myState == EventHandlerState::TIMEMACHINE) leaveMenuMode(); else handled = false; break; case Event::DebuggerMode: if(myState == EventHandlerState::EMULATION || myState == EventHandlerState::PAUSE || myState == EventHandlerState::TIMEMACHINE) enterDebugMode(); else if(myState == EventHandlerState::DEBUGGER) leaveDebugMode(); else handled = false; break; default: handled = false; } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setActionMappings(EventMode mode) { int listsize = 0; ActionList* list = nullptr; switch(mode) { case kEmulationMode: listsize = kEmulActionListSize; list = ourEmulActionList; break; case kMenuMode: listsize = kMenuActionListSize; list = ourMenuActionList; break; default: return; } ostringstream buf; // Fill the ActionList with the current key and joystick mappings for(int i = 0; i < listsize; ++i) { Event::Type event = list[i].event; list[i].key = "None"; string key = ""; for(int j = 0; j < KBDK_LAST; ++j) // key mapping { if(myKeyTable[j][mode] == event) { if(key == "") key = key + nameForKey(StellaKey(j)); else key = key + ", " + nameForKey(StellaKey(j)); } } #ifdef JOYSTICK_SUPPORT for(const auto& st: myJoyHandler->sticks()) { uInt32 stick = st.first; const StellaJoystick* joy = st.second; if(!joy) continue; // Joystick button mapping/labeling for(int button = 0; button < joy->numButtons; ++button) { if(joy->btnTable[button][mode] == event) { buf.str(""); buf << "J" << stick << "/B" << button; if(key == "") key = key + buf.str(); else key = key + ", " + buf.str(); } } // Joystick axis mapping/labeling for(int axis = 0; axis < joy->numAxes; ++axis) { for(int dir = 0; dir < 2; ++dir) { if(joy->axisTable[axis][dir][mode] == event) { buf.str(""); buf << "J" << stick << "/A" << axis; if(eventIsAnalog(event)) { dir = 2; // Immediately exit the inner loop after this iteration buf << "/+|-"; } else if(dir == 0) buf << "/-"; else buf << "/+"; if(key == "") key = key + buf.str(); else key = key + ", " + buf.str(); } } } // Joystick hat mapping/labeling for(int hat = 0; hat < joy->numHats; ++hat) { for(int dir = 0; dir < 4; ++dir) { if(joy->hatTable[hat][dir][mode] == event) { buf.str(""); buf << "J" << stick << "/H" << hat; switch(JoyHat(dir)) { case JoyHat::UP: buf << "/up"; break; case JoyHat::DOWN: buf << "/down"; break; case JoyHat::LEFT: buf << "/left"; break; case JoyHat::RIGHT: buf << "/right"; break; case JoyHat::CENTER: break; } if(key == "") key = key + buf.str(); else key = key + ", " + buf.str(); } } } } #endif // There are some keys which are hardcoded. These should be represented too. string prepend = ""; if(event == Event::Quit) #ifndef BSPF_MAC_OSX prepend = "Ctrl Q"; #else prepend = "Cmd Q"; #endif else if(event == Event::UINavNext) prepend = "TAB"; else if(event == Event::UINavPrev) prepend = "Shift-TAB"; // else if ... if(key == "") key = prepend; else if(prepend != "") key = prepend + ", " + key; if(key != "") list[i].key = key; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setKeymap() { // Since istringstream swallows whitespace, we have to make the // delimiters be spaces string list = myOSystem.settings().getString("keymap"); replace(list.begin(), list.end(), ':', ' '); istringstream buf(list); IntArray map; int value; Event::Type event; // Get event count, which should be the first int in the list buf >> value; event = Event::Type(value); if(event == Event::LastType) while(buf >> value) map.push_back(value); // Only fill the key mapping array if the data is valid if(event == Event::LastType && map.size() == KBDK_LAST * kNumModes) { // Fill the keymap table with events auto e = map.cbegin(); for(int mode = 0; mode < kNumModes; ++mode) for(int i = 0; i < KBDK_LAST; ++i) myKeyTable[i][mode] = Event::Type(*e++); } else { setDefaultKeymap(Event::NoType, kEmulationMode); setDefaultKeymap(Event::NoType, kMenuMode); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setComboMap() { // Since istringstream swallows whitespace, we have to make the // delimiters be spaces string list = myOSystem.settings().getString("combomap"); replace(list.begin(), list.end(), ':', ' '); istringstream buf(list); // Get combo count, which should be the first int in the list // If it isn't, then we treat the entire list as invalid string key; buf >> key; if(atoi(key.c_str()) == kComboSize) { // Fill the combomap table with events for as long as they exist int combocount = 0; while(buf >> key && combocount < kComboSize) { // Each event in a comboevent is separated by a comma replace(key.begin(), key.end(), ',', ' '); istringstream buf2(key); int eventcount = 0; while(buf2 >> key && eventcount < kEventsPerCombo) { myComboTable[combocount][eventcount] = Event::Type(atoi(key.c_str())); ++eventcount; } ++combocount; } } else { // Erase the 'combo' array for(int i = 0; i < kComboSize; ++i) for(int j = 0; j < kEventsPerCombo; ++j) myComboTable[i][j] = Event::NoType; } saveComboMapping(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VariantList EventHandler::joystickDatabase() const { VariantList db; for(const auto& i: myJoyHandler->database()) VarList::push_back(db, i.first, i.second.joy ? i.second.joy->ID : -1); return db; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::removeJoystickFromDatabase(const string& name) { myJoyHandler->remove(name); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addKeyMapping(Event::Type event, EventMode mode, StellaKey key) { // These keys cannot be remapped if(key == KBDK_TAB || eventIsAnalog(event)) return false; else { myKeyTable[key][mode] = event; setActionMappings(mode); return true; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addJoyAxisMapping(Event::Type event, EventMode mode, int stick, int axis, int value, bool updateMenus) { #ifdef JOYSTICK_SUPPORT const StellaJoystick* joy = myJoyHandler->joy(stick); if(joy) { if(axis >= 0 && axis < joy->numAxes && event < Event::LastType) { // This confusing code is because each axis has two associated values, // but analog events only affect one of the axis. if(eventIsAnalog(event)) joy->axisTable[axis][0][mode] = joy->axisTable[axis][1][mode] = event; else { // Otherwise, turn off the analog event(s) for this axis if(eventIsAnalog(joy->axisTable[axis][0][mode])) joy->axisTable[axis][0][mode] = Event::NoType; if(eventIsAnalog(joy->axisTable[axis][1][mode])) joy->axisTable[axis][1][mode] = Event::NoType; joy->axisTable[axis][(value > 0)][mode] = event; } if(updateMenus) setActionMappings(mode); return true; } } #endif return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addJoyButtonMapping(Event::Type event, EventMode mode, int stick, int button, bool updateMenus) { #ifdef JOYSTICK_SUPPORT const StellaJoystick* joy = myJoyHandler->joy(stick); if(joy) { if(button >= 0 && button < joy->numButtons && event < Event::LastType) { joy->btnTable[button][mode] = event; if(updateMenus) setActionMappings(mode); return true; } } #endif return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::addJoyHatMapping(Event::Type event, EventMode mode, int stick, int hat, JoyHat value, bool updateMenus) { #ifdef JOYSTICK_SUPPORT const StellaJoystick* joy = myJoyHandler->joy(stick); if(joy) { if(hat >= 0 && hat < joy->numHats && event < Event::LastType && value != JoyHat::CENTER) { joy->hatTable[hat][int(value)][mode] = event; if(updateMenus) setActionMappings(mode); return true; } } #endif return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::eraseMapping(Event::Type event, EventMode mode) { // Erase the KeyEvent arrays for(int i = 0; i < KBDK_LAST; ++i) if(myKeyTable[i][mode] == event && i != KBDK_TAB) myKeyTable[i][mode] = Event::NoType; #ifdef JOYSTICK_SUPPORT // Erase the joystick mapping arrays myJoyHandler->eraseMapping(event, mode); #endif setActionMappings(mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setDefaultMapping(Event::Type event, EventMode mode) { setDefaultKeymap(event, mode); setDefaultJoymap(event, mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setDefaultKeymap(Event::Type event, EventMode mode) { // If event is 'NoType', erase and reset all mappings // Otherwise, only reset the given event bool eraseAll = (event == Event::NoType); if(eraseAll) { // Erase all mappings for(int i = 0; i < KBDK_LAST; ++i) myKeyTable[i][mode] = Event::NoType; } auto setDefaultKey = [&](StellaKey key, Event::Type k_event) { if(eraseAll || k_event == event) myKeyTable[key][mode] = k_event; }; switch(mode) { case kEmulationMode: setDefaultKey( KBDK_1, Event::KeyboardZero1 ); setDefaultKey( KBDK_2, Event::KeyboardZero2 ); setDefaultKey( KBDK_3, Event::KeyboardZero3 ); setDefaultKey( KBDK_Q, Event::KeyboardZero4 ); setDefaultKey( KBDK_W, Event::KeyboardZero5 ); setDefaultKey( KBDK_E, Event::KeyboardZero6 ); setDefaultKey( KBDK_A, Event::KeyboardZero7 ); setDefaultKey( KBDK_S, Event::KeyboardZero8 ); setDefaultKey( KBDK_D, Event::KeyboardZero9 ); setDefaultKey( KBDK_Z, Event::KeyboardZeroStar ); setDefaultKey( KBDK_X, Event::KeyboardZero0 ); setDefaultKey( KBDK_C, Event::KeyboardZeroPound ); setDefaultKey( KBDK_8, Event::KeyboardOne1 ); setDefaultKey( KBDK_9, Event::KeyboardOne2 ); setDefaultKey( KBDK_0, Event::KeyboardOne3 ); setDefaultKey( KBDK_I, Event::KeyboardOne4 ); setDefaultKey( KBDK_O, Event::KeyboardOne5 ); setDefaultKey( KBDK_P, Event::KeyboardOne6 ); setDefaultKey( KBDK_K, Event::KeyboardOne7 ); setDefaultKey( KBDK_L, Event::KeyboardOne8 ); setDefaultKey( KBDK_SEMICOLON, Event::KeyboardOne9 ); setDefaultKey( KBDK_COMMA, Event::KeyboardOneStar ); setDefaultKey( KBDK_PERIOD, Event::KeyboardOne0 ); setDefaultKey( KBDK_SLASH, Event::KeyboardOnePound ); setDefaultKey( KBDK_UP, Event::JoystickZeroUp ); setDefaultKey( KBDK_DOWN, Event::JoystickZeroDown ); setDefaultKey( KBDK_LEFT, Event::JoystickZeroLeft ); setDefaultKey( KBDK_RIGHT, Event::JoystickZeroRight ); setDefaultKey( KBDK_SPACE, Event::JoystickZeroFire ); setDefaultKey( KBDK_LCTRL, Event::JoystickZeroFire ); setDefaultKey( KBDK_4, Event::JoystickZeroFire5 ); setDefaultKey( KBDK_5, Event::JoystickZeroFire9 ); setDefaultKey( KBDK_Y, Event::JoystickOneUp ); setDefaultKey( KBDK_H, Event::JoystickOneDown ); setDefaultKey( KBDK_G, Event::JoystickOneLeft ); setDefaultKey( KBDK_J, Event::JoystickOneRight ); setDefaultKey( KBDK_F, Event::JoystickOneFire ); setDefaultKey( KBDK_6, Event::JoystickOneFire5 ); setDefaultKey( KBDK_7, Event::JoystickOneFire9 ); setDefaultKey( KBDK_F1, Event::ConsoleSelect ); setDefaultKey( KBDK_F2, Event::ConsoleReset ); setDefaultKey( KBDK_F3, Event::ConsoleColor ); setDefaultKey( KBDK_F4, Event::ConsoleBlackWhite ); setDefaultKey( KBDK_F5, Event::ConsoleLeftDiffA ); setDefaultKey( KBDK_F6, Event::ConsoleLeftDiffB ); setDefaultKey( KBDK_F7, Event::ConsoleRightDiffA ); setDefaultKey( KBDK_F8, Event::ConsoleRightDiffB ); setDefaultKey( KBDK_F9, Event::SaveState ); setDefaultKey( KBDK_F10, Event::ChangeState ); setDefaultKey( KBDK_F11, Event::LoadState ); setDefaultKey( KBDK_F12, Event::TakeSnapshot ); setDefaultKey( KBDK_BACKSPACE, Event::Fry ); setDefaultKey( KBDK_PAUSE, Event::PauseMode ); setDefaultKey( KBDK_TAB, Event::OptionsMenuMode ); setDefaultKey( KBDK_BACKSLASH, Event::CmdMenuMode ); setDefaultKey( KBDK_T, Event::TimeMachineMode ); setDefaultKey( KBDK_GRAVE, Event::DebuggerMode ); setDefaultKey( KBDK_ESCAPE, Event::LauncherMode ); break; case kMenuMode: setDefaultKey( KBDK_UP, Event::UIUp ); setDefaultKey( KBDK_DOWN, Event::UIDown ); setDefaultKey( KBDK_LEFT, Event::UILeft ); setDefaultKey( KBDK_RIGHT, Event::UIRight ); setDefaultKey( KBDK_HOME, Event::UIHome ); setDefaultKey( KBDK_END, Event::UIEnd ); setDefaultKey( KBDK_PAGEUP, Event::UIPgUp ); setDefaultKey( KBDK_PAGEDOWN, Event::UIPgDown ); setDefaultKey( KBDK_RETURN, Event::UISelect ); setDefaultKey( KBDK_ESCAPE, Event::UICancel ); setDefaultKey( KBDK_BACKSPACE, Event::UIPrevDir ); break; default: return; } setActionMappings(mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setDefaultJoymap(Event::Type event, EventMode mode) { myJoyHandler->setDefaultMapping(event, mode); setActionMappings(mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::saveKeyMapping() { // Iterate through the keymap table and create a colon-separated list // Prepend the event count, so we can check it on next load ostringstream keybuf; keybuf << Event::LastType; for(int mode = 0; mode < kNumModes; ++mode) for(int i = 0; i < KBDK_LAST; ++i) keybuf << ":" << myKeyTable[i][mode]; myOSystem.settings().setValue("keymap", keybuf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::saveJoyMapping() { myJoyHandler->saveMapping(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::saveComboMapping() { // Iterate through the combomap table and create a colon-separated list // For each combo event, create a comma-separated list of its events // Prepend the event count, so we can check it on next load ostringstream buf; buf << kComboSize; for(int i = 0; i < kComboSize; ++i) { buf << ":" << myComboTable[i][0]; for(int j = 1; j < kEventsPerCombo; ++j) buf << "," << myComboTable[i][j]; } myOSystem.settings().setValue("combomap", buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline bool EventHandler::eventIsAnalog(Event::Type event) const { switch(event) { case Event::PaddleZeroAnalog: case Event::PaddleOneAnalog: case Event::PaddleTwoAnalog: case Event::PaddleThreeAnalog: return true; default: return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StringList EventHandler::getActionList(EventMode mode) const { StringList l; switch(mode) { case kEmulationMode: for(uInt32 i = 0; i < kEmulActionListSize; ++i) l.push_back(EventHandler::ourEmulActionList[i].action); break; case kMenuMode: for(uInt32 i = 0; i < kMenuActionListSize; ++i) l.push_back(EventHandler::ourMenuActionList[i].action); break; default: break; } return l; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VariantList EventHandler::getComboList(EventMode /**/) const { // For now, this only works in emulation mode VariantList l; ostringstream buf; VarList::push_back(l, "None", "-1"); for(uInt32 i = 0; i < kEmulActionListSize; ++i) { if(EventHandler::ourEmulActionList[i].allow_combo) { buf << i; VarList::push_back(l, EventHandler::ourEmulActionList[i].action, buf.str()); buf.str(""); } } return l; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StringList EventHandler::getComboListForEvent(Event::Type event) const { StringList l; ostringstream buf; if(event >= Event::Combo1 && event <= Event::Combo16) { int combo = event - Event::Combo1; for(uInt32 i = 0; i < kEventsPerCombo; ++i) { Event::Type e = myComboTable[combo][i]; for(uInt32 j = 0; j < kEmulActionListSize; ++j) { if(EventHandler::ourEmulActionList[j].event == e && EventHandler::ourEmulActionList[j].allow_combo) { buf << j; l.push_back(buf.str()); buf.str(""); } } // Make sure entries are 1-to-1, using '-1' to indicate Event::NoType if(i == l.size()) l.push_back("-1"); } } return l; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setComboListForEvent(Event::Type event, const StringList& events) { if(event >= Event::Combo1 && event <= Event::Combo16) { assert(events.size() == 8); int combo = event - Event::Combo1; for(int i = 0; i < 8; ++i) { int idx = atoi(events[i].c_str()); if(idx >=0 && idx < kEmulActionListSize) myComboTable[combo][i] = EventHandler::ourEmulActionList[idx].event; else myComboTable[combo][i] = Event::NoType; } saveComboMapping(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Event::Type EventHandler::eventAtIndex(int idx, EventMode mode) const { switch(mode) { case kEmulationMode: if(idx < 0 || idx >= kEmulActionListSize) return Event::NoType; else return ourEmulActionList[idx].event; case kMenuMode: if(idx < 0 || idx >= kMenuActionListSize) return Event::NoType; else return ourMenuActionList[idx].event; default: return Event::NoType; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::actionAtIndex(int idx, EventMode mode) const { switch(mode) { case kEmulationMode: if(idx < 0 || idx >= kEmulActionListSize) return EmptyString; else return ourEmulActionList[idx].action; case kMenuMode: if(idx < 0 || idx >= kMenuActionListSize) return EmptyString; else return ourMenuActionList[idx].action; default: return EmptyString; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::keyAtIndex(int idx, EventMode mode) const { switch(mode) { case kEmulationMode: if(idx < 0 || idx >= kEmulActionListSize) return EmptyString; else return ourEmulActionList[idx].key; case kMenuMode: if(idx < 0 || idx >= kMenuActionListSize) return EmptyString; else return ourMenuActionList[idx].key; default: return EmptyString; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::takeSnapshot(uInt32 number) { // Figure out the correct snapshot name string filename; bool showmessage = number == 0; string sspath = myOSystem.snapshotSaveDir() + (myOSystem.settings().getString("snapname") != "int" ? myOSystem.romFile().getNameWithExt("") : myOSystem.console().properties().get(Cartridge_Name)); // Check whether we want multiple snapshots created if(number > 0) { ostringstream buf; buf << sspath << "_" << std::hex << std::setw(8) << std::setfill('0') << number << ".png"; filename = buf.str(); } else if(!myOSystem.settings().getBool("sssingle")) { // Determine if the file already exists, checking each successive filename // until one doesn't exist filename = sspath + ".png"; FilesystemNode node(filename); if(node.exists()) { ostringstream buf; for(uInt32 i = 1; ;++i) { buf.str(""); buf << sspath << "_" << i << ".png"; FilesystemNode next(buf.str()); if(!next.exists()) break; } filename = buf.str(); } } else filename = sspath + ".png"; // Some text fields to add to the PNG snapshot VariantList comments; ostringstream version; version << "Stella " << STELLA_VERSION << " (Build " << STELLA_BUILD << ") [" << BSPF::ARCH << "]"; VarList::push_back(comments, "Software", version.str()); VarList::push_back(comments, "ROM Name", myOSystem.console().properties().get(Cartridge_Name)); VarList::push_back(comments, "ROM MD5", myOSystem.console().properties().get(Cartridge_MD5)); VarList::push_back(comments, "TV Effects", myOSystem.frameBuffer().tiaSurface().effectsInfo()); // Now create a PNG snapshot if(myOSystem.settings().getBool("ss1x")) { string message = "Snapshot saved"; try { GUI::Rect rect; const FBSurface& surface = myOSystem.frameBuffer().tiaSurface().baseSurface(rect); myOSystem.png().saveImage(filename, surface, rect, comments); } catch(const runtime_error& e) { message = e.what(); } if(showmessage) myOSystem.frameBuffer().showMessage(message); } else { // Make sure we have a 'clean' image, with no onscreen messages myOSystem.frameBuffer().enableMessages(false); myOSystem.frameBuffer().tiaSurface().reRender(); string message = "Snapshot saved"; try { myOSystem.png().saveImage(filename, comments); } catch(const runtime_error& e) { message = e.what(); } // Re-enable old messages myOSystem.frameBuffer().enableMessages(true); if(showmessage) myOSystem.frameBuffer().showMessage(message); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::controllerIsAnalog(Controller::Jack jack) const { const Controller& controller = jack == Controller::Left ? myOSystem.console().leftController() : myOSystem.console().rightController(); switch(controller.type()) { case Controller::Paddles: case Controller::Driving: case Controller::AmigaMouse: case Controller::AtariMouse: case Controller::TrakBall: case Controller::MindLink: return true; default: return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setMouseControllerMode(const string& enable) { if(myOSystem.hasConsole()) { bool usemouse = false; if(BSPF::equalsIgnoreCase(enable, "always")) usemouse = true; else if(BSPF::equalsIgnoreCase(enable, "never")) usemouse = false; else // 'analog' { if(controllerIsAnalog(Controller::Left) || controllerIsAnalog(Controller::Right)) usemouse = true; } const string& control = usemouse ? myOSystem.console().properties().get(Controller_MouseAxis) : "none"; myMouseControl = make_unique(myOSystem.console(), control); myMouseControl->next(); // set first available mode } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setContinuousSnapshots(uInt32 interval) { myContSnapshotInterval = interval; myContSnapshotCounter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::enterMenuMode(EventHandlerState state) { setEventState(state); myOverlay->reStack(); myOSystem.sound().mute(true); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::leaveMenuMode() { setEventState(EventHandlerState::EMULATION); myOSystem.sound().mute(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::enterDebugMode() { #ifdef DEBUGGER_SUPPORT if(myState == EventHandlerState::DEBUGGER || !myOSystem.hasConsole()) return false; // Make sure debugger starts in a consistent state // This absolutely *has* to come before we actually change to debugger // mode, since it takes care of locking the debugger state, which will // probably be modified below myOSystem.debugger().setStartState(); setEventState(EventHandlerState::DEBUGGER); FBInitStatus fbstatus = myOSystem.createFrameBuffer(); if(fbstatus != FBInitStatus::Success) { myOSystem.debugger().setQuitState(); setEventState(EventHandlerState::EMULATION); if(fbstatus == FBInitStatus::FailTooLarge) myOSystem.frameBuffer().showMessage("Debugger window too large for screen", MessagePosition::BottomCenter, true); return false; } myOverlay->reStack(); myOSystem.sound().mute(true); #else myOSystem.frameBuffer().showMessage("Debugger support not included", MessagePosition::BottomCenter, true); #endif return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::leaveDebugMode() { #ifdef DEBUGGER_SUPPORT // paranoia: this should never happen: if(myState != EventHandlerState::DEBUGGER) return; // Make sure debugger quits in a consistent state myOSystem.debugger().setQuitState(); setEventState(EventHandlerState::EMULATION); myOSystem.createFrameBuffer(); myOSystem.sound().mute(false); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::enterTimeMachineMenuMode(uInt32 numWinds, bool unwind) { // add one extra state if we are in Time Machine mode // TODO: maybe remove this state if we leave the menu at this new state myOSystem.state().addExtraState("enter Time Machine dialog"); // force new state if(numWinds) myOSystem.state().windStates(numWinds, unwind); // TODO: display last wind message (numWinds != 0) in time machine dialog enterMenuMode(EventHandlerState::TIMEMACHINE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::setEventState(EventHandlerState state) { myState = state; // Normally, the usage of Control key is determined by 'ctrlcombo' // For certain ROMs it may be forced off, whatever the setting myUseCtrlKeyFlag = myOSystem.settings().getBool("ctrlcombo"); // Only enable text input in GUI modes, since in emulation mode the // keyboard acts as one large joystick with many (single) buttons switch(myState) { case EventHandlerState::EMULATION: myOverlay = nullptr; myOSystem.sound().mute(false); enableTextEvents(false); if(myOSystem.console().leftController().type() == Controller::CompuMate) myUseCtrlKeyFlag = false; break; case EventHandlerState::PAUSE: myOverlay = nullptr; myOSystem.sound().mute(true); enableTextEvents(false); break; case EventHandlerState::OPTIONSMENU: myOverlay = &myOSystem.menu(); enableTextEvents(true); break; case EventHandlerState::CMDMENU: myOverlay = &myOSystem.commandMenu(); enableTextEvents(true); break; case EventHandlerState::TIMEMACHINE: myOSystem.timeMachine().requestResize(); myOverlay = &myOSystem.timeMachine(); enableTextEvents(true); break; case EventHandlerState::LAUNCHER: myOverlay = &myOSystem.launcher(); enableTextEvents(true); myEvent.clear(); break; case EventHandlerState::DEBUGGER: #ifdef DEBUGGER_SUPPORT myOverlay = &myOSystem.debugger(); enableTextEvents(true); #endif break; case EventHandlerState::NONE: myOverlay = nullptr; break; } // Inform various subsystems about the new state myOSystem.stateChanged(myState); myOSystem.frameBuffer().stateChanged(myState); myOSystem.frameBuffer().setCursorState(); if(myOSystem.hasConsole()) myOSystem.console().stateChanged(myState); // Sometimes an extraneous mouse motion event is generated // after a state change, which should be supressed mySkipMouseMotion = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::ActionList EventHandler::ourEmulActionList[kEmulActionListSize] = { { Event::ConsoleSelect, "Select", "", true }, { Event::ConsoleReset, "Reset", "", true }, { Event::ConsoleColor, "Color TV", "", true }, { Event::ConsoleBlackWhite, "Black & White TV", "", true }, { Event::ConsoleColorToggle, "Swap Color / B&W TV", "", true }, { Event::Console7800Pause, "7800 Pause Key", "", true }, { Event::ConsoleLeftDiffA, "P0 Difficulty A", "", true }, { Event::ConsoleLeftDiffB, "P0 Difficulty B", "", true }, { Event::ConsoleLeftDiffToggle, "P0 Swap Difficulty", "", true }, { Event::ConsoleRightDiffA, "P1 Difficulty A", "", true }, { Event::ConsoleRightDiffB, "P1 Difficulty B", "", true }, { Event::ConsoleRightDiffToggle, "P1 Swap Difficulty", "", true }, { Event::SaveState, "Save State", "", false }, { Event::ChangeState, "Change State", "", false }, { Event::LoadState, "Load State", "", false }, { Event::TakeSnapshot, "Snapshot", "", false }, { Event::Fry, "Fry cartridge", "", false }, { Event::VolumeDecrease, "Decrease volume", "", false }, { Event::VolumeIncrease, "Increase volume", "", false }, { Event::PauseMode, "Pause", "", false }, { Event::OptionsMenuMode, "Enter options menu UI", "", false }, { Event::CmdMenuMode, "Toggle command menu UI", "", false }, { Event::TimeMachineMode, "Toggle time machine UI", "", false }, { Event::DebuggerMode, "Toggle debugger mode", "", false }, { Event::LauncherMode, "Enter ROM launcher", "", false }, { Event::Quit, "Quit", "", false }, { Event::JoystickZeroUp, "P0 Joystick Up", "", true }, { Event::JoystickZeroDown, "P0 Joystick Down", "", true }, { Event::JoystickZeroLeft, "P0 Joystick Left", "", true }, { Event::JoystickZeroRight, "P0 Joystick Right", "", true }, { Event::JoystickZeroFire, "P0 Joystick Fire", "", true }, { Event::JoystickZeroFire5, "P0 Booster Top Trigger", "", true }, { Event::JoystickZeroFire9, "P0 Booster Handle Grip", "", true }, { Event::JoystickOneUp, "P1 Joystick Up", "", true }, { Event::JoystickOneDown, "P1 Joystick Down", "", true }, { Event::JoystickOneLeft, "P1 Joystick Left", "", true }, { Event::JoystickOneRight, "P1 Joystick Right", "", true }, { Event::JoystickOneFire, "P1 Joystick Fire", "", true }, { Event::JoystickOneFire5, "P1 Booster Top Trigger", "", true }, { Event::JoystickOneFire9, "P1 Booster Handle Grip", "", true }, { Event::PaddleZeroAnalog, "Paddle 0 Analog", "", true }, { Event::PaddleZeroDecrease, "Paddle 0 Decrease", "", true }, { Event::PaddleZeroIncrease, "Paddle 0 Increase", "", true }, { Event::PaddleZeroFire, "Paddle 0 Fire", "", true }, { Event::PaddleOneAnalog, "Paddle 1 Analog", "", true }, { Event::PaddleOneDecrease, "Paddle 1 Decrease", "", true }, { Event::PaddleOneIncrease, "Paddle 1 Increase", "", true }, { Event::PaddleOneFire, "Paddle 1 Fire", "", true }, { Event::PaddleTwoAnalog, "Paddle 2 Analog", "", true }, { Event::PaddleTwoDecrease, "Paddle 2 Decrease", "", true }, { Event::PaddleTwoIncrease, "Paddle 2 Increase", "", true }, { Event::PaddleTwoFire, "Paddle 2 Fire", "", true }, { Event::PaddleThreeAnalog, "Paddle 3 Analog", "", true }, { Event::PaddleThreeDecrease, "Paddle 3 Decrease", "", true }, { Event::PaddleThreeIncrease, "Paddle 3 Increase", "", true }, { Event::PaddleThreeFire, "Paddle 3 Fire", "", true }, { Event::KeyboardZero1, "P0 Keyboard 1", "", true }, { Event::KeyboardZero2, "P0 Keyboard 2", "", true }, { Event::KeyboardZero3, "P0 Keyboard 3", "", true }, { Event::KeyboardZero4, "P0 Keyboard 4", "", true }, { Event::KeyboardZero5, "P0 Keyboard 5", "", true }, { Event::KeyboardZero6, "P0 Keyboard 6", "", true }, { Event::KeyboardZero7, "P0 Keyboard 7", "", true }, { Event::KeyboardZero8, "P0 Keyboard 8", "", true }, { Event::KeyboardZero9, "P0 Keyboard 9", "", true }, { Event::KeyboardZeroStar, "P0 Keyboard *", "", true }, { Event::KeyboardZero0, "P0 Keyboard 0", "", true }, { Event::KeyboardZeroPound, "P0 Keyboard #", "", true }, { Event::KeyboardOne1, "P1 Keyboard 1", "", true }, { Event::KeyboardOne2, "P1 Keyboard 2", "", true }, { Event::KeyboardOne3, "P1 Keyboard 3", "", true }, { Event::KeyboardOne4, "P1 Keyboard 4", "", true }, { Event::KeyboardOne5, "P1 Keyboard 5", "", true }, { Event::KeyboardOne6, "P1 Keyboard 6", "", true }, { Event::KeyboardOne7, "P1 Keyboard 7", "", true }, { Event::KeyboardOne8, "P1 Keyboard 8", "", true }, { Event::KeyboardOne9, "P1 Keyboard 9", "", true }, { Event::KeyboardOneStar, "P1 Keyboard *", "", true }, { Event::KeyboardOne0, "P1 Keyboard 0", "", true }, { Event::KeyboardOnePound, "P1 Keyboard #", "", true }, { Event::Combo1, "Combo 1", "", false }, { Event::Combo2, "Combo 2", "", false }, { Event::Combo3, "Combo 3", "", false }, { Event::Combo4, "Combo 4", "", false }, { Event::Combo5, "Combo 5", "", false }, { Event::Combo6, "Combo 6", "", false }, { Event::Combo7, "Combo 7", "", false }, { Event::Combo8, "Combo 8", "", false }, { Event::Combo9, "Combo 9", "", false }, { Event::Combo10, "Combo 10", "", false }, { Event::Combo11, "Combo 11", "", false }, { Event::Combo12, "Combo 12", "", false }, { Event::Combo13, "Combo 13", "", false }, { Event::Combo14, "Combo 14", "", false }, { Event::Combo15, "Combo 15", "", false }, { Event::Combo16, "Combo 16", "", false } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::ActionList EventHandler::ourMenuActionList[kMenuActionListSize] = { { Event::UIUp, "Move Up", "", false }, { Event::UIDown, "Move Down", "", false }, { Event::UILeft, "Move Left", "", false }, { Event::UIRight, "Move Right", "", false }, { Event::UIHome, "Home", "", false }, { Event::UIEnd, "End", "", false }, { Event::UIPgUp, "Page Up", "", false }, { Event::UIPgDown, "Page Down", "", false }, { Event::UIOK, "OK", "", false }, { Event::UICancel, "Cancel", "", false }, { Event::UISelect, "Select item", "", false }, { Event::UINavPrev, "Previous object", "", false }, { Event::UINavNext, "Next object", "", false }, { Event::UIPrevDir, "Parent directory", "", false } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Used by the Stelladaptor to send absolute axis values const Event::Type EventHandler::SA_Axis[2][2] = { { Event::SALeftAxis0Value, Event::SALeftAxis1Value }, { Event::SARightAxis0Value, Event::SARightAxis1Value } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Used by the Stelladaptor to map button presses to joystick or paddles // (driving controllers and boostergrip are considered the same as joysticks) const Event::Type EventHandler::SA_Button[2][4] = { { Event::JoystickZeroFire, Event::JoystickZeroFire9, Event::JoystickZeroFire5, Event::JoystickZeroFire9 }, { Event::JoystickOneFire, Event::JoystickOneFire9, Event::JoystickOneFire5, Event::JoystickOneFire9 } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Used by the 2600-daptor to map button presses to keypad keys const Event::Type EventHandler::SA_Key[2][12] = { { Event::KeyboardZero1, Event::KeyboardZero2, Event::KeyboardZero3, Event::KeyboardZero4, Event::KeyboardZero5, Event::KeyboardZero6, Event::KeyboardZero7, Event::KeyboardZero8, Event::KeyboardZero9, Event::KeyboardZeroStar, Event::KeyboardZero0, Event::KeyboardZeroPound }, { Event::KeyboardOne1, Event::KeyboardOne2, Event::KeyboardOne3, Event::KeyboardOne4, Event::KeyboardOne5, Event::KeyboardOne6, Event::KeyboardOne7, Event::KeyboardOne8, Event::KeyboardOne9, Event::KeyboardOneStar, Event::KeyboardOne0, Event::KeyboardOnePound } }; stella-5.1.1/src/emucore/EventHandler.hxx000066400000000000000000000454451324334165500203620ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef EVENTHANDLER_HXX #define EVENTHANDLER_HXX #include class Console; class OSystem; class MouseControl; class DialogContainer; class EventMappingWidget; #include "Event.hxx" #include "EventHandlerConstants.hxx" #include "Control.hxx" #include "StellaKeys.hxx" #include "Variant.hxx" #include "bspf.hxx" /** This class takes care of event remapping and dispatching for the Stella core, as well as keeping track of the current 'mode'. The frontend will send translated events here, and the handler will check to see what the current 'mode' is. If in emulation mode, events received from the frontend are remapped and sent to the emulation core. If in menu mode, the events are sent unchanged to the menu class, where (among other things) changing key mapping can take place. @author Stephen Anthony */ class EventHandler { public: /** Create a new event handler object */ EventHandler(OSystem& osystem); virtual ~EventHandler(); /** Returns the event object associated with this handler class. @return The event object */ const Event& event() const { return myEvent; } /** Initialize state of this eventhandler. */ void initialize(); /** Maps the given Stelladaptor/2600-daptor(s) to specified ports on a real 2600. @param saport How to map the ports ('lr' or 'rl') */ void mapStelladaptors(const string& saport); /** Swaps the ordering of Stelladaptor/2600-daptor(s) devices. */ void toggleSAPortOrder(); /** Toggle whether the console is in 2600 or 7800 mode. Note that for now, this only affects whether the 7800 pause button is supported; there is no further emulation of the 7800 itself. */ void set7800Mode(); /** Collects and dispatches any pending events. This method should be called regularly (at X times per second, where X is the game framerate). @param time The current time in microseconds. */ void poll(uInt64 time); /** Returns the current state of the EventHandler @return The EventHandlerState type */ EventHandlerState state() const { return myState; } /** Resets the state machine of the EventHandler to the defaults @param state The current state to set */ void reset(EventHandlerState state); /** This method indicates that the system should terminate. */ void quit() { handleEvent(Event::Quit, 1); } /** Sets the mouse axes and buttons to act as the controller specified in the ROM properties, otherwise disable mouse control completely @param enable Whether to use the mouse to emulate controllers Currently, this will be one of the following values: 'always', 'analog', 'never' */ void setMouseControllerMode(const string& enable); /** Set the number of seconds between taking a snapshot in continuous snapshot mode. Setting an interval of 0 disables continuous snapshots. @param interval Interval in seconds between snapshots */ void setContinuousSnapshots(uInt32 interval); void enterMenuMode(EventHandlerState state); void leaveMenuMode(); bool enterDebugMode(); void leaveDebugMode(); void enterTimeMachineMenuMode(uInt32 numWinds, bool unwind); void takeSnapshot(uInt32 number = 0); /** Send an event directly to the event handler. These events cannot be remapped. @param type The event @param value The value for the event */ void handleEvent(Event::Type type, Int32 value); /** Handle events that must be processed each time a new console is created. Typically, these are events set by commandline arguments. */ void handleConsoleStartupEvents(); bool frying() const { return myFryingFlag; } StringList getActionList(EventMode mode) const; VariantList getComboList(EventMode mode) const; /** Used to access the list of events assigned to a specific combo event. */ StringList getComboListForEvent(Event::Type event) const; void setComboListForEvent(Event::Type event, const StringList& events); Event::Type eventForKey(StellaKey key, EventMode mode) const { return myKeyTable[key][mode]; } Event::Type eventForJoyAxis(int stick, int axis, int value, EventMode mode) const { const StellaJoystick* joy = myJoyHandler->joy(stick); return joy ? joy->axisTable[axis][(value > 0)][mode] : Event::NoType; } Event::Type eventForJoyButton(int stick, int button, EventMode mode) const { const StellaJoystick* joy = myJoyHandler->joy(stick); return joy ? joy->btnTable[button][mode] : Event::NoType; } Event::Type eventForJoyHat(int stick, int hat, JoyHat value, EventMode mode) const { const StellaJoystick* joy = myJoyHandler->joy(stick); return joy ? joy->hatTable[hat][int(value)][mode] : Event::NoType; } Event::Type eventAtIndex(int idx, EventMode mode) const; string actionAtIndex(int idx, EventMode mode) const; string keyAtIndex(int idx, EventMode mode) const; /** Bind a key to an event/action and regenerate the mapping array(s). @param event The event we are remapping @param mode The mode where this event is active @param key The key to bind to this event */ bool addKeyMapping(Event::Type event, EventMode mode, StellaKey key); /** Bind a joystick axis direction to an event/action and regenerate the mapping array(s). @param event The event we are remapping @param mode The mode where this event is active @param stick The joystick number @param axis The joystick axis @param value The value on the given axis @param updateMenus Whether to update the action mappings (normally we want to do this, unless there are a batch of 'adds', in which case it's delayed until the end */ bool addJoyAxisMapping(Event::Type event, EventMode mode, int stick, int axis, int value, bool updateMenus = true); /** Bind a joystick button to an event/action and regenerate the mapping array(s). @param event The event we are remapping @param mode The mode where this event is active @param stick The joystick number @param button The joystick button @param updateMenus Whether to update the action mappings (normally we want to do this, unless there are a batch of 'adds', in which case it's delayed until the end */ bool addJoyButtonMapping(Event::Type event, EventMode mode, int stick, int button, bool updateMenus = true); /** Bind a joystick hat direction to an event/action and regenerate the mapping array(s). @param event The event we are remapping @param mode The mode where this event is active @param stick The joystick number @param hat The joystick hat @param value The value on the given hat @param updateMenus Whether to update the action mappings (normally we want to do this, unless there are a batch of 'adds', in which case it's delayed until the end */ bool addJoyHatMapping(Event::Type event, EventMode mode, int stick, int hat, JoyHat value, bool updateMenus = true); /** Erase the specified mapping. @param event The event for which we erase all mappings @param mode The mode where this event is active */ void eraseMapping(Event::Type event, EventMode mode); /** Resets the event mappings to default values. @param event The event which to (re)set (Event::NoType resets all) @param mode The mode for which the defaults are set */ void setDefaultMapping(Event::Type event, EventMode mode); /** Sets the combo event mappings to those in the 'combomap' setting */ void setComboMap(); /** Joystick emulates 'impossible' directions (ie, left & right at the same time). @param allow Whether or not to allow impossible directions */ void allowAllDirections(bool allow) { myAllowAllDirectionsFlag = allow; } /** Determines whether the given controller must use the mouse (aka, whether the controller generates analog output). @param jack The controller to query */ bool controllerIsAnalog(Controller::Jack jack) const; /** Return a list of all joysticks currently in the internal database (first part of variant) and its internal ID (second part of variant). */ VariantList joystickDatabase() const; /** Remove the joystick identified by 'name' from the joystick database, only if it is not currently active. */ void removeJoystickFromDatabase(const string& name); /** Enable/disable text events (distinct from single-key events). */ virtual void enableTextEvents(bool enable) = 0; protected: // Global OSystem object OSystem& myOSystem; /** Methods which are called by derived classes to handle specific types of input. */ void handleTextEvent(char text); void handleKeyEvent(StellaKey key, StellaMod mod, bool state); void handleMouseMotionEvent(int x, int y, int xrel, int yrel); void handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y); void handleJoyEvent(int stick, int button, uInt8 state); void handleJoyAxisEvent(int stick, int axis, int value); void handleJoyHatEvent(int stick, int hat, int value); /** Returns the human-readable name for a StellaKey. */ virtual const char* const nameForKey(StellaKey key) const { return EmptyString.c_str(); } /** Collects and dispatches any pending events. */ virtual void pollEvent() = 0; // Other events that can be received from the underlying event handler enum class SystemEvent { WINDOW_SHOWN, WINDOW_HIDDEN, WINDOW_EXPOSED, WINDOW_MOVED, WINDOW_RESIZED, WINDOW_MINIMIZED, WINDOW_MAXIMIZED, WINDOW_RESTORED, WINDOW_ENTER, WINDOW_LEAVE, WINDOW_FOCUS_GAINED, WINDOW_FOCUS_LOST }; void handleSystemEvent(SystemEvent e, int data1 = 0, int data2 = 0); // An abstraction of a joystick in Stella. // A StellaJoystick holds its own event mapping information, space for // which is dynamically allocated based on the actual number of buttons, // axes, etc that the device contains. // Specific backend class(es) will inherit from this class, and implement // functionality specific to the device. class StellaJoystick { friend class EventHandler; public: StellaJoystick(); virtual ~StellaJoystick(); string getMap() const; bool setMap(const string& map); void eraseMap(EventMode mode); void eraseEvent(Event::Type event, EventMode mode); string about() const; protected: void initialize(int index, const string& desc, int axes, int buttons, int hats, int balls); private: enum JoyType { JT_NONE = 0, JT_REGULAR = 1, JT_STELLADAPTOR_LEFT = 2, JT_STELLADAPTOR_RIGHT = 3, JT_2600DAPTOR_LEFT = 4, JT_2600DAPTOR_RIGHT = 5 }; JoyType type; int ID; string name; int numAxes, numButtons, numHats; Event::Type (*axisTable)[2][kNumModes]; Event::Type (*btnTable)[kNumModes]; Event::Type (*hatTable)[4][kNumModes]; int* axisLastValue; private: void getValues(const string& list, IntArray& map) const; friend ostream& operator<<(ostream& os, const StellaJoystick& s) { os << " ID: " << s.ID << ", name: " << s.name << ", numaxis: " << s.numAxes << ", numbtns: " << s.numButtons << ", numhats: " << s.numHats; return os; } }; class JoystickHandler { private: struct StickInfo { StickInfo(const string& map = EmptyString, StellaJoystick* stick = nullptr) : mapping(map), joy(stick) {} string mapping; StellaJoystick* joy; friend ostream& operator<<(ostream& os, const StickInfo& si) { os << " joy: " << si.joy << endl << " map: " << si.mapping; return os; } }; public: using StickDatabase = std::map; using StickList = std::map; JoystickHandler(OSystem& system); ~JoystickHandler(); bool add(StellaJoystick* stick); bool remove(int id); bool remove(const string& name); void mapStelladaptors(const string& saport); void setDefaultMapping(Event::Type type, EventMode mode); void eraseMapping(Event::Type event, EventMode mode); void saveMapping(); const StellaJoystick* joy(int id) const { const auto& i = mySticks.find(id); return i != mySticks.cend() ? i->second : nullptr; } const StickDatabase& database() const { return myDatabase; } const StickList& sticks() const { return mySticks; } private: OSystem& myOSystem; // Contains all joysticks that Stella knows about, indexed by name StickDatabase myDatabase; // Contains only joysticks that are currently available, indexed by id StickList mySticks; void setStickDefaultMapping(int stick, Event::Type type, EventMode mode); void printDatabase() const; }; /** Add the given joystick to the list of sticks available to the handler. */ void addJoystick(StellaJoystick* stick); /** Remove joystick at the current index. */ void removeJoystick(int index); private: enum { kComboSize = 16, kEventsPerCombo = 8, kEmulActionListSize = 80 + kComboSize, kMenuActionListSize = 14 }; /** Detects and changes the eventhandler state @param type The event @return True if the state changed, else false */ bool eventStateChange(Event::Type type); /** The following methods take care of assigning action mappings. */ void setActionMappings(EventMode mode); void setKeyNames(); void setKeymap(); void setDefaultKeymap(Event::Type, EventMode mode); void setDefaultJoymap(Event::Type, EventMode mode); void saveKeyMapping(); void saveJoyMapping(); void saveComboMapping(); /** Tests if a given event should use continuous/analog values. @param event The event to test for analog processing @return True if analog, else false */ bool eventIsAnalog(Event::Type event) const; void setEventState(EventHandlerState state); private: // Structure used for action menu items struct ActionList { Event::Type event; string action; string key; bool allow_combo; }; // Global Event object Event myEvent; // Indicates current overlay object DialogContainer* myOverlay; // MouseControl object, which takes care of switching the mouse between // all possible controller modes unique_ptr myMouseControl; // Array of key events, indexed by StellaKey Event::Type myKeyTable[KBDK_LAST][kNumModes]; // The event(s) assigned to each combination event Event::Type myComboTable[kComboSize][kEventsPerCombo]; // Indicates the current state of the system (ie, which mode is current) EventHandlerState myState; // Indicates whether the joystick emulates 'impossible' directions bool myAllowAllDirectionsFlag; // Indicates whether or not we're in frying mode bool myFryingFlag; // Indicates whether the key-combos tied to the Control key are // being used or not (since Ctrl by default is the fire button, // pressing it with a movement key could inadvertantly activate // a Ctrl combo when it isn't wanted) bool myUseCtrlKeyFlag; // Sometimes an extraneous mouse motion event occurs after a video // state change; we detect when this happens and discard the event bool mySkipMouseMotion; // Whether the currently enabled console is emulating certain aspects // of the 7800 (for now, only the switches are notified) bool myIs7800; // Sometimes key combos with the Alt key become 'stuck' after the // window changes state, and we want to ignore that event // For example, press Alt-Tab and then upon re-entering the window, // the app receives 'tab'; obviously the 'tab' shouldn't be happening // So we keep track of the cases that matter (for now, Alt-Tab) // and swallow the event afterwards // Basically, the initial event sets the variable to 1, and upon // returning to the app (ie, receiving EVENT_WINDOW_FOCUS_GAINED), // the count is updated to 2, but only if it was already updated to 1 // TODO - This may be a bug in SDL, and might be removed in the future // It only seems to be an issue in Linux uInt8 myAltKeyCounter; // Used for continuous snapshot mode uInt32 myContSnapshotInterval; uInt32 myContSnapshotCounter; // Holds static strings for the remap menu (emulation and menu events) static ActionList ourEmulActionList[kEmulActionListSize]; static ActionList ourMenuActionList[kMenuActionListSize]; // Static lookup tables for Stelladaptor/2600-daptor axis/button support static const Event::Type SA_Axis[2][2]; static const Event::Type SA_Button[2][4]; static const Event::Type SA_Key[2][12]; // Handler for all joystick addition/removal/mapping unique_ptr myJoyHandler; // Following constructors and assignment operators not supported EventHandler() = delete; EventHandler(const EventHandler&) = delete; EventHandler(EventHandler&&) = delete; EventHandler& operator=(const EventHandler&) = delete; EventHandler& operator=(EventHandler&&) = delete; }; #endif stella-5.1.1/src/emucore/EventHandlerConstants.hxx000066400000000000000000000032201324334165500222400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef EVENTHANDLER_CONSTANTS_HXX #define EVENTHANDLER_CONSTANTS_HXX // Enumeration representing the different states of operation enum class EventHandlerState { EMULATION, TIMEMACHINE, PAUSE, LAUNCHER, OPTIONSMENU, CMDMENU, DEBUGGER, NONE }; enum class MouseButton { LEFT, RIGHT, WHEELDOWN, WHEELUP, NONE }; enum class JoyHat { UP = 0, // make sure these are set correctly, DOWN = 1, // since they'll be used as array indices LEFT = 2, RIGHT = 3, CENTER = 4 }; // TODO - add bitmask class for 'enum class' and convert this enum JoyHatMask { EVENT_HATUP_M = 1<<0, EVENT_HATDOWN_M = 1<<1, EVENT_HATLEFT_M = 1<<2, EVENT_HATRIGHT_M = 1<<3, EVENT_HATCENTER_M = 1<<4 }; // TODO - make this 'enum class' somehow enum EventMode { kEmulationMode = 0, // make sure these are set correctly, kMenuMode = 1, // since they'll be used as array indices kNumModes = 2 }; #endif // EVENTHANDLER_CONSTANTS_HXX stella-5.1.1/src/emucore/EventJoyHandler.cxx000066400000000000000000000445551324334165500210400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "OSystem.hxx" #include "Settings.hxx" #include "Vec.hxx" #include "bspf.hxx" #include "EventHandler.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::StellaJoystick::StellaJoystick() : type(JT_NONE), ID(-1), name("None"), numAxes(0), numButtons(0), numHats(0), axisTable(nullptr), btnTable(nullptr), hatTable(nullptr), axisLastValue(nullptr) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::StellaJoystick::~StellaJoystick() { delete[] axisTable; delete[] btnTable; delete[] hatTable; delete[] axisLastValue; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::StellaJoystick::initialize(int index, const string& desc, int axes, int buttons, int hats, int /*balls*/) { ID = index; name = desc; // Dynamically create the various mapping arrays for this joystick, // based on its specific attributes numAxes = axes; numButtons = buttons; numHats = hats; if(numAxes) axisTable = new Event::Type[numAxes][2][kNumModes]; if(numButtons) btnTable = new Event::Type[numButtons][kNumModes]; if(numHats) hatTable = new Event::Type[numHats][4][kNumModes]; axisLastValue = new int[numAxes]; // Erase the joystick axis mapping array and last axis value for(int a = 0; a < numAxes; ++a) { axisLastValue[a] = 0; for(int m = 0; m < kNumModes; ++m) axisTable[a][0][m] = axisTable[a][1][m] = Event::NoType; } // Erase the joystick button mapping array for(int b = 0; b < numButtons; ++b) for(int m = 0; m < kNumModes; ++m) btnTable[b][m] = Event::NoType; // Erase the joystick hat mapping array for(int h = 0; h < numHats; ++h) for(int m = 0; m < kNumModes; ++m) hatTable[h][0][m] = hatTable[h][1][m] = hatTable[h][2][m] = hatTable[h][3][m] = Event::NoType; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::StellaJoystick::getMap() const { // The mapping structure (for remappable devices) is defined as follows: // NAME | AXIS # + values | BUTTON # + values | HAT # + values, // where each subsection of values is separated by ':' if(type == JT_REGULAR) { ostringstream joybuf; joybuf << name << "|" << numAxes; for(int m = 0; m < kNumModes; ++m) for(int a = 0; a < numAxes; ++a) for(int k = 0; k < 2; ++k) joybuf << " " << axisTable[a][k][m]; joybuf << "|" << numButtons; for(int m = 0; m < kNumModes; ++m) for(int b = 0; b < numButtons; ++b) joybuf << " " << btnTable[b][m]; joybuf << "|" << numHats; for(int m = 0; m < kNumModes; ++m) for(int h = 0; h < numHats; ++h) for(int k = 0; k < 4; ++k) joybuf << " " << hatTable[h][k][m]; return joybuf.str(); } return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::StellaJoystick::setMap(const string& mapString) { istringstream buf(mapString); StringList items; string item; while(getline(buf, item, '|')) items.push_back(item); // Error checking if(items.size() != 4) return false; IntArray map; // Parse axis/button/hat values getValues(items[1], map); if(int(map.size()) == numAxes * 2 * kNumModes) { // Fill the axes table with events auto event = map.cbegin(); for(int m = 0; m < kNumModes; ++m) for(int a = 0; a < numAxes; ++a) for(int k = 0; k < 2; ++k) axisTable[a][k][m] = Event::Type(*event++); } getValues(items[2], map); if(int(map.size()) == numButtons * kNumModes) { auto event = map.cbegin(); for(int m = 0; m < kNumModes; ++m) for(int b = 0; b < numButtons; ++b) btnTable[b][m] = Event::Type(*event++); } getValues(items[3], map); if(int(map.size()) == numHats * 4 * kNumModes) { auto event = map.cbegin(); for(int m = 0; m < kNumModes; ++m) for(int h = 0; h < numHats; ++h) for(int k = 0; k < 4; ++k) hatTable[h][k][m] = Event::Type(*event++); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::StellaJoystick::eraseMap(EventMode mode) { // Erase axis mappings for(int a = 0; a < numAxes; ++a) axisTable[a][0][mode] = axisTable[a][1][mode] = Event::NoType; // Erase button mappings for(int b = 0; b < numButtons; ++b) btnTable[b][mode] = Event::NoType; // Erase hat mappings for(int h = 0; h < numHats; ++h) hatTable[h][0][mode] = hatTable[h][1][mode] = hatTable[h][2][mode] = hatTable[h][3][mode] = Event::NoType; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::StellaJoystick::eraseEvent(Event::Type event, EventMode mode) { // Erase axis mappings for(int a = 0; a < numAxes; ++a) { if(axisTable[a][0][mode] == event) axisTable[a][0][mode] = Event::NoType; if(axisTable[a][1][mode] == event) axisTable[a][1][mode] = Event::NoType; } // Erase button mappings for(int b = 0; b < numButtons; ++b) if(btnTable[b][mode] == event) btnTable[b][mode] = Event::NoType; // Erase hat mappings for(int h = 0; h < numHats; ++h) { if(hatTable[h][0][mode] == event) hatTable[h][0][mode] = Event::NoType; if(hatTable[h][1][mode] == event) hatTable[h][1][mode] = Event::NoType; if(hatTable[h][2][mode] == event) hatTable[h][2][mode] = Event::NoType; if(hatTable[h][3][mode] == event) hatTable[h][3][mode] = Event::NoType; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::StellaJoystick::getValues(const string& list, IntArray& map) const { map.clear(); istringstream buf(list); int value; buf >> value; // we don't need to know the # of items at this point while(buf >> value) map.push_back(value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EventHandler::StellaJoystick::about() const { ostringstream buf; buf << name; if(type == JT_REGULAR) buf << " with: " << numAxes << " axes, " << numButtons << " buttons, " << numHats << " hats"; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::JoystickHandler::JoystickHandler(OSystem& system) : myOSystem(system) { // Load previously saved joystick mapping (if any) from settings istringstream buf(myOSystem.settings().getString("joymap")); string joymap, joyname; // First check the event type, and disregard the entire mapping if it's invalid getline(buf, joymap, '^'); if(atoi(joymap.c_str()) == Event::LastType) { // Otherwise, put each joystick mapping entry into the database while(getline(buf, joymap, '^')) { istringstream namebuf(joymap); getline(namebuf, joyname, '|'); if(joyname.length() != 0) { StickInfo info(joymap); myDatabase.emplace(joyname, info); } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventHandler::JoystickHandler::~JoystickHandler() { for(const auto& i: myDatabase) delete i.second.joy; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::JoystickHandler::printDatabase() const { cerr << "---------------------------------------------------------" << endl << "joy database:" << endl; for(const auto& i: myDatabase) cerr << i.first << endl << i.second << endl << endl; cerr << "---------------------" << endl << "joy active:" << endl; for(const auto& i: mySticks) cerr << i.first << ": " << *i.second << endl; cerr << "---------------------------------------------------------" << endl << endl << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::JoystickHandler::add(StellaJoystick* stick) { // Skip if we couldn't open it for any reason if(stick->ID < 0) return false; // Figure out what type of joystick this is bool specialAdaptor = false; if(BSPF::containsIgnoreCase(stick->name, "2600-daptor")) { // 2600-daptorII devices have 3 axes and 12 buttons, and the value of the z-axis // determines how those 12 buttons are used (not all buttons are used in all modes) if(stick->numAxes == 3) { // TODO - stubbed out for now, until we find a way to reliably get info // from the Z axis stick->name = "2600-daptor II"; } else stick->name = "2600-daptor"; specialAdaptor = true; } else if(BSPF::containsIgnoreCase(stick->name, "Stelladaptor")) { stick->name = "Stelladaptor"; specialAdaptor = true; } else { // We need unique names for mappable devices // For non-unique names that already have a database entry, // we append ' #x', where 'x' increases consecutively int count = 0; for(const auto& i: myDatabase) if(BSPF::startsWithIgnoreCase(i.first, stick->name) && i.second.joy) ++count; if(count > 0) { ostringstream name; name << stick->name << " #" << count+1; stick->name = name.str(); } stick->type = StellaJoystick::JT_REGULAR; } // The stick *must* be inserted here, since it may be used below mySticks[stick->ID] = stick; // Map the stelladaptors we've found according to the specified ports if(specialAdaptor) mapStelladaptors(myOSystem.settings().getString("saport")); // Add stick to database auto it = myDatabase.find(stick->name); if(it != myDatabase.end()) // already present { it->second.joy = stick; stick->setMap(it->second.mapping); } else // adding for the first time { StickInfo info("", stick); myDatabase.emplace(stick->name, info); setStickDefaultMapping(stick->ID, Event::NoType, kEmulationMode); setStickDefaultMapping(stick->ID, Event::NoType, kMenuMode); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::JoystickHandler::remove(int id) { // When a joystick is removed, we delete the actual joystick object but // remember its mapping, since it will eventually be saved to settings // Sticks that are removed must have initially been added // So we use the 'active' joystick list to access them try { StellaJoystick* stick = mySticks.at(id); auto it = myDatabase.find(stick->name); if(it != myDatabase.end() && it->second.joy == stick) { ostringstream buf; buf << "Removed joystick " << mySticks[id]->ID << ":" << endl << " " << mySticks[id]->about() << endl; myOSystem.logMessage(buf.str(), 1); // Remove joystick, but remember mapping it->second.mapping = stick->getMap(); delete it->second.joy; it->second.joy = nullptr; mySticks.erase(id); return true; } } catch(std::out_of_range) { // fall through to indicate remove failed } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventHandler::JoystickHandler::remove(const string& name) { auto it = myDatabase.find(name); if(it != myDatabase.end() && it->second.joy == nullptr) { myDatabase.erase(it); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::JoystickHandler::mapStelladaptors(const string& saport) { // saport will have two values: // 'lr' means treat first valid adaptor as left port, second as right port // 'rl' means treat first valid adaptor as right port, second as left port // We know there will be only two such devices (at most), since the logic // in setupJoysticks take care of that int saCount = 0; int saOrder[2] = { 1, 2 }; if(BSPF::equalsIgnoreCase(saport, "rl")) { saOrder[0] = 2; saOrder[1] = 1; } for(auto& stick: mySticks) { if(BSPF::startsWithIgnoreCase(stick.second->name, "Stelladaptor")) { if(saOrder[saCount] == 1) { stick.second->name += " (emulates left joystick port)"; stick.second->type = StellaJoystick::JT_STELLADAPTOR_LEFT; } else if(saOrder[saCount] == 2) { stick.second->name += " (emulates right joystick port)"; stick.second->type = StellaJoystick::JT_STELLADAPTOR_RIGHT; } saCount++; } else if(BSPF::startsWithIgnoreCase(stick.second->name, "2600-daptor")) { if(saOrder[saCount] == 1) { stick.second->name += " (emulates left joystick port)"; stick.second->type = StellaJoystick::JT_2600DAPTOR_LEFT; } else if(saOrder[saCount] == 2) { stick.second->name += " (emulates right joystick port)"; stick.second->type = StellaJoystick::JT_2600DAPTOR_RIGHT; } saCount++; } } myOSystem.settings().setValue("saport", saport); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::JoystickHandler::setDefaultMapping(Event::Type event, EventMode mode) { eraseMapping(event, mode); for(auto& i: mySticks) setStickDefaultMapping(i.first, event, mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::JoystickHandler::setStickDefaultMapping(int stick, Event::Type event, EventMode mode) { EventHandler& handler = myOSystem.eventHandler(); bool eraseAll = (event == Event::NoType); auto setDefaultAxis = [&](int a_stick, int a_axis, int a_value, Event::Type a_event) { if(eraseAll || a_event == event) handler.addJoyAxisMapping(a_event, mode, a_stick, a_axis, a_value, false); }; auto setDefaultBtn = [&](int b_stick, int b_button, Event::Type b_event) { if(eraseAll || b_event == event) handler.addJoyButtonMapping(b_event, mode, b_stick, b_button, false); }; auto setDefaultHat = [&](int h_stick, int h_hat, JoyHat h_dir, Event::Type h_event) { if(eraseAll || h_event == event) handler.addJoyHatMapping(h_event, mode, h_stick, h_hat, h_dir, false); }; switch(mode) { case kEmulationMode: // Default emulation events if(stick == 0) { // Left joystick left/right directions (assume joystick zero) setDefaultAxis( 0, 0, 0, Event::JoystickZeroLeft ); setDefaultAxis( 0, 0, 1, Event::JoystickZeroRight ); // Left joystick up/down directions (assume joystick zero) setDefaultAxis( 0, 1, 0, Event::JoystickZeroUp ); setDefaultAxis( 0, 1, 1, Event::JoystickZeroDown ); // Left joystick (assume joystick zero, button zero) setDefaultBtn( 0, 0, Event::JoystickZeroFire ); // Left joystick left/right directions (assume joystick zero and hat 0) setDefaultHat( 0, 0, JoyHat::LEFT, Event::JoystickZeroLeft ); setDefaultHat( 0, 0, JoyHat::RIGHT, Event::JoystickZeroRight ); // Left joystick up/down directions (assume joystick zero and hat 0) setDefaultHat( 0, 0, JoyHat::UP, Event::JoystickZeroUp ); setDefaultHat( 0, 0, JoyHat::DOWN, Event::JoystickZeroDown ); } else if(stick == 1) { // Right joystick left/right directions (assume joystick one) setDefaultAxis( 1, 0, 0, Event::JoystickOneLeft ); setDefaultAxis( 1, 0, 1, Event::JoystickOneRight ); // Right joystick left/right directions (assume joystick one) setDefaultAxis( 1, 1, 0, Event::JoystickOneUp ); setDefaultAxis( 1, 1, 1, Event::JoystickOneDown ); // Right joystick (assume joystick one, button zero) setDefaultBtn( 1, 0, Event::JoystickOneFire ); // Right joystick left/right directions (assume joystick one and hat 0) setDefaultHat( 1, 0, JoyHat::LEFT, Event::JoystickOneLeft ); setDefaultHat( 1, 0, JoyHat::RIGHT, Event::JoystickOneRight ); // Right joystick up/down directions (assume joystick one and hat 0) setDefaultHat( 1, 0, JoyHat::UP, Event::JoystickOneUp ); setDefaultHat( 1, 0, JoyHat::DOWN, Event::JoystickOneDown ); } break; case kMenuMode: // Default menu/UI events if(stick == 0) { setDefaultAxis( 0, 0, 0, Event::UILeft ); setDefaultAxis( 0, 0, 1, Event::UIRight ); setDefaultAxis( 0, 1, 0, Event::UIUp ); setDefaultAxis( 0, 1, 1, Event::UIDown ); // Left joystick (assume joystick zero, button zero) setDefaultBtn( 0, 0, Event::UISelect ); setDefaultHat( 0, 0, JoyHat::LEFT, Event::UILeft ); setDefaultHat( 0, 0, JoyHat::RIGHT, Event::UIRight ); setDefaultHat( 0, 0, JoyHat::UP, Event::UIUp ); setDefaultHat( 0, 0, JoyHat::DOWN, Event::UIDown ); } break; default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::JoystickHandler::eraseMapping(Event::Type event, EventMode mode) { // If event is 'NoType', erase and reset all mappings // Otherwise, only reset the given event if(event == Event::NoType) { for(auto& stick: mySticks) stick.second->eraseMap(mode); // erase all events } else { for(auto& stick: mySticks) stick.second->eraseEvent(event, mode); // only reset the specific event } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventHandler::JoystickHandler::saveMapping() { // Save the joystick mapping hash table, making sure to update it with // any changes that have been made during the program run ostringstream joybuf; joybuf << Event::LastType; for(const auto& i: myDatabase) { const string& map = i.second.joy ? i.second.joy->getMap() : i.second.mapping; if(map != "") joybuf << "^" << map; } myOSystem.settings().setValue("joymap", joybuf.str()); } stella-5.1.1/src/emucore/FBSurface.cxx000066400000000000000000000232001324334165500175570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "Font.hxx" #include "Rect.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBSurface::FBSurface() : myPixels(nullptr), myPitch(0) { // NOTE: myPixels and myPitch MUST be set in child classes that inherit // from this class // Set default attributes myAttributes.smoothing = false; myAttributes.blending = false; myAttributes.blendalpha = 100; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const { uInt8* src = reinterpret_cast(myPixels + rect.y() * myPitch + rect.x()); if(rect.empty()) memcpy(buffer, src, width() * height() * 4); else { uInt32 w = std::min(rect.width(), width()); uInt32 h = std::min(rect.height(), height()); // Copy 'height' lines of width 'pitch' (in bytes for both) uInt8* dst = buffer; while(h--) { memcpy(dst, src, w * 4); src += myPitch * 4; dst += pitch * 4; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::pixel(uInt32 x, uInt32 y, uInt32 color) { uInt32* buffer = myPixels + y * myPitch + x; *buffer = uInt32(myPalette[color]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::line(uInt32 x, uInt32 y, uInt32 x2, uInt32 y2, uInt32 color) { // draw line using Bresenham algorithm Int32 dx = (x2 - x); Int32 dy = (y2 - y); if(abs(dx) >= abs(dy)) { // x is major axis if(dx < 0) { uInt32 tx = x; x = x2; x2 = tx; uInt32 ty = y; y = y2; y2 = ty; dx = -dx; dy = -dy; } Int32 yd = dy > 0 ? 1 : -1; dy = abs(dy); Int32 err = dx / 2; // now draw the line for(; x <= x2; ++x) { pixel(x, y, color); err -= dy; if(err < 0) { err += dx; y += yd; } } } else { // y is major axis if(dy < 0) { uInt32 tx = x; x = x2; x2 = tx; uInt32 ty = y; y = y2; y2 = ty; dx = -dx; dy = -dy; } Int32 xd = dx > 0 ? 1 : -1; dx = abs(dx); Int32 err = dy / 2; // now draw the line for(; y <= y2; ++y) { pixel(x, y, color); err -= dx; if(err < 0) { err += dy; x += xd; } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color) { uInt32* buffer = myPixels + y * myPitch + x; while(x++ <= x2) *buffer++ = uInt32(myPalette[color]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color) { uInt32* buffer = static_cast(myPixels + y * myPitch + x); while(y++ <= y2) { *buffer = uInt32(myPalette[color]); buffer += myPitch; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color) { while(h--) hLine(x, y+h, x+w-1, color); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::drawChar(const GUI::Font& font, uInt8 chr, uInt32 tx, uInt32 ty, uInt32 color, uInt32 shadowColor) { if(shadowColor != 0) { drawChar(font, chr, tx + 1, ty + 0, shadowColor); drawChar(font, chr, tx + 0, ty + 1, shadowColor); drawChar(font, chr, tx + 1, ty + 1, shadowColor); } const FontDesc& desc = font.desc(); // If this character is not included in the font, use the default char. if(chr < desc.firstchar || chr >= desc.firstchar + desc.size) { if (chr == ' ') return; chr = desc.defaultchar; } chr -= desc.firstchar; // Get the bounding box of the character int bbw, bbh, bbx, bby; if(!desc.bbx) { bbw = desc.fbbw; bbh = desc.fbbh; bbx = desc.fbbx; bby = desc.fbby; } else { bbw = desc.bbx[chr].w; bbh = desc.bbx[chr].h; bbx = desc.bbx[chr].x; bby = desc.bbx[chr].y; } const uInt16* tmp = desc.bits + (desc.offset ? desc.offset[chr] : (chr * desc.fbbh)); uInt32* buffer = myPixels + (ty + desc.ascent - bby - bbh) * myPitch + tx + bbx; for(int y = 0; y < bbh; y++) { const uInt16 ptr = *tmp++; uInt16 mask = 0x8000; for(int x = 0; x < bbw; x++, mask >>= 1) if(ptr & mask) buffer[x] = uInt32(myPalette[color]); buffer += myPitch; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::drawBitmap(uInt32* bitmap, uInt32 tx, uInt32 ty, uInt32 color, uInt32 h) { drawBitmap(bitmap, tx, ty, color, h, h); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::drawBitmap(uInt32* bitmap, uInt32 tx, uInt32 ty, uInt32 color, uInt32 w, uInt32 h) { uInt32* buffer = myPixels + ty * myPitch + tx; for(uInt32 y = 0; y < h; ++y) { uInt32 mask = 1 << (w - 1); for(uInt32 x = 0; x < w; ++x, mask >>= 1) if(bitmap[y] & mask) buffer[x] = uInt32(myPalette[color]); buffer += myPitch; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::drawPixels(uInt32* data, uInt32 tx, uInt32 ty, uInt32 numpixels) { uInt32* buffer = myPixels + ty * myPitch + tx; for(uInt32 i = 0; i < numpixels; ++i) *buffer++ = data[i]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::box(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 colorA, uInt32 colorB) { hLine(x + 1, y, x + w - 2, colorA); hLine(x, y + 1, x + w - 1, colorA); vLine(x, y + 1, y + h - 2, colorA); vLine(x + 1, y, y + h - 1, colorA); hLine(x + 1, y + h - 2, x + w - 1, colorB); hLine(x + 1, y + h - 1, x + w - 2, colorB); vLine(x + w - 1, y + 1, y + h - 2, colorB); vLine(x + w - 2, y + 1, y + h - 1, colorB); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color, FrameStyle style) { switch(style) { case FrameStyle::Solid: hLine(x, y, x + w - 1, color); hLine(x, y + h - 1, x + w - 1, color); vLine(x, y, y + h - 1, color); vLine(x + w - 1, y, y + h - 1, color); break; case FrameStyle::Dashed: uInt32 i, skip, lwidth = 1; #ifndef FLAT_UI for(i = x, skip = 1; i < x+w-1; i=i+lwidth+1, ++skip) { if(skip % 2) { hLine(i, y, i + lwidth, color); hLine(i, y + h - 1, i + lwidth, color); } } for(i = y, skip = 1; i < y+h-1; i=i+lwidth+1, ++skip) { if(skip % 2) { vLine(x, i, i + lwidth, color); vLine(x + w - 1, i, i + lwidth, color); } } #else for(i = x; i < x + w; i += 2) { hLine(i, y, i, color); hLine(i, y + h - 1, i, color); } for(i = y; i < y + h; i += 2) { vLine(x, i, i, color); vLine(x + w - 1, i, i, color); } #endif break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FBSurface::drawString(const GUI::Font& font, const string& s, int x, int y, int w, uInt32 color, TextAlign align, int deltax, bool useEllipsis, uInt32 shadowColor) { const string ELLIPSIS = "\x1d"; // "..." const int leftX = x, rightX = x + w; uInt32 i; int width = font.getStringWidth(s); string str; if(useEllipsis && width > w) { // String is too wide. So we shorten it "intelligently", by replacing // parts of it by an ellipsis ("..."). There are three possibilities // for this: replace the start, the end, or the middle of the string. // What is best really depends on the context; but most applications // replace the end. So we use that too. int w2 = font.getStringWidth(ELLIPSIS); // SLOW algorithm to find the acceptable length. But it is good enough for now. for(i = 0; i < s.size(); ++i) { int charWidth = font.getCharWidth(s[i]); if(w2 + charWidth > w) break; w2 += charWidth; str += s[i]; } str += ELLIPSIS; width = font.getStringWidth(str); } else str = s; if(align == TextAlign::Center) x = x + (w - width - 1)/2; else if(align == TextAlign::Right) x = x + w - width; x += deltax; for(i = 0; i < str.size(); ++i) { w = font.getCharWidth(str[i]); if(x+w > rightX) break; if(x >= leftX) drawChar(font, str[i], x, y, color, shadowColor); x += w; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32* FBSurface::myPalette = nullptr; stella-5.1.1/src/emucore/FBSurface.hxx000066400000000000000000000271621324334165500175770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FBSURFACE_HXX #define FBSURFACE_HXX class FrameBuffer; class TIASurface; namespace GUI { class Font; struct Rect; } #include "FrameBufferConstants.hxx" #include "bspf.hxx" /** This class is basically a thin wrapper around the video toolkit 'surface' structure. We do it this way so the actual video toolkit won't be dragged into the depths of the codebase. All drawing is done into FBSurfaces, which are then drawn into the FrameBuffer. Each FrameBuffer-derived class is responsible for extending an FBSurface object suitable to the FrameBuffer type. @author Stephen Anthony */ class FBSurface { public: FBSurface(); virtual ~FBSurface() = default; /** This method returns the surface pixel pointer and pitch, which are used when one wishes to modify the surface pixels directly. */ inline void basePtr(uInt32*& pixels, uInt32& pitch) const { pixels = myPixels; pitch = myPitch; } /** This method is called to get a copy of the specified ARGB data from the behind-the-scenes surface. @param buffer A copy of the pixel data in ARGB8888 format @param pitch The pitch (in bytes) for the pixel data @param rect The bounding rectangle for the buffer */ void readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const; ////////////////////////////////////////////////////////////////////////// // Note: The drawing primitives below will work, but do not take // advantage of any acceleration whatsoever. The methods are // marked as 'virtual' so that child classes can choose to // implement them more efficiently. ////////////////////////////////////////////////////////////////////////// /** This method should be called to draw a single pixel. @param x The x coordinate @param y The y coordinate @param color The color of the line */ virtual void pixel(uInt32 x, uInt32 y, uInt32 color); /** This method should be called to draw a line. @param x The first x coordinate @param y The first y coordinate @param x2 The second x coordinate @param y2 The second y coordinate @param color The color of the line */ virtual void line(uInt32 x, uInt32 y, uInt32 x2, uInt32 y2, uInt32 color); /** This method should be called to draw a horizontal line. @param x The first x coordinate @param y The y coordinate @param x2 The second x coordinate @param color The color of the line */ virtual void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color); /** This method should be called to draw a vertical line. @param x The x coordinate @param y The first y coordinate @param y2 The second y coordinate @param color The color of the line */ virtual void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color); /** This method should be called to draw a filled rectangle. @param x The x coordinate @param y The y coordinate @param w The width of the area @param h The height of the area @param color The fill color of the rectangle */ virtual void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color); /** This method should be called to draw the specified character. @param font The font to use to draw the character @param c The character to draw @param x The x coordinate @param y The y coordinate @param color The color of the character */ virtual void drawChar(const GUI::Font& font, uInt8 c, uInt32 x, uInt32 y, uInt32 color, uInt32 shadowColor = 0); /** This method should be called to draw the bitmap image. @param bitmap The data to draw @param x The x coordinate @param y The y coordinate @param color The color of the bitmap @param h The height of the data image */ virtual void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color, uInt32 h = 8); /** This method should be called to draw the bitmap image. @param bitmap The data to draw @param x The x coordinate @param y The y coordinate @param color The color of the bitmap @param w The width of the data image @param h The height of the data image */ virtual void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color, uInt32 w, uInt32 h); /** This method should be called to convert and copy a given row of pixel data into a FrameBuffer surface. The pixels must already be in the format used by the surface. @param data The data in uInt8 R/G/B format @param x The destination x-location to start drawing pixels @param y The destination y-location to start drawing pixels @param numpixels The number of pixels to draw */ virtual void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels); /** This method should be called to draw a rectangular box with sides at the specified coordinates. @param x The x coordinate @param y The y coordinate @param w The width of the box @param h The height of the box @param colorA Lighter color for outside line. @param colorB Darker color for inside line. */ virtual void box(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 colorA, uInt32 colorB); /** This method should be called to draw a framed rectangle with several different possible styles. @param x The x coordinate @param y The y coordinate @param w The width of the area @param h The height of the area @param color The color of the surrounding frame @param style The 'FrameStyle' to use for the surrounding frame */ virtual void frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color, FrameStyle style = FrameStyle::Solid); /** This method should be called to draw the specified string. @param font The font to draw the string with @param s The string to draw @param x The x coordinate @param y The y coordinate @param w The width of the string area @param color The color of the text @param align The alignment of the text in the string width area @param deltax FIXME @param useEllipsis Whether to use '...' when the string is too long */ virtual void drawString( const GUI::Font& font, const string& s, int x, int y, int w, uInt32 color, TextAlign align = TextAlign::Left, int deltax = 0, bool useEllipsis = true, uInt32 shadowColor = 0); /** This method should be called to indicate that the surface has been modified, and should be redrawn at the next interval. */ virtual void setDirty() { } ////////////////////////////////////////////////////////////////////////// // Note: The following methods are FBSurface-specific, and must be // implemented in child classes. // // For the following, 'src' indicates the actual data buffer area // (non-scaled) and 'dst' indicates the rendered area (possibly scaled). ////////////////////////////////////////////////////////////////////////// /** These methods answer the current *real* dimensions of the specified surface. */ virtual uInt32 width() const = 0; virtual uInt32 height() const = 0; /** These methods answer the current *rendering* dimensions of the specified surface. */ virtual const GUI::Rect& srcRect() const = 0; virtual const GUI::Rect& dstRect() const = 0; /** These methods set the origin point and width/height for the specified service. They are defined as separate x/y and w/h methods since these items are sometimes set separately. */ virtual void setSrcPos(uInt32 x, uInt32 y) = 0; virtual void setSrcSize(uInt32 w, uInt32 h) = 0; virtual void setDstPos(uInt32 x, uInt32 y) = 0; virtual void setDstSize(uInt32 w, uInt32 h) = 0; /** This method should be called to enable/disable showing the surface (ie, if hidden it will not be drawn under any circumstances. */ virtual void setVisible(bool visible) = 0; /** This method should be called to translate the given coordinates to the (destination) surface coordinates. @param x X coordinate to translate @param y Y coordinate to translate */ virtual void translateCoords(Int32& x, Int32& y) const = 0; /** This method should be called to draw the surface to the screen. It will return true if rendering actually occurred. */ virtual bool render() = 0; /** This method should be called to reset the surface to empty pixels / colour black. */ virtual void invalidate() = 0; /** This method should be called to free any resources being used by the surface. */ virtual void free() = 0; /** This method should be called to reload the surface data/state. It will normally be called after free(). */ virtual void reload() = 0; /** This method should be called to resize the surface to the given dimensions and reload data/state. The surface is not modified if it is larger than the given dimensions. */ virtual void resize(uInt32 width, uInt32 height) = 0; /** The rendering attributes that can be modified for this texture. These probably can only be implemented in child FBSurfaces where the specific functionality actually exists. */ struct Attributes { bool smoothing; // Scaling is smoothed or blocky bool blending; // Blending is enabled uInt32 blendalpha; // Alpha to use in blending mode (0-100%) }; /** Get the currently applied attributes. */ Attributes& attributes() { return myAttributes; } /** The child class chooses which (if any) of the actual attributes can be applied. @param immediate Whether to re-initialize the surface immediately with the new attributes, or wait until manually reloaded */ virtual void applyAttributes(bool immediate = true) = 0; static void setPalette(const uInt32* palette) { myPalette = palette; } protected: static const uInt32* myPalette; uInt32* myPixels; uInt32 myPitch; Attributes myAttributes; private: // Following constructors and assignment operators not supported FBSurface(const FBSurface&) = delete; FBSurface(FBSurface&&) = delete; FBSurface& operator=(const FBSurface&) = delete; FBSurface& operator=(FBSurface&&) = delete; }; #endif stella-5.1.1/src/emucore/FSNode.cxx000066400000000000000000000137221324334165500171050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #include #include "bspf.hxx" #include "FSNodeFactory.hxx" #include "FSNode.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNode::FilesystemNode() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNode::FilesystemNode(AbstractFSNode *realNode) : _realNode(realNode) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNode::FilesystemNode(const string& p) { AbstractFSNode* tmp = nullptr; // Is this potentially a ZIP archive? if(BSPF::containsIgnoreCase(p, ".zip")) tmp = FilesystemNodeFactory::create(p, FilesystemNodeFactory::ZIP); else tmp = FilesystemNodeFactory::create(p, FilesystemNodeFactory::SYSTEM); _realNode = shared_ptr(tmp); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::exists() const { return _realNode ? _realNode->exists() : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::getChildren(FSList& fslist, ListMode mode, bool hidden) const { if (!_realNode || !_realNode->isDirectory()) return false; AbstractFSList tmp; tmp.reserve(fslist.capacity()); if (!_realNode->getChildren(tmp, mode, hidden)) return false; for (const auto& i: tmp) fslist.emplace_back(FilesystemNode(i)); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& FilesystemNode::getName() const { return _realNode->getName(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& FilesystemNode::getPath() const { return _realNode->getPath(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FilesystemNode::getShortPath() const { return _realNode->getShortPath(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FilesystemNode::getNameWithExt(const string& ext) const { size_t pos = _realNode->getName().find_last_of("/\\"); string s = pos == string::npos ? _realNode->getName() : _realNode->getName().substr(pos+1); pos = s.find_last_of("."); return (pos != string::npos) ? s.replace(pos, string::npos, ext) : s + ext; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FilesystemNode::getPathWithExt(const string& ext) const { string s = _realNode->getPath(); size_t pos = s.find_last_of("."); return (pos != string::npos) ? s.replace(pos, string::npos, ext) : s + ext; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FilesystemNode::getShortPathWithExt(const string& ext) const { string s = _realNode->getShortPath(); size_t pos = s.find_last_of("."); return (pos != string::npos) ? s.replace(pos, string::npos, ext) : s + ext; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::hasParent() const { return _realNode ? (_realNode->getParent() != nullptr) : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNode FilesystemNode::getParent() const { if (_realNode == nullptr) return *this; AbstractFSNode* node = _realNode->getParent(); return node ? FilesystemNode(node) : *this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::isDirectory() const { return _realNode ? _realNode->isDirectory() : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::isFile() const { return _realNode ? _realNode->isFile() : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::isReadable() const { return _realNode ? _realNode->isReadable() : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::isWritable() const { return _realNode ? _realNode->isWritable() : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::makeDir() { return (_realNode && !_realNode->exists()) ? _realNode->makeDir() : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNode::rename(const string& newfile) { return (_realNode && _realNode->exists()) ? _realNode->rename(newfile) : false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FilesystemNode::read(BytePtr& image) const { uInt32 size = 0; // First let the private subclass attempt to open the file if((size = _realNode->read(image)) > 0) return size; // File must actually exist if(!(exists() && isReadable())) throw runtime_error("File not found/readable"); // Otherwise, assume the file is either gzip'ed or not compressed at all gzFile f = gzopen(getPath().c_str(), "rb"); if(f) { image = make_unique(512 * 1024); size = gzread(f, image.get(), 512 * 1024); gzclose(f); if(size == 0) throw runtime_error("Zero-byte file"); return size; } else throw runtime_error("ZLIB open/read error"); } stella-5.1.1/src/emucore/FSNode.hxx000066400000000000000000000322171324334165500171120ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef FS_NODE_HXX #define FS_NODE_HXX #include /* * The API described in this header is meant to allow for file system browsing in a * portable fashions. To this ends, multiple or single roots have to be supported * (compare Unix with a single root, Windows with multiple roots C:, D:, ...). * * To this end, we abstract away from paths; implementations can be based on * paths (and it's left to them whether / or \ or : is the path separator :-); * but it is also possible to use inodes or vrefs (MacOS 9) or anything else. * * You may ask now: "isn't this cheating? Why do we go through all this when we use * a path in the end anyway?!?". * Well, for once as long as we don't provide our own file open/read/write API, we * still have to use fopen(). Since all our targets already support fopen(), it should * be possible to get a fopen() compatible string for any file system node. * * Secondly, with this abstraction layer, we still avoid a lot of complications based on * differences in FS roots, different path separators, or even systems with no real * paths (MacOS 9 doesn't even have the notion of a "current directory"). * And if we ever want to support devices with no FS in the classical sense (Palm...), * we can build upon this. */ #include "bspf.hxx" class FilesystemNode; class AbstractFSNode; /** * List of multiple file system nodes. E.g. the contents of a given directory. * This is subclass instead of just a typedef so that we can use forward * declarations of it in other places. */ class FSList : public vector { }; /** * This class acts as a wrapper around the AbstractFSNode class defined * in backends/fs. */ class FilesystemNode { public: /** * Flag to tell listDir() which kind of files to list. */ enum ListMode { kListFilesOnly = 1, kListDirectoriesOnly = 2, kListAll = 3 }; /** * Create a new pathless FilesystemNode. Since there's no path associated * with this node, path-related operations (i.e. exists(), isDirectory(), * getPath()) will always return false or raise an assertion. */ FilesystemNode(); /** * Create a new FilesystemNode referring to the specified path. This is * the counterpart to the path() method. * * If path is empty or equals '~', then a node representing the * "home directory" will be created. If that is not possible (since e.g. the * operating system doesn't support the concept), some other directory is * used (usually the root directory). */ explicit FilesystemNode(const string& path); virtual ~FilesystemNode() = default; /** * Assignment operators. */ FilesystemNode(const FilesystemNode&) = default; FilesystemNode& operator=(const FilesystemNode&) = default; /** * Compare the name of this node to the name of another. Directories * go before normal files. */ inline bool operator<(const FilesystemNode& node) const { if (isDirectory() != node.isDirectory()) return isDirectory(); return BSPF::compareIgnoreCase(getName(), node.getName()) < 0; } /** * Compare the name of this node to the name of another, testing for * equality, */ inline bool operator==(const FilesystemNode& node) const { return BSPF::compareIgnoreCase(getName(), node.getName()) == 0; } /** * By default, the output operator simply outputs the fully-qualified * pathname of the node. */ friend ostream& operator<<(ostream& os, const FilesystemNode& node) { return os << node.getPath(); } /** * Indicates whether the object referred by this path exists in the * filesystem or not. * * @return bool true if the path exists, false otherwise. */ virtual bool exists() const; /** * Return a list of child nodes of this directory node. If called on a node * that does not represent a directory, false is returned. * * @return true if successful, false otherwise (e.g. when the directory * does not exist). */ virtual bool getChildren(FSList &fslist, ListMode mode = kListDirectoriesOnly, bool hidden = false) const; /** * Return a string representation of the name of the file. This is can be * used e.g. by detection code that relies on matching the name of a given * file. But it is *not* suitable for use with fopen / File::open, nor * should it be archived. * * @return the file name */ virtual const string& getName() const; /** * Return a string representation of the file which can be passed to fopen(). * This will usually be a 'path' (hence the name of the method), but can * be anything that fulfills the above criterions. * * @return the 'path' represented by this filesystem node */ virtual const string& getPath() const; /** * Return a string representation of the file which contains the '~' * symbol (if applicable), and is suitable for archiving (i.e. writing * to the config file). * * @return the 'path' represented by this filesystem node */ virtual string getShortPath() const; /** * Determine whether this node has a parent. */ bool hasParent() const; /** * Get the parent node of this node. If this node has no parent node, * then it returns a duplicate of this node. */ FilesystemNode getParent() const; /** * Indicates whether the path refers to a directory or not. */ virtual bool isDirectory() const; /** * Indicates whether the path refers to a real file or not. * * Currently, a symlink or pipe is not considered a file. */ virtual bool isFile() const; /** * Indicates whether the object referred by this path can be read from or not. * * If the path refers to a directory, readability implies being able to read * and list the directory entries. * * If the path refers to a file, readability implies being able to read the * contents of the file. * * @return bool true if the object can be read, false otherwise. */ virtual bool isReadable() const; /** * Indicates whether the object referred by this path can be written to or not. * * If the path refers to a directory, writability implies being able to modify * the directory entry (i.e. rename the directory, remove it or write files * inside of it). * * If the path refers to a file, writability implies being able to write data * to the file. * * @return bool true if the object can be written to, false otherwise. */ virtual bool isWritable() const; /** * Create a directory from the current node path. * * @return bool true if the directory was created, false otherwise. */ virtual bool makeDir(); /** * Rename the current node path with the new given name. * * @return bool true if the node was renamed, false otherwise. */ virtual bool rename(const string& newfile); /** * Read data (binary format) into the given buffer. * * @param buffer The buffer to contain the data. * * @return The number of bytes read (0 in the case of failure) * This method can throw exceptions, and should be used inside * a try-catch block. */ virtual uInt32 read(BytePtr& buffer) const; /** * The following methods are almost exactly the same as the various * getXXXX() methods above. Internally, they call the respective methods * and replace the extension (if present) with the given one. If no * extension is present, the given one is appended instead. */ string getNameWithExt(const string& ext) const; string getPathWithExt(const string& ext) const; string getShortPathWithExt(const string& ext) const; // FIXME - dead code private: shared_ptr _realNode; FilesystemNode(AbstractFSNode* realNode); }; /** * Abstract file system node. Private subclasses implement the actual * functionality. * * Most of the methods correspond directly to methods in class FSNode, * so if they are not documented here, look there for more information about * the semantics. */ using AbstractFSList = vector; class AbstractFSNode { protected: friend class FilesystemNode; using ListMode = FilesystemNode::ListMode; public: /** * Assignment operators. */ AbstractFSNode() = default; AbstractFSNode(const AbstractFSNode&) = default; // AbstractFSNode(AbstractFSNode&&) = default; AbstractFSNode& operator=(const AbstractFSNode&) = default; // AbstractFSNode& operator=(AbstractFSNode&&) = default; virtual ~AbstractFSNode() = default; /* * Indicates whether the object referred by this path exists in the * filesystem or not. */ virtual bool exists() const = 0; /** * Return a list of child nodes of this directory node. If called on a node * that does not represent a directory, false is returned. * * @param list List to put the contents of the directory in. * @param mode Mode to use while listing the directory. * @param hidden Whether to include hidden files or not in the results. * * @return true if successful, false otherwise (e.g. when the directory * does not exist). */ virtual bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const = 0; /** * Returns the last component of the path pointed by this FilesystemNode. * * Examples (POSIX): * /foo/bar.txt would return /bar.txt * /foo/bar/ would return /bar/ * * @note This method is very architecture dependent, please check the concrete * implementation for more information. */ virtual const string& getName() const = 0; /** * Returns the 'path' of the current node, usable in fopen(). */ virtual const string& getPath() const = 0; /** * Returns the 'path' of the current node, containing '~' and for archiving. */ virtual string getShortPath() const = 0; /** * Indicates whether this path refers to a directory or not. */ virtual bool isDirectory() const = 0; /** * Indicates whether this path refers to a real file or not. */ virtual bool isFile() const = 0; /** * Indicates whether the object referred by this path can be read from or not. * * If the path refers to a directory, readability implies being able to read * and list the directory entries. * * If the path refers to a file, readability implies being able to read the * contents of the file. * * @return bool true if the object can be read, false otherwise. */ virtual bool isReadable() const = 0; /** * Indicates whether the object referred by this path can be written to or not. * * If the path refers to a directory, writability implies being able to modify * the directory entry (i.e. rename the directory, remove it or write files * inside of it). * * If the path refers to a file, writability implies being able to write data * to the file. * * @return bool true if the object can be written to, false otherwise. */ virtual bool isWritable() const = 0; /** * Create a directory from the current node path. * * @return bool true if the directory was created, false otherwise. */ virtual bool makeDir() = 0; /** * Rename the current node path with the new given name. * * @return bool true if the node was renamed, false otherwise. */ virtual bool rename(const string& newfile) = 0; /** * Read data (binary format) into the given buffer. * * @param buffer The buffer to containing the data * This will be allocated by the method, and must be * freed by the caller. * @return The number of bytes read (0 in the case of failure) * This method can throw exceptions, and should be used inside * a try-catch block. */ virtual uInt32 read(BytePtr& buffer) const { return 0; } /** * The parent node of this directory. * The parent of the root is the root itself. */ virtual AbstractFSNode* getParent() const = 0; }; #endif stella-5.1.1/src/emucore/FrameBuffer.cxx000066400000000000000000001013401324334165500201450ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Console.hxx" #include "EventHandler.hxx" #include "Event.hxx" #include "Font.hxx" #include "StellaFont.hxx" #include "StellaMediumFont.hxx" #include "StellaLargeFont.hxx" #include "ConsoleFont.hxx" #include "Launcher.hxx" #include "Menu.hxx" #include "CommandMenu.hxx" #include "TimeMachine.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "TIA.hxx" #include "FBSurface.hxx" #include "TIASurface.hxx" #include "FrameBuffer.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::FrameBuffer(OSystem& osystem) : myOSystem(osystem), myInitializedCount(0), myPausedCount(0), myStatsEnabled(false), myLastFrameRate(60), myCurrentModeList(nullptr), myTotalTime(0), myTotalFrames(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::~FrameBuffer() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBuffer::initialize() { // Get desktop resolution and supported renderers queryHardware(myDisplays, myRenderers); uInt32 query_w = myDisplays[0].w, query_h = myDisplays[0].h; // Check the 'maxres' setting, which is an undocumented developer feature // that specifies the desktop size (not normally set) const GUI::Size& s = myOSystem.settings().getSize("maxres"); if(s.valid()) { query_w = s.w; query_h = s.h; } // Various parts of the codebase assume a minimum screen size myDesktopSize.w = std::max(query_w, uInt32(kFBMinW)); myDesktopSize.h = std::max(query_h, uInt32(kFBMinH)); //////////////////////////////////////////////////////////////////// // Create fonts to draw text // NOTE: the logic determining appropriate font sizes is done here, // so that the UI classes can just use the font they expect, // and not worry about it // This logic should also take into account the size of the // framebuffer, and try to be intelligent about font sizes // We can probably add ifdefs to take care of corner cases, // but that means we've failed to abstract it enough ... //////////////////////////////////////////////////////////////////// bool smallScreen = myDesktopSize.w < kFBMinW || myDesktopSize.h < kFBMinH; // This font is used in a variety of situations when a really small // font is needed; we let the specific widget/dialog decide when to // use it mySmallFont = make_unique(GUI::stellaDesc); // The general font used in all UI elements // This is determined by the size of the framebuffer myFont = make_unique(smallScreen ? GUI::stellaDesc : GUI::stellaMediumDesc); // The info font used in all UI elements // This is determined by the size of the framebuffer myInfoFont = make_unique(smallScreen ? GUI::stellaDesc : GUI::consoleDesc); // The font used by the ROM launcher // Normally, this is configurable by the user, except in the case of // very small screens if(!smallScreen) { const string& lf = myOSystem.settings().getString("launcherfont"); if(lf == "small") myLauncherFont = make_unique(GUI::consoleDesc); else if(lf == "medium") myLauncherFont = make_unique(GUI::stellaMediumDesc); else myLauncherFont = make_unique(GUI::stellaLargeDesc); } else myLauncherFont = make_unique(GUI::stellaDesc); // Determine possible TIA windowed zoom levels uInt32 maxZoom = maxWindowSizeForScreen(uInt32(kTIAMinW), uInt32(kTIAMinH), myDesktopSize.w, myDesktopSize.h); // Figure our the smallest zoom level we can use uInt32 firstZoom = smallScreen ? 1 : 2; for(uInt32 zoom = firstZoom; zoom <= maxZoom; ++zoom) { ostringstream desc; desc << "Zoom " << zoom << "x"; VarList::push_back(myTIAZoomLevels, desc.str(), zoom); } // Set palette for GUI (upper area of array, doesn't change during execution) int palID = 0; if(myOSystem.settings().getString("uipalette") == "classic") palID = 1; else if(myOSystem.settings().getString("uipalette") == "light") palID = 2; for(int i = 0, j = 256; i < kNumColors-256; ++i, ++j) { uInt8 r = (ourGUIColors[palID][i] >> 16) & 0xff; uInt8 g = (ourGUIColors[palID][i] >> 8) & 0xff; uInt8 b = ourGUIColors[palID][i] & 0xff; myPalette[j] = mapRGB(r, g, b); } FBSurface::setPalette(myPalette); myGrabMouse = myOSystem.settings().getBool("grabmouse"); // Create a TIA surface; we need it for rendering TIA images myTIASurface = make_unique(myOSystem); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus FrameBuffer::createDisplay(const string& title, uInt32 width, uInt32 height) { myInitializedCount++; myScreenTitle = title; // A 'windowed' system is defined as one where the window size can be // larger than the screen size, as there's some sort of window manager // that takes care of it (all current desktop systems fall in this category) // However, some systems have no concept of windowing, and have hard limits // on how large a window can be (ie, the size of the 'desktop' is the // absolute upper limit on window size) // // If the WINDOWED_SUPPORT macro is defined, we treat the system as the // former type; if not, as the latter type bool useFullscreen = false; #ifdef WINDOWED_SUPPORT // We assume that a desktop of at least minimum acceptable size means that // we're running on a 'large' system, and the window size requirements // can be relaxed // Otherwise, we treat the system as if WINDOWED_SUPPORT is not defined if(myDesktopSize.w < kFBMinW && myDesktopSize.h < kFBMinH && (myDesktopSize.w < width || myDesktopSize.h < height)) return FBInitStatus::FailTooLarge; useFullscreen = myOSystem.settings().getBool("fullscreen"); #else // Make sure this mode is even possible // We only really need to worry about it in non-windowed environments, // where requesting a window that's too large will probably cause a crash if(myDesktopSize.w < width || myDesktopSize.h < height) return FBInitStatus::FailTooLarge; #endif // Set the available video modes for this framebuffer setAvailableVidModes(width, height); // Initialize video subsystem (make sure we get a valid mode) string pre_about = about(); const VideoMode& mode = getSavedVidMode(useFullscreen); if(width <= mode.screen.w && height <= mode.screen.h) { if(setVideoMode(myScreenTitle, mode)) { myImageRect = mode.image; myScreenSize = mode.screen; // Inform TIA surface about new mode if(myOSystem.eventHandler().state() != EventHandlerState::LAUNCHER && myOSystem.eventHandler().state() != EventHandlerState::DEBUGGER) myTIASurface->initialize(myOSystem.console(), mode); // Did we get the requested fullscreen state? myOSystem.settings().setValue("fullscreen", fullScreen()); resetSurfaces(); setCursorState(); } else { myOSystem.logMessage("ERROR: Couldn't initialize video subsystem", 0); return FBInitStatus::FailNotSupported; } } else return FBInitStatus::FailTooLarge; // Erase any messages from a previous run myMsg.counter = 0; // Create surfaces for TIA statistics and general messages myStatsMsg.color = kColorInfo; myStatsMsg.w = font().getMaxCharWidth() * 30 + 3; myStatsMsg.h = (font().getFontHeight() + 2) * 2; if(!myStatsMsg.surface) { myStatsMsg.surface = allocateSurface(myStatsMsg.w, myStatsMsg.h); myStatsMsg.surface->attributes().blending = true; myStatsMsg.surface->attributes().blendalpha = 92; //aligned with TimeMachineDialog myStatsMsg.surface->applyAttributes(); } if(!myMsg.surface) myMsg.surface = allocateSurface(kFBMinW, font().getFontHeight()+10); // Print initial usage message, but only print it later if the status has changed if(myInitializedCount == 1) { myOSystem.logMessage(about(), 1); } else { string post_about = about(); if(post_about != pre_about) myOSystem.logMessage(post_about, 1); } return FBInitStatus::Success; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::update() { // Determine which mode we are in (from the EventHandler) // Take care of S_EMULATE mode here, otherwise let the GUI // figure out what to draw invalidate(); switch(myOSystem.eventHandler().state()) { case EventHandlerState::EMULATION: { // Run the console for one frame // Note that the debugger can cause a breakpoint to occur, which changes // the EventHandler state 'behind our back' - we need to check for that myOSystem.console().tia().update(); #ifdef DEBUGGER_SUPPORT if(myOSystem.eventHandler().state() != EventHandlerState::EMULATION) break; #endif if(myOSystem.eventHandler().frying()) myOSystem.console().fry(); // And update the screen myTIASurface->render(); // Show frame statistics if(myStatsMsg.enabled) drawFrameStats(); else myLastFrameRate = myOSystem.console().getFramerate(); myLastScanlines = myOSystem.console().tia().scanlinesLastFrame(); myPausedCount = 0; break; // EventHandlerState::EMULATION } case EventHandlerState::PAUSE: { myTIASurface->render(); // Show a pause message immediately and then every 7 seconds if (myPausedCount-- <= 0) { myPausedCount = uInt32(7 * myOSystem.frameRate()); showMessage("Paused", MessagePosition::MiddleCenter); } break; // EventHandlerState::PAUSE } case EventHandlerState::OPTIONSMENU: { myTIASurface->render(); myOSystem.menu().draw(true); break; // EventHandlerState::OPTIONSMENU } case EventHandlerState::CMDMENU: { myTIASurface->render(); myOSystem.commandMenu().draw(true); break; // EventHandlerState::CMDMENU } case EventHandlerState::TIMEMACHINE: { myTIASurface->render(); myOSystem.timeMachine().draw(true); break; // EventHandlerState::TIMEMACHINE } case EventHandlerState::LAUNCHER: { myOSystem.launcher().draw(true); break; // EventHandlerState::LAUNCHER } case EventHandlerState::DEBUGGER: { #ifdef DEBUGGER_SUPPORT myOSystem.debugger().draw(true); #endif break; // EventHandlerState::DEBUGGER } case EventHandlerState::NONE: return; } // Draw any pending messages if(myMsg.enabled) drawMessage(); // Do any post-frame stuff postFrameUpdate(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::showMessage(const string& message, MessagePosition position, bool force) { // Only show messages if they've been enabled if(!(force || myOSystem.settings().getBool("uimessages"))) return; // Precompute the message coordinates myMsg.text = message; myMsg.counter = uInt32(myOSystem.frameRate()) << 1; // Show message for 2 seconds myMsg.color = kBtnTextColor; myMsg.w = font().getStringWidth(myMsg.text) + 10; myMsg.h = font().getFontHeight() + 8; myMsg.surface->setSrcSize(myMsg.w, myMsg.h); myMsg.surface->setDstSize(myMsg.w, myMsg.h); myMsg.position = position; myMsg.enabled = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::drawFrameStats() { const ConsoleInfo& info = myOSystem.console().about(); char msg[30]; uInt32 color; const int XPOS = 0, YPOS = 0; int xPos = XPOS; myStatsMsg.surface->invalidate(); myStatsMsg.surface->invalidate(); string bsinfo = info.BankSwitch + (myOSystem.settings().getBool("dev.settings") ? "| Developer" : ""); // draw shadowed text color = myOSystem.console().tia().scanlinesLastFrame() != myLastScanlines ? uInt32(kDbgColorRed) : myStatsMsg.color; std::snprintf(msg, 30, "%3u", myOSystem.console().tia().scanlinesLastFrame()); myStatsMsg.surface->drawString(font(), msg, xPos, YPOS, myStatsMsg.w, color, TextAlign::Left, 0, true, kBGColor); xPos += font().getStringWidth(msg); std::snprintf(msg, 30, " => %s", info.DisplayFormat.c_str()); myStatsMsg.surface->drawString(font(), msg, xPos, YPOS, myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); xPos += font().getStringWidth(msg); // draw the effective framerate float frameRate; const TimingInfo& ti = myOSystem.timingInfo(); // update every ~1 second if(ti.totalFrames - myTotalFrames >= myLastFrameRate) { frameRate = 1000000.0 * (ti.totalFrames - myTotalFrames) / (ti.totalTime - myTotalTime); if(frameRate > myOSystem.console().getFramerate() + 1) frameRate = 1; // check soon again myTotalFrames = ti.totalFrames; myTotalTime = ti.totalTime; } else frameRate = myLastFrameRate; myLastFrameRate = frameRate; std::snprintf(msg, 30, " @%6.2ffps", frameRate); myStatsMsg.surface->drawString(font(), msg, xPos, YPOS, myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); // draw bankswitching type myStatsMsg.surface->drawString(font(), bsinfo, XPOS, YPOS + font().getFontHeight(), myStatsMsg.w, myStatsMsg.color, TextAlign::Left, 0, true, kBGColor); myStatsMsg.surface->setDirty(); myStatsMsg.surface->setDstPos(myImageRect.x() + 10, myImageRect.y() + 8); myStatsMsg.surface->render(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleFrameStats() { showFrameStats(!myStatsEnabled); myOSystem.settings().setValue( myOSystem.settings().getBool("dev.settings") ? "dev.stats" : "plr.stats", myStatsEnabled); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::showFrameStats(bool enable) { myStatsEnabled = myStatsMsg.enabled = enable; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::enableMessages(bool enable) { if(enable) { // Only re-enable frame stats if they were already enabled before myStatsMsg.enabled = myStatsEnabled; } else { // Temporarily disable frame stats myStatsMsg.enabled = false; // Erase old messages on the screen myMsg.enabled = false; myMsg.counter = 0; update(); // Force update immediately } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void FrameBuffer::drawMessage() { // Draw the bounded box and text const GUI::Rect& dst = myMsg.surface->dstRect(); switch(myMsg.position) { case MessagePosition::TopLeft: myMsg.x = 5; myMsg.y = 5; break; case MessagePosition::TopCenter: myMsg.x = (myImageRect.width() - dst.width()) >> 1; myMsg.y = 5; break; case MessagePosition::TopRight: myMsg.x = myImageRect.width() - dst.width() - 5; myMsg.y = 5; break; case MessagePosition::MiddleLeft: myMsg.x = 5; myMsg.y = (myImageRect.height() - dst.height()) >> 1; break; case MessagePosition::MiddleCenter: myMsg.x = (myImageRect.width() - dst.width()) >> 1; myMsg.y = (myImageRect.height() - dst.height()) >> 1; break; case MessagePosition::MiddleRight: myMsg.x = myImageRect.width() - dst.width() - 5; myMsg.y = (myImageRect.height() - dst.height()) >> 1; break; case MessagePosition::BottomLeft: myMsg.x = 5; myMsg.y = myImageRect.height() - dst.height() - 5; break; case MessagePosition::BottomCenter: myMsg.x = (myImageRect.width() - dst.width()) >> 1; myMsg.y = myImageRect.height() - dst.height() - 5; break; case MessagePosition::BottomRight: myMsg.x = myImageRect.width() - dst.width() - 5; myMsg.y = myImageRect.height() - dst.height() - 5; break; } myMsg.surface->setDstPos(myMsg.x + myImageRect.x(), myMsg.y + myImageRect.y()); myMsg.surface->fillRect(1, 1, myMsg.w-2, myMsg.h-2, kBtnColor); #ifndef FLAT_UI myMsg.surface->box(0, 0, myMsg.w, myMsg.h, kColor, kShadowColor); #else myMsg.surface->frameRect(0, 0, myMsg.w, myMsg.h, kColor); #endif myMsg.surface->drawString(font(), myMsg.text, 5, 4, myMsg.w, myMsg.color, TextAlign::Left); // Either erase the entire message (when time is reached), // or show again this frame if(myMsg.counter-- > 0) { myMsg.surface->setDirty(); myMsg.surface->render(); } else myMsg.enabled = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setPauseDelay() { myPausedCount = uInt32(2 * myOSystem.frameRate()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - shared_ptr FrameBuffer::allocateSurface(int w, int h, const uInt32* data) { // Add new surface to the list mySurfaceList.push_back(createSurface(w, h, data)); // And return a pointer to it (pointer should be treated read-only) return mySurfaceList.at(mySurfaceList.size() - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::resetSurfaces() { // Free all resources for each surface, then reload them // Due to possible timing and/or synchronization issues, all free()'s // are done first, then all reload()'s // Any derived FrameBuffer classes that call this method should be // aware of these restrictions, and act accordingly for(auto& s: mySurfaceList) s->free(); for(auto& s: mySurfaceList) s->reload(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setPalette(const uInt32* raw_palette) { // Set palette for normal fill for(int i = 0; i < 256; ++i) { uInt8 r = (raw_palette[i] >> 16) & 0xff; uInt8 g = (raw_palette[i] >> 8) & 0xff; uInt8 b = raw_palette[i] & 0xff; myPalette[i] = mapRGB(r, g, b); } // Let the TIA surface know about the new palette myTIASurface->setPalette(myPalette, raw_palette); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::stateChanged(EventHandlerState state) { // Make sure any onscreen messages are removed myMsg.enabled = false; myMsg.counter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setFullscreen(bool enable) { const VideoMode& mode = getSavedVidMode(enable); if(setVideoMode(myScreenTitle, mode)) { myImageRect = mode.image; myScreenSize = mode.screen; // Inform TIA surface about new mode if(myOSystem.eventHandler().state() != EventHandlerState::LAUNCHER && myOSystem.eventHandler().state() != EventHandlerState::DEBUGGER) myTIASurface->initialize(myOSystem.console(), mode); // Did we get the requested fullscreen state? myOSystem.settings().setValue("fullscreen", fullScreen()); resetSurfaces(); setCursorState(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleFullscreen() { setFullscreen(!fullScreen()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBuffer::changeWindowedVidMode(int direction) { #ifdef WINDOWED_SUPPORT EventHandlerState state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandlerState::DEBUGGER && state != EventHandlerState::LAUNCHER); // Ignore any attempts to change video size while in invalid modes if(!tiaMode || fullScreen()) return false; if(direction == +1) myCurrentModeList->next(); else if(direction == -1) myCurrentModeList->previous(); else return false; const VideoMode& mode = myCurrentModeList->current(); if(setVideoMode(myScreenTitle, mode)) { myImageRect = mode.image; myScreenSize = mode.screen; // Inform TIA surface about new mode myTIASurface->initialize(myOSystem.console(), mode); resetSurfaces(); showMessage(mode.description); myOSystem.settings().setValue("tia.zoom", mode.zoom); return true; } #endif return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setCursorState() { // Always grab mouse in emulation (if enabled) and emulating a controller // that always uses the mouse bool emulation = myOSystem.eventHandler().state() == EventHandlerState::EMULATION; bool analog = myOSystem.hasConsole() ? (myOSystem.eventHandler().controllerIsAnalog(Controller::Left) || myOSystem.eventHandler().controllerIsAnalog(Controller::Right)) : false; bool alwaysUseMouse = BSPF::equalsIgnoreCase("always", myOSystem.settings().getString("usemouse")); grabMouse(emulation && (analog || alwaysUseMouse) && myGrabMouse); // Show/hide cursor in UI/emulation mode based on 'cursor' setting switch(myOSystem.settings().getInt("cursor")) { case 0: showCursor(false); break; case 1: showCursor(emulation); break; case 2: showCursor(!emulation); break; case 3: showCursor(true); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::enableGrabMouse(bool enable) { myGrabMouse = enable; setCursorState(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::toggleGrabMouse() { myGrabMouse = !myGrabMouse; setCursorState(); myOSystem.settings().setValue("grabmouse", myGrabMouse); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBuffer::maxWindowSizeForScreen(uInt32 baseWidth, uInt32 baseHeight, uInt32 screenWidth, uInt32 screenHeight) const { uInt32 multiplier = 1; for(;;) { // Figure out the zoomed size of the window uInt32 width = baseWidth * multiplier; uInt32 height = baseHeight * multiplier; if((width > screenWidth) || (height > screenHeight)) break; ++multiplier; } return multiplier > 1 ? multiplier - 1 : 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight) { myWindowedModeList.clear(); for(auto& mode: myFullscreenModeLists) mode.clear(); for(size_t i = myFullscreenModeLists.size(); i < myDisplays.size(); ++i) myFullscreenModeLists.push_back(VideoModeList()); // Check if zooming is allowed for this state (currently only allowed // for TIA screens) EventHandlerState state = myOSystem.eventHandler().state(); bool tiaMode = (state != EventHandlerState::DEBUGGER && state != EventHandlerState::LAUNCHER); // TIA mode allows zooming at integral factors in windowed modes, // and also non-integral factors in fullscreen mode if(tiaMode) { // TIA windowed modes uInt32 maxZoom = maxWindowSizeForScreen(baseWidth, baseHeight, myDesktopSize.w, myDesktopSize.h); // Aspect ratio bool ntsc = myOSystem.console().about().InitialFrameRate == "60"; uInt32 aspect = myOSystem.settings().getInt(ntsc ? "tia.aspectn" : "tia.aspectp"); // Figure our the smallest zoom level we can use uInt32 firstZoom = 2; if(myDesktopSize.w < kFBMinW || myDesktopSize.h < kFBMinH) firstZoom = 1; for(uInt32 zoom = firstZoom; zoom <= maxZoom; ++zoom) { ostringstream desc; desc << "Zoom " << zoom << "x"; VideoMode mode(baseWidth*zoom, baseHeight*zoom, baseWidth*zoom, baseHeight*zoom, -1, zoom, desc.str()); mode.applyAspectCorrection(aspect); myWindowedModeList.add(mode); } // TIA fullscreen mode for(uInt32 i = 0; i < myDisplays.size(); ++i) { maxZoom = maxWindowSizeForScreen(baseWidth, baseHeight, myDisplays[i].w, myDisplays[i].h); VideoMode mode(baseWidth*maxZoom, baseHeight*maxZoom, myDisplays[i].w, myDisplays[i].h, i); mode.applyAspectCorrection(aspect, myOSystem.settings().getBool("tia.fsfill")); myFullscreenModeLists[i].add(mode); } } else // UI mode { // Windowed and fullscreen mode differ only in screen size myWindowedModeList.add( VideoMode(baseWidth, baseHeight, baseWidth, baseHeight, -1) ); for(uInt32 i = 0; i < myDisplays.size(); ++i) { myFullscreenModeLists[i].add( VideoMode(baseWidth, baseHeight, myDisplays[i].w, myDisplays[i].h, i) ); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const VideoMode& FrameBuffer::getSavedVidMode(bool fullscreen) { EventHandlerState state = myOSystem.eventHandler().state(); if(fullscreen) { Int32 i = getCurrentDisplayIndex(); if(i < 0) { // default to the first display i = 0; } myCurrentModeList = &myFullscreenModeLists[i]; } else myCurrentModeList = &myWindowedModeList; // Now select the best resolution depending on the state // UI modes (launcher and debugger) have only one supported resolution // so the 'current' one is the only valid one if(state == EventHandlerState::DEBUGGER || state == EventHandlerState::LAUNCHER) myCurrentModeList->setZoom(1); else myCurrentModeList->setZoom(myOSystem.settings().getInt("tia.zoom")); return myCurrentModeList->current(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // VideoMode implementation // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoMode::VideoMode() : fsIndex(-1), zoom(1), description("") { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoMode::VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Int32 full, uInt32 z, const string& desc) : fsIndex(full), zoom(z), description(desc) { sw = std::max(sw, uInt32(FrameBuffer::kTIAMinW)); sh = std::max(sh, uInt32(FrameBuffer::kTIAMinH)); iw = std::min(iw, sw); ih = std::min(ih, sh); int ix = (sw - iw) >> 1; int iy = (sh - ih) >> 1; image = GUI::Rect(ix, iy, ix+iw, iy+ih); screen = GUI::Size(sw, sh); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoMode::applyAspectCorrection(uInt32 aspect, bool stretch) { // Width is modified by aspect ratio; other factors may be applied below uInt32 iw = uInt32(float(image.width() * aspect) / 100.0); uInt32 ih = image.height(); if(fsIndex != -1) { // Fullscreen mode stretching float stretchFactor = 1.0; float scaleX = float(iw) / screen.w; float scaleY = float(ih) / screen.h; // Scale to actual or integral factors if(stretch) { // Scale to full (non-integral) available space if(scaleX > scaleY) stretchFactor = float(screen.w) / iw; else stretchFactor = float(screen.h) / ih; } else { // Only scale to an integral amount if(scaleX > scaleY) { int bw = iw / zoom; stretchFactor = float(int(screen.w / bw) * bw) / iw; } else { int bh = ih / zoom; stretchFactor = float(int(screen.h / bh) * bh) / ih; } } iw = uInt32(stretchFactor * iw); ih = uInt32(stretchFactor * ih); } else { // In windowed mode, the screen size changes to match the image width // Height is never modified in this mode screen.w = iw; } // Now re-calculate the dimensions iw = std::min(iw, screen.w); ih = std::min(ih, screen.h); image.moveTo((screen.w - iw) >> 1, (screen.h - ih) >> 1); image.setWidth(iw); image.setHeight(ih); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // // VideoModeList implementation // // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameBuffer::VideoModeList::VideoModeList() : myIdx(-1) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::add(const VideoMode& mode) { myModeList.emplace_back(mode); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::clear() { myModeList.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameBuffer::VideoModeList::empty() const { return myModeList.empty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 FrameBuffer::VideoModeList::size() const { return uInt32(myModeList.size()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::previous() { --myIdx; if(myIdx < 0) myIdx = int(myModeList.size()) - 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const VideoMode& FrameBuffer::VideoModeList::current() const { return myModeList[myIdx]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::next() { myIdx = (myIdx + 1) % myModeList.size(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameBuffer::VideoModeList::setZoom(uInt32 zoom) { for(uInt32 i = 0; i < myModeList.size(); ++i) { if(myModeList[i].zoom == zoom) { myIdx = i; return; } } myIdx = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* Palette is defined as follows: *** Base colors *** kColor Normal foreground color (non-text) kBGColor Normal background color (non-text) kBGColorLo Disabled background color dark (non-text) kBGColorHi Disabled background color light (non-text) kShadowColor Item is disabled *** Text colors *** kTextColor Normal text color kTextColorHi Highlighted text color kTextColorEm Emphasized text color kTextColorSel Color for selected text *** UI elements (dialog and widgets) *** kDlgColor Dialog background kWidColor Widget background kWidFrameColor Border for currently selected widget *** Button colors *** kBtnColor Normal button background kBtnColorHi Highlighted button background kBtnTextColor Normal button font color kBtnTextColorHi Highlighted button font color *** Checkbox colors *** kCheckColor Color of 'X' in checkbox *** Scrollbar colors *** kScrollColor Normal scrollbar color kScrollColorHi Highlighted scrollbar color *** Slider colors *** kSliderColor, kSliderColorHi *** Debugger colors *** kDbgChangedColor Background color for changed cells kDbgChangedTextColor Text color for changed cells kDbgColorHi Highlighted color in debugger data cells kDbgColorRed Red color in debugger *** Info color *** kColorinfo */ uInt32 FrameBuffer::ourGUIColors[3][kNumColors-256] = { // Standard { 0x686868, 0x000000, 0xa38c61, 0xdccfa5, 0x404040, 0x000000, 0x62a108, 0x9f0000, 0x000000, 0xc9af7c, 0xf0f0cf, 0xc80000, 0xac3410, 0xd55941, 0xffffff, 0xffd652, 0xac3410, 0xac3410, 0xd55941, 0xac3410, 0xd55941, 0xc80000, 0x00ff00, 0xc8c8ff, 0xc80000, 0xffffff }, // Classic { 0x686868, 0x000000, 0x404040, 0x404040, 0x404040, 0x20a020, 0x00ff00, 0xc80000, 0x20a020, 0x000000, 0x000000, 0xc80000, 0x000000, 0x000000, 0x20a020, 0x00ff00, 0x20a020, 0x20a020, 0x00ff00, 0x20a020, 0x00ff00, 0xc80000, 0x00ff00, 0xc8c8ff, 0xc80000, 0x20a020 }, // Light { 0x808080, 0x000000, 0xc0c0c0, 0xe1e1e1, 0x333333, // base 0x000000, 0x0078d7, 0x0078d7, 0xffffff, // text 0xf0f0f0, 0xffffff, 0x0f0f0f, // elements 0xe1e1e1, 0xe5f1fb, 0x000000, 0x000000, // buttons 0x333333, // checkbox 0x808080, 0x0078d7, // scrollbar 0x333333, 0x0078d7, // slider 0xffc0c0, 0x000000, 0xe00000, 0xc00000, // debugger 0xffffff // info } }; stella-5.1.1/src/emucore/FrameBuffer.hxx000066400000000000000000000371641324334165500201660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FRAMEBUFFER_HXX #define FRAMEBUFFER_HXX #include class OSystem; class Console; class Settings; class FBSurface; class TIASurface; namespace GUI { class Font; } #include "Rect.hxx" #include "Variant.hxx" #include "TIAConstants.hxx" #include "FrameBufferConstants.hxx" #include "EventHandlerConstants.hxx" #include "bspf.hxx" // Contains all relevant info for the dimensions of a video screen // Also takes care of the case when the image should be 'centered' // within the given screen: // 'image' is the image dimensions into the screen // 'screen' are the dimensions of the screen itself class VideoMode { friend class FrameBuffer; public: GUI::Rect image; GUI::Size screen; Int32 fsIndex; uInt32 zoom; string description; public: VideoMode(); VideoMode(uInt32 iw, uInt32 ih, uInt32 sw, uInt32 sh, Int32 full, uInt32 z = 1, const string& desc = ""); friend ostream& operator<<(ostream& os, const VideoMode& vm) { os << "image=" << vm.image << " screen=" << vm.screen << " full= " << vm.fsIndex << " zoom=" << vm.zoom << " desc=" << vm.description; return os; } private: void applyAspectCorrection(uInt32 aspect, bool stretch = false); }; /** This class encapsulates all video buffers and is the basis for the video display in Stella. All graphics ports should derive from this class for platform-specific video stuff. The TIA is drawn here, and all GUI elements (ala ScummVM, which are drawn into FBSurfaces), are in turn drawn here as well. @author Stephen Anthony */ class FrameBuffer { public: enum { kTIAMinW = 320u, kTIAMinH = TIAConstants::minViewableHeight, kFBMinW = 640u, kFBMinH = 480u }; /** Creates a new Frame Buffer */ FrameBuffer(OSystem& osystem); virtual ~FrameBuffer(); /** Initialize the framebuffer object (set up the underlying hardware) */ bool initialize(); /** (Re)creates the framebuffer display. This must be called before any calls are made to derived methods. @param title The title of the application / window @param width The width of the framebuffer @param height The height of the framebuffer @return Status of initialization (see FBInitStatus 'enum') */ FBInitStatus createDisplay(const string& title, uInt32 width, uInt32 height); /** Updates the display, which depending on the current mode could mean drawing the TIA, any pending menus, etc. */ void update(); /** Shows a message onscreen. @param message The message to be shown @param position Onscreen position for the message @param force Force showing this message, even if messages are disabled */ void showMessage(const string& message, MessagePosition position = MessagePosition::BottomCenter, bool force = false); /** Toggles showing or hiding framerate statistics. */ void toggleFrameStats(); /** Shows a message containing frame statistics for the current frame. */ void showFrameStats(bool enable); /** Enable/disable any pending messages. Disabled messages aren't removed from the message queue; they're just not redrawn into the framebuffer. */ void enableMessages(bool enable); /** Reset 'Paused' display delay counter */ void setPauseDelay(); /** Allocate a new surface. The FrameBuffer class takes all responsibility for freeing this surface (ie, other classes must not delete it directly). @param w The requested width of the new surface. @param h The requested height of the new surface. @param data If non-null, use the given data values as a static surface @return A pointer to a valid surface object, or nullptr. */ shared_ptr allocateSurface(int w, int h, const uInt32* data = nullptr); /** Returns the current dimensions of the framebuffer image. Note that this will take into account the current scaling (if any) as well as image 'centering'. */ const GUI::Rect& imageRect() const { return myImageRect; } /** Returns the current dimensions of the framebuffer window. This is the entire area containing the framebuffer image as well as any 'unusable' area. */ const GUI::Size& screenSize() const { return myScreenSize; } /** Returns the current dimensions of the users' desktop. */ const GUI::Size& desktopSize() const { return myDesktopSize; } /** Get the supported renderers for the video hardware. @return An array of supported renderers */ const VariantList& supportedRenderers() const { return myRenderers; } /** Get the supported TIA zoom levels (windowed mode) for the framebuffer. */ const VariantList& supportedTIAZoomLevels() const { return myTIAZoomLevels; } /** Get the font object(s) of the framebuffer */ const GUI::Font& font() const { return *myFont; } const GUI::Font& infoFont() const { return *myInfoFont; } const GUI::Font& smallFont() const { return *mySmallFont; } const GUI::Font& launcherFont() const { return *myLauncherFont; } /** Get the TIA surface associated with the framebuffer. */ TIASurface& tiaSurface() const { return *myTIASurface; } /** Enables/disables fullscreen mode. */ void setFullscreen(bool enable); /** Toggles between fullscreen and window mode. */ void toggleFullscreen(); /** This method is called when the user wants to switch to the next available windowed video mode. direction = -1 means go to the next lower windowed video mode direction = +1 means go to the next higher windowed video mode @param direction Described above */ bool changeWindowedVidMode(int direction); /** Sets the state of the cursor (hidden or grabbed) based on the current mode. */ void setCursorState(); /** Sets the use of grabmouse. */ void enableGrabMouse(bool enable); /** Toggles the use of grabmouse (only has effect in emulation mode). */ void toggleGrabMouse(); /** Sets the use of grabmouse. */ bool grabMouseEnabled() { return myGrabMouse; } /** Set up the TIA/emulation palette for a screen of any depth > 8. @param raw_palette The array of colors in R/G/B format */ void setPalette(const uInt32* raw_palette); /** Informs the Framebuffer of a change in EventHandler state. */ void stateChanged(EventHandlerState state); ////////////////////////////////////////////////////////////////////// // The following methods are system-specific and can/must be // implemented in derived classes. ////////////////////////////////////////////////////////////////////// public: /** Updates window title @param title The title of the application / window */ virtual void setTitle(const string& title) = 0; /** Shows or hides the cursor based on the given boolean value. */ virtual void showCursor(bool show) = 0; /** Answers if the display is currently in fullscreen mode. */ virtual bool fullScreen() const = 0; /** This method is called to retrieve the R/G/B data from the given pixel. @param pixel The pixel containing R/G/B data @param r The red component of the color @param g The green component of the color @param b The blue component of the color */ virtual void getRGB(uInt32 pixel, uInt8* r, uInt8* g, uInt8* b) const = 0; /** This method is called to map a given R/G/B triple to the screen palette. @param r The red component of the color. @param g The green component of the color. @param b The blue component of the color. */ virtual uInt32 mapRGB(uInt8 r, uInt8 g, uInt8 b) const = 0; /** This method is called to get the specified ARGB data from the viewable FrameBuffer area. Note that this isn't the same as any internal surfaces that may be in use; it should return the actual data as it is currently seen onscreen. @param buffer The actual pixel data in ARGB8888 format @param pitch The pitch (in bytes) for the pixel data @param rect The bounding rectangle for the buffer */ virtual void readPixels(uInt8* buffer, uInt32 pitch, const GUI::Rect& rect) const = 0; /** Clear the framebuffer. */ virtual void clear() = 0; protected: /** This method is called to query and initialize the video hardware for desktop and fullscreen resolution information. */ virtual void queryHardware(vector& mons, VariantList& ren) = 0; virtual Int32 getCurrentDisplayIndex() = 0; /** This method is called to change to the given video mode. @param title The title for the created window @param mode The video mode to use @return False on any errors, else true */ virtual bool setVideoMode(const string& title, const VideoMode& mode) = 0; /** This method is called to invalidate the contents of the entire framebuffer (ie, mark the current content as invalid, and erase it on the next drawing pass). */ virtual void invalidate() = 0; /** This method is called to create a surface with the given attributes. @param w The requested width of the new surface. @param h The requested height of the new surface. @param data If non-null, use the given data values as a static surface */ virtual unique_ptr createSurface(uInt32 w, uInt32 h, const uInt32* data) const = 0; /** Grabs or ungrabs the mouse based on the given boolean value. */ virtual void grabMouse(bool grab) = 0; /** Set the icon for the main window. */ virtual void setWindowIcon() = 0; /** This method is called after any drawing is done (per-frame). */ virtual void postFrameUpdate() = 0; /** This method is called to provide information about the FrameBuffer. */ virtual string about() const = 0; protected: // The parent system for the framebuffer OSystem& myOSystem; // Color palette for TIA and UI modes uInt32 myPalette[256+kNumColors]; private: /** Draw pending messages. */ void drawMessage(); /** Issues a 'free' and 'reload' instruction to all surfaces that the framebuffer knows about. */ void resetSurfaces(); /** Calculate the maximum level by which the base window can be zoomed and still fit in the given screen dimensions. */ uInt32 maxWindowSizeForScreen(uInt32 baseWidth, uInt32 baseHeight, uInt32 screenWidth, uInt32 screenHeight) const; /** Set all possible video modes (both windowed and fullscreen) available for this framebuffer based on given image dimensions and maximum window size. */ void setAvailableVidModes(uInt32 basewidth, uInt32 baseheight); /** Returns an appropriate video mode based on the current eventhandler state, taking into account the maximum size of the window. @param fullscreen Whether to use a windowed or fullscreen mode @return A valid VideoMode for this framebuffer */ const VideoMode& getSavedVidMode(bool fullscreen); private: /** This class implements an iterator around an array of VideoMode objects. */ class VideoModeList { public: VideoModeList(); VideoModeList(const VideoModeList&) = default; VideoModeList& operator=(const VideoModeList&) = default; void add(const VideoMode& mode); void clear(); bool empty() const; uInt32 size() const; void previous(); const VideoMode& current() const; void next(); void setZoom(uInt32 zoom); friend ostream& operator<<(ostream& os, const VideoModeList& l) { for(const auto& vm: l.myModeList) os << "-----\n" << vm << endl << "-----\n"; return os; } private: vector myModeList; int myIdx; }; protected: // Title of the main window/screen string myScreenTitle; private: // Draws the frame stats overlay void drawFrameStats(); // Indicates the number of times the framebuffer was initialized uInt32 myInitializedCount; // Used to set intervals between messages while in pause mode Int32 myPausedCount; // Dimensions of the actual image, after zooming, and taking into account // any image 'centering' GUI::Rect myImageRect; // Dimensions of the main window (not always the same as the image) GUI::Size myScreenSize; // Maximum dimensions of the desktop area GUI::Size myDesktopSize; // The resolution of the attached displays // The primary display is first in the array vector myDisplays; // Supported renderers VariantList myRenderers; // The font object to use for the normal in-game GUI unique_ptr myFont; // The info font object to use for the normal in-game GUI unique_ptr myInfoFont; // The font object to use when space is very limited unique_ptr mySmallFont; // The font object to use for the ROM launcher unique_ptr myLauncherFont; // The TIASurface class takes responsibility for TIA rendering unique_ptr myTIASurface; // Used for onscreen messages and frame statistics // (scanline count and framerate) struct Message { string text; int counter; int x, y, w, h; MessagePosition position; uInt32 color; shared_ptr surface; bool enabled; Message() : counter(0), x(0), y(0), w(0), h(0), color(0), enabled(false) { } }; Message myMsg; Message myStatsMsg; bool myStatsEnabled; uInt32 myLastScanlines; float myLastFrameRate; bool myGrabMouse; // The list of all available video modes for this framebuffer VideoModeList* myCurrentModeList; VideoModeList myWindowedModeList; vector myFullscreenModeLists; // Names of the TIA zoom levels that can be used for this framebuffer VariantList myTIAZoomLevels; // Holds a reference to all the surfaces that have been created vector> mySurfaceList; // Holds UI palette data (standard and classic colours) static uInt32 ourGUIColors[3][kNumColors-256]; uInt64 myTotalTime; uInt64 myTotalFrames; private: // Following constructors and assignment operators not supported FrameBuffer() = delete; FrameBuffer(const FrameBuffer&) = delete; FrameBuffer(FrameBuffer&&) = delete; FrameBuffer& operator=(const FrameBuffer&) = delete; FrameBuffer& operator=(FrameBuffer&&) = delete; }; #endif stella-5.1.1/src/emucore/FrameBufferConstants.hxx000066400000000000000000000035111324334165500220500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FRAMEBUFFER_CONSTANTS_HXX #define FRAMEBUFFER_CONSTANTS_HXX // Return values for initialization of framebuffer window enum class FBInitStatus { Success, FailComplete, FailTooLarge, FailNotSupported }; // Positions for onscreen/overlaid messages enum class MessagePosition { TopLeft, TopCenter, TopRight, MiddleLeft, MiddleCenter, MiddleRight, BottomLeft, BottomCenter, BottomRight }; // TODO - make this 'enum class' // Colors indices to use for the various GUI elements enum { kColor = 256, kBGColor, kBGColorLo, kBGColorHi, kShadowColor, kTextColor, kTextColorHi, kTextColorEm, kTextColorInv, kDlgColor, kWidColor, kWidFrameColor, kBtnColor, kBtnColorHi, kBtnTextColor, kBtnTextColorHi, kCheckColor, kScrollColor, kScrollColorHi, kSliderColor, kSliderColorHi, kDbgChangedColor, kDbgChangedTextColor, kDbgColorHi, kDbgColorRed, kColorInfo, kNumColors }; // Text alignment modes for drawString() enum class TextAlign { Left, Center, Right }; // Line types for drawing rectangular frames enum class FrameStyle { Solid, Dashed }; #endif // FRAMEBUFFER_CONSTANTS_HXX stella-5.1.1/src/emucore/Genesis.cxx000066400000000000000000000076141324334165500173670ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Event.hxx" #include "Genesis.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Genesis::Genesis(Jack jack, const Event& event, const System& system) : Controller(jack, event, system, Controller::Genesis), myControlID(-1) { if(myJack == Left) { myUpEvent = Event::JoystickZeroUp; myDownEvent = Event::JoystickZeroDown; myLeftEvent = Event::JoystickZeroLeft; myRightEvent = Event::JoystickZeroRight; myFire1Event = Event::JoystickZeroFire; myFire2Event = Event::JoystickZeroFire5; } else { myUpEvent = Event::JoystickOneUp; myDownEvent = Event::JoystickOneDown; myLeftEvent = Event::JoystickOneLeft; myRightEvent = Event::JoystickOneRight; myFire1Event = Event::JoystickOneFire; myFire2Event = Event::JoystickOneFire5; } updateAnalogPin(Five, minimumResistance); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Genesis::update() { // Digital events (from keyboard or joystick hats & buttons) myDigitalPinState[One] = (myEvent.get(myUpEvent) == 0); myDigitalPinState[Two] = (myEvent.get(myDownEvent) == 0); myDigitalPinState[Three] = (myEvent.get(myLeftEvent) == 0); myDigitalPinState[Four] = (myEvent.get(myRightEvent) == 0); myDigitalPinState[Six] = (myEvent.get(myFire1Event) == 0); // The Genesis has one more button (C) that can be read by the 2600 // However, it seems to work opposite to the BoosterGrip controller, // in that the logic is inverted updateAnalogPin( Five, (myEvent.get(myFire2Event) == 0) ? minimumResistance : maximumResistance ); // Mouse motion and button events if(myControlID > -1) { // The following code was taken from z26 #define MJ_Threshold 2 int mousex = myEvent.get(Event::MouseAxisXValue), mousey = myEvent.get(Event::MouseAxisYValue); if(mousex || mousey) { if((!(abs(mousey) > abs(mousex) << 1)) && (abs(mousex) >= MJ_Threshold)) { if(mousex < 0) myDigitalPinState[Three] = false; else if (mousex > 0) myDigitalPinState[Four] = false; } if((!(abs(mousex) > abs(mousey) << 1)) && (abs(mousey) >= MJ_Threshold)) { if(mousey < 0) myDigitalPinState[One] = false; else if(mousey > 0) myDigitalPinState[Two] = false; } } // Get mouse button state if(myEvent.get(Event::MouseButtonLeftValue)) myDigitalPinState[Six] = false; if(myEvent.get(Event::MouseButtonRightValue)) updateAnalogPin(Five, maximumResistance); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Genesis::setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { // Currently, the Genesis controller takes full control of the mouse, using // both axes for its two degrees of movement, and the left/right buttons for // 'B' and 'C', respectively if(xtype == Controller::Genesis && ytype == Controller::Genesis && xid == yid) { myControlID = ((myJack == Left && xid == 0) || (myJack == Right && xid == 1) ) ? xid : -1; } else myControlID = -1; return true; } stella-5.1.1/src/emucore/Genesis.hxx000066400000000000000000000060111324334165500173620ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef GENESIS_HXX #define GENESIS_HXX #include "bspf.hxx" #include "Control.hxx" #include "Event.hxx" /** The standard Sega Genesis controller works with the 2600 console for joystick directions and some of the buttons. Button 'B' corresponds to the normal fire button (joy0fire), while button 'C' is read through INPT1 (analog pin 5). @author Stephen Anthony */ class Genesis : public Controller { public: /** Create a new Genesis gamepad plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ Genesis(Jack jack, const Event& event, const System& system); virtual ~Genesis() = default; public: /** Update the entire digital and analog pin state according to the events currently set. */ void update() override; /** Determines how this controller will treat values received from the X/Y axis and left/right buttons of the mouse. Since not all controllers use the mouse the same way (or at all), it's up to the specific class to decide how to use this data. In the current implementation, the left button is tied to the X axis, and the right one tied to the Y axis. @param xtype The controller to use for x-axis data @param xid The controller ID to use for x-axis data (-1 for no id) @param ytype The controller to use for y-axis data @param yid The controller ID to use for y-axis data (-1 for no id) @return Whether the controller supports using the mouse */ bool setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; private: // Pre-compute the events we care about based on given port // This will eliminate test for left or right port in update() Event::Type myUpEvent, myDownEvent, myLeftEvent, myRightEvent, myFire1Event, myFire2Event; // Controller to emulate in normal mouse axis mode int myControlID; private: // Following constructors and assignment operators not supported Genesis() = delete; Genesis(const Genesis&) = delete; Genesis(Genesis&&) = delete; Genesis& operator=(const Genesis&) = delete; Genesis& operator=(Genesis&&) = delete; }; #endif stella-5.1.1/src/emucore/Joystick.cxx000066400000000000000000000110571324334165500175650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Event.hxx" #include "Joystick.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Joystick::Joystick(Jack jack, const Event& event, const System& system) : Controller(jack, event, system, Controller::Joystick), myControlID(-1) { if(myJack == Left) { myUpEvent = Event::JoystickZeroUp; myDownEvent = Event::JoystickZeroDown; myLeftEvent = Event::JoystickZeroLeft; myRightEvent = Event::JoystickZeroRight; myFireEvent = Event::JoystickZeroFire; myXAxisValue = Event::SALeftAxis0Value; myYAxisValue = Event::SALeftAxis1Value; } else { myUpEvent = Event::JoystickOneUp; myDownEvent = Event::JoystickOneDown; myLeftEvent = Event::JoystickOneLeft; myRightEvent = Event::JoystickOneRight; myFireEvent = Event::JoystickOneFire; myXAxisValue = Event::SARightAxis0Value; myYAxisValue = Event::SARightAxis1Value; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Joystick::update() { // Digital events (from keyboard or joystick hats & buttons) myDigitalPinState[One] = (myEvent.get(myUpEvent) == 0); myDigitalPinState[Two] = (myEvent.get(myDownEvent) == 0); myDigitalPinState[Three] = (myEvent.get(myLeftEvent) == 0); myDigitalPinState[Four] = (myEvent.get(myRightEvent) == 0); myDigitalPinState[Six] = (myEvent.get(myFireEvent) == 0); // Axis events (usually generated by the Stelladaptor) int xaxis = myEvent.get(myXAxisValue); int yaxis = myEvent.get(myYAxisValue); if(xaxis > 16384-4096) { myDigitalPinState[Four] = false; // Stelladaptor sends "half moved right" for L+R pushed together if(xaxis < 16384+4096) myDigitalPinState[Three] = false; } else if(xaxis < -16384) myDigitalPinState[Three] = false; if(yaxis > 16384-4096) { myDigitalPinState[Two] = false; // Stelladaptor sends "half moved down" for U+D pushed together if(yaxis < 16384+4096) myDigitalPinState[One] = false; } else if(yaxis < -16384) myDigitalPinState[One] = false; // Mouse motion and button events if(myControlID > -1) { // The following code was taken from z26 #define MJ_Threshold 2 int mousex = myEvent.get(Event::MouseAxisXValue), mousey = myEvent.get(Event::MouseAxisYValue); if(mousex || mousey) { if((!(abs(mousey) > abs(mousex) << 1)) && (abs(mousex) >= MJ_Threshold)) { if(mousex < 0) myDigitalPinState[Three] = false; else if (mousex > 0) myDigitalPinState[Four] = false; } if((!(abs(mousex) > abs(mousey) << 1)) && (abs(mousey) >= MJ_Threshold)) { if(mousey < 0) myDigitalPinState[One] = false; else if(mousey > 0) myDigitalPinState[Two] = false; } } // Get mouse button state if(myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)) myDigitalPinState[Six] = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Joystick::setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { // Currently, the joystick takes full control of the mouse, using both // axes for its two degrees of movement, and both mouse buttons for the // single joystick button if(xtype == Controller::Joystick && ytype == Controller::Joystick && xid == yid) { myControlID = ((myJack == Left && xid == 0) || (myJack == Right && xid == 1) ) ? xid : -1; } else myControlID = -1; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Joystick::setDeadZone(int deadzone) { deadzone = BSPF::clamp(deadzone, 0, 29); _DEAD_ZONE = 3200 + deadzone * 1000; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Joystick::_DEAD_ZONE = 3200; stella-5.1.1/src/emucore/Joystick.hxx000066400000000000000000000062551324334165500175760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef JOYSTICK_HXX #define JOYSTICK_HXX #include "bspf.hxx" #include "Control.hxx" #include "Event.hxx" /** The standard Atari 2600 joystick controller. @author Bradford W. Mott */ class Joystick : public Controller { public: /** Create a new joystick controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ Joystick(Jack jack, const Event& event, const System& system); virtual ~Joystick() = default; public: /** Update the entire digital and analog pin state according to the events currently set. */ void update() override; /** Determines how this controller will treat values received from the X/Y axis and left/right buttons of the mouse. Since not all controllers use the mouse the same way (or at all), it's up to the specific class to decide how to use this data. In the current implementation, the left button is tied to the X axis, and the right one tied to the Y axis. @param xtype The controller to use for x-axis data @param xid The controller ID to use for x-axis data (-1 for no id) @param ytype The controller to use for y-axis data @param yid The controller ID to use for y-axis data (-1 for no id) @return Whether the controller supports using the mouse */ bool setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; /** Sets the deadzone amount for real analog joysticks. Technically, this isn't really used by the Joystick class at all, but it seemed like the best place to put it. */ static void setDeadZone(int deadzone); inline static int deadzone() { return _DEAD_ZONE; } private: // Pre-compute the events we care about based on given port // This will eliminate test for left or right port in update() Event::Type myUpEvent, myDownEvent, myLeftEvent, myRightEvent, myXAxisValue, myYAxisValue, myFireEvent; // Controller to emulate in normal mouse axis mode int myControlID; static int _DEAD_ZONE; private: // Following constructors and assignment operators not supported Joystick() = delete; Joystick(const Joystick&) = delete; Joystick(Joystick&&) = delete; Joystick& operator=(const Joystick&) = delete; Joystick& operator=(Joystick&&) = delete; }; #endif stella-5.1.1/src/emucore/Keyboard.cxx000066400000000000000000000066351324334165500175340ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Event.hxx" #include "Keyboard.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Keyboard::Keyboard(Jack jack, const Event& event, const System& system) : Controller(jack, event, system, Controller::Keyboard) { if(myJack == Left) { myOneEvent = Event::KeyboardZero1; myTwoEvent = Event::KeyboardZero2; myThreeEvent = Event::KeyboardZero3; myFourEvent = Event::KeyboardZero4; myFiveEvent = Event::KeyboardZero5; mySixEvent = Event::KeyboardZero6; mySevenEvent = Event::KeyboardZero7; myEightEvent = Event::KeyboardZero8; myNineEvent = Event::KeyboardZero9; myStarEvent = Event::KeyboardZeroStar; myZeroEvent = Event::KeyboardZero0; myPoundEvent = Event::KeyboardZeroPound; } else { myOneEvent = Event::KeyboardOne1; myTwoEvent = Event::KeyboardOne2; myThreeEvent = Event::KeyboardOne3; myFourEvent = Event::KeyboardOne4; myFiveEvent = Event::KeyboardOne5; mySixEvent = Event::KeyboardOne6; mySevenEvent = Event::KeyboardOne7; myEightEvent = Event::KeyboardOne8; myNineEvent = Event::KeyboardOne9; myStarEvent = Event::KeyboardOneStar; myZeroEvent = Event::KeyboardOne0; myPoundEvent = Event::KeyboardOnePound; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Keyboard::write(DigitalPin pin, bool value) { myDigitalPinState[pin] = value; // Set defaults myDigitalPinState[Six] = true; Int32 resistanceFive = MIN_RESISTANCE; Int32 resistanceNine = MIN_RESISTANCE; // Now scan the rows and columns if(!myDigitalPinState[Four]) { myDigitalPinState[Six] = (myEvent.get(myPoundEvent) == 0); if(myEvent.get(myZeroEvent) != 0) resistanceFive = maximumResistance; if(myEvent.get(myStarEvent) != 0) resistanceNine = maximumResistance; } if(!myDigitalPinState[Three]) { myDigitalPinState[Six] = (myEvent.get(myNineEvent) == 0); if(myEvent.get(myEightEvent) != 0) resistanceFive = maximumResistance; if(myEvent.get(mySevenEvent) != 0) resistanceNine = maximumResistance; } if(!myDigitalPinState[Two]) { myDigitalPinState[Six] = (myEvent.get(mySixEvent) == 0); if(myEvent.get(myFiveEvent) != 0) resistanceFive = maximumResistance; if(myEvent.get(myFourEvent) != 0) resistanceNine = maximumResistance; } if(!myDigitalPinState[One]) { myDigitalPinState[Six] = (myEvent.get(myThreeEvent) == 0); if(myEvent.get(myTwoEvent) != 0) resistanceFive = maximumResistance; if(myEvent.get(myOneEvent) != 0) resistanceNine = maximumResistance; } if (resistanceFive != read(Five)) { updateAnalogPin(Five, resistanceFive); } if (resistanceNine != read(Nine)) updateAnalogPin(Nine, resistanceNine); } stella-5.1.1/src/emucore/Keyboard.hxx000066400000000000000000000047311324334165500175340ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef KEYBOARD_HXX #define KEYBOARD_HXX #include "bspf.hxx" #include "Control.hxx" #include "Event.hxx" /** The standard Atari 2600 keyboard controller @author Bradford W. Mott */ class Keyboard : public Controller { public: /** Create a new keyboard controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ Keyboard(Jack jack, const Event& event, const System& system); virtual ~Keyboard() = default; public: /** Write the given value to the specified digital pin for this controller. Writing is only allowed to the pins associated with the PIA. Therefore you cannot write to pin six. @param pin The pin of the controller jack to write to @param value The value to write to the pin */ void write(DigitalPin pin, bool value) override; /** Update the entire digital and analog pin state according to the events currently set. */ void update() override { } private: // Pre-compute the events we care about based on given port // This will eliminate test for left or right port in update() Event::Type myOneEvent, myTwoEvent, myThreeEvent, myFourEvent, myFiveEvent, mySixEvent, mySevenEvent, myEightEvent, myNineEvent, myStarEvent, myZeroEvent, myPoundEvent; static constexpr Int32 MIN_RESISTANCE = 5600; private: // Following constructors and assignment operators not supported Keyboard() = delete; Keyboard(const Keyboard&) = delete; Keyboard(Keyboard&&) = delete; Keyboard& operator=(const Keyboard&) = delete; Keyboard& operator=(Keyboard&&) = delete; }; #endif stella-5.1.1/src/emucore/KidVid.cxx000066400000000000000000000323041324334165500171360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "Event.hxx" #include "KidVid.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - KidVid::KidVid(Jack jack, const Event& event, const System& system, const string& rommd5) : Controller(jack, event, system, Controller::KidVid), myEnabled(myJack == Right), mySampleFile(nullptr), mySharedSampleFile(nullptr), myFileOpened(false), myTapeBusy(false), myFilePointer(0), mySongCounter(0), myBeep(false), mySharedData(false), mySampleByte(0), myGame(0), myTape(0), myIdx(0), myBlock(0), myBlockIdx(0) { // Right now, there are only two games that use the KidVid if(rommd5 == "ee6665683ebdb539e89ba620981cb0f6") myGame = KVBBEARS; // Berenstain Bears else if(rommd5 == "a204cd4fb1944c86e800120706512a64") myGame = KVSMURFS; // Smurfs Save the Day else myEnabled = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - KidVid::~KidVid() { closeSampleFile(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KidVid::update() { if(!myEnabled) return; if(myEvent.get(Event::ConsoleReset)) { myTape = 0; // rewind Kid Vid tape closeSampleFile(); } if(myEvent.get(Event::KeyboardZero1)) { myTape = 2; myIdx = myGame == KVBBEARS ? KVBLOCKBITS : 0; myBlockIdx = KVBLOCKBITS; myBlock = 0; openSampleFile(); cerr << "myTape = " << myTape << endl; } else if(myEvent.get(Event::KeyboardZero2)) { myTape = 3; myIdx = myGame == KVBBEARS ? KVBLOCKBITS : 0; myBlockIdx = KVBLOCKBITS; myBlock = 0; openSampleFile(); cerr << "myTape = " << myTape << endl; } else if(myEvent.get(Event::KeyboardZero3)) { if(myGame == KVBBEARS) /* Berenstain Bears ? */ { myTape = 4; myIdx = KVBLOCKBITS; cerr << "myTape = " << myTape << endl; } else /* no, Smurf Save The Day */ { myTape = 1; myIdx = 0; cerr << "myTape = " << myTape << endl; } myBlockIdx = KVBLOCKBITS; myBlock = 0; openSampleFile(); } // Convert separate pin states into a 'register' uInt8 IOPortA = 0xf0; if(myDigitalPinState[One]) IOPortA |= 0x01; if(myDigitalPinState[Two]) IOPortA |= 0x02; if(myDigitalPinState[Three]) IOPortA |= 0x04; if(myDigitalPinState[Four]) IOPortA |= 0x08; // Is the tape running? if((myTape != 0) && ((IOPortA & 0x01) == 0x01) && !myTapeBusy) { IOPortA = (IOPortA & 0xf7) | (((ourKVData[myIdx >> 3] << (myIdx & 0x07)) & 0x80) >> 4); // increase to next bit myIdx++; myBlockIdx--; // increase to next block (byte) if(myBlockIdx == 0) { if(myBlock == 0) myIdx = ((myTape * 6) + 12 - KVBLOCKS) * 8; //KVData00-KVData=12 else { if(myGame == KVSMURFS) { if(myBlock >= ourKVBlocks[myTape - 1]) myIdx = 42 * 8; //KVData80-KVData=42 else { myIdx = 36 * 8;//KVPause-KVData=36 setNextSong(); } } else { if(myBlock >= ourKVBlocks[myTape + 2 - 1]) myIdx = 42 * 8; //KVData80-KVData=42 else { myIdx = 36 * 8;//KVPause-KVData=36 setNextSong(); } } } myBlock++; myBlockIdx = KVBLOCKBITS; } } // Now convert the register back into separate boolean values myDigitalPinState[One] = IOPortA & 0x01; myDigitalPinState[Two] = IOPortA & 0x02; myDigitalPinState[Three] = IOPortA & 0x04; myDigitalPinState[Four] = IOPortA & 0x08; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KidVid::openSampleFile() { static const char* const kvNameTable[6] = { "kvs3.wav", "kvs1.wav", "kvs2.wav", "kvb3.wav", "kvb1.wav", "kvb2.wav" }; static uInt32 StartSong[6] = { 44+38, 0, 44, 44+38+42+62+80, 44+38+42, 44+38+42+62 }; if(!myEnabled) return; if(!myFileOpened) { int i = myGame == KVSMURFS ? 0 : 3; i += myTape - 1; if(myTape == 4) i -= 3; mySampleFile = fopen(kvNameTable[i], "rb"); if(mySampleFile != nullptr) { cerr << "opened file: " << kvNameTable[i] << endl; mySharedSampleFile = fopen("kvshared.wav", "rb"); if(mySharedSampleFile == nullptr) { fclose(mySampleFile); myFileOpened = false; } else { cerr << "opened file: " << "kvshared.wav" << endl; // fseek(mySampleFile, 45, SEEK_SET); myFileOpened = true; } } else myFileOpened = false; mySongCounter = 0; myTapeBusy = false; myFilePointer = StartSong[i]; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KidVid::closeSampleFile() { if(myFileOpened) { fclose(mySampleFile); fclose(mySharedSampleFile); myFileOpened = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KidVid::setNextSong() { if(myFileOpened) { myBeep = (ourSongPositions[myFilePointer] & 0x80) ? false : true; uInt8 temp = ourSongPositions[myFilePointer] & 0x7f; mySharedData = (temp < 10); mySongCounter = ourSongStart[temp+1] - ourSongStart[temp]; #if 0 if(mySharedData) ; // fseek(mySharedSampleFile, ourSongStart[temp], SEEK_SET); else ; // fseek(mySampleFile, ourSongStart[temp], SEEK_SET); #endif myFilePointer++; myTapeBusy = true; } else { myBeep = true; myTapeBusy = true; mySongCounter = 80*262; /* delay needed for Harmony without tape */ } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void KidVid::getNextSampleByte() { // static int oddeven = 0; if(mySongCounter == 0) mySampleByte = 0x80; #if 0 else { oddeven = oddeven^1; if(oddeven & 1) { mySongCounter--; myTapeBusy = (mySongCounter > 262*48) || !myBeep; if(myFileOpened) { if(mySharedData) mySampleByte = getc(mySharedSampleFile); else mySampleByte = getc(mySampleFile); } else mySampleByte = 0x80; if(!myBeep && (mySongCounter == 0)) setNextSong(); } } #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8 KidVid::ourKVBlocks[6] = { 2+40, 2+21, 2+35, /* Smurfs tapes 3, 1, 2 */ 42+60, 42+78, 42+60 /* BBears tapes 1, 2, 3 (40 extra blocks for intro) */ }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8 KidVid::ourKVData[6*8] = { /* KVData44 */ 0x7b, // 0111 1011b ; (1)0 0x1e, // 0001 1110b ; 1 0xc6, // 1100 0110b ; 00 0x31, // 0011 0001b ; 01 0xec, // 1110 1100b ; 0 0x60, // 0110 0000b ; 0+ /* KVData48 */ 0x7b, // 0111 1011b ; (1)0 0x1e, // 0001 1110b ; 1 0xc6, // 1100 0110b ; 00 0x3d, // 0011 1101b ; 10 0x8c, // 1000 1100b ; 0 0x60, // 0110 0000b ; 0+ /* KVData00 */ 0xf6, // 1111 0110b 0x31, // 0011 0001b 0x8c, // 1000 1100b 0x63, // 0110 0011b 0x18, // 0001 1000b 0xc0, // 1100 0000b /* KVData01 */ 0xf6, // 1111 0110b 0x31, // 0011 0001b 0x8c, // 1000 1100b 0x63, // 0110 0011b 0x18, // 0001 1000b 0xf0, // 1111 0000b /* KVData02 */ 0xf6, // 1111 0110b 0x31, // 0011 0001b 0x8c, // 1000 1100b 0x63, // 0110 0011b 0x1e, // 0001 1110b 0xc0, // 1100 0000b /* KVData03 */ 0xf6, // 1111 0110b 0x31, // 0011 0001b 0x8c, // 1000 1100b 0x63, // 0110 0011b 0x1e, // 0001 1110b 0xf0, // 1111 0000b /* KVPause */ 0x3f, // 0011 1111b 0xf0, // 1111 0000b 0x00, // 0000 0000b 0x00, // 0000 0000b 0x00, // 0000 0000b 0x00, // 0000 0000b /* KVData80 */ 0xf7, // 1111 0111b ; marks end of tape (green/yellow screen) 0xb1, // 1011 0001b 0x8c, // 1000 1100b 0x63, // 0110 0011b 0x18, // 0001 1000b 0xc0 // 1100 0000b }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8 KidVid::ourSongPositions[44+38+42+62+80+62] = { /* kvs1 44 */ 11, 12+0x80, 13+0x80, 14, 15+0x80, 16, 8+0x80, 17, 18+0x80, 19, 20+0x80, 21, 8+0x80, 22, 15+0x80, 23, 18+0x80, 14, 20+0x80, 16, 18+0x80, 17, 15+0x80, 19, 8+0x80, 21, 20+0x80, 22, 18+0x80, 23, 15+0x80, 14, 20+0x80, 16, 8+0x80, 22, 15+0x80, 23, 18+0x80, 14, 20+0x80, 16, 8+0x80, 9, /* kvs2 38 */ 25+0x80, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30, 26, 27, 28, 8, 29, 30+0x80, 9, /* kvs3 42 */ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 34, 42, 36, 43, 40, 39, 38, 37, 34, 43, 36, 39, 40, 37, 38, 43, 34, 37, 36, 43, 40, 39, 38, 37, 34, 43, 36, 39, 40, 37, 38+0x80, 9, /* kvb1 62 */ 0, 1, 45, 2, 3, 46, 4, 5, 47, 6, 7, 48, 4, 3, 49, 2, 1, 50, 6, 7, 51, 4, 5, 52, 6, 1, 53, 2, 7, 54, 6, 5, 45, 2, 1, 46, 4, 3, 47, 2, 5, 48, 4, 7, 49, 6, 1, 50, 2, 5, 51, 6, 3, 52, 4, 7, 53, 2, 1, 54, 6+0x80, 9, /* kvb2 80 */ 0, 1, 56, 4, 3, 57, 2, 5, 58, 6, 7, 59, 2, 3, 60, 4, 1, 61, 6, 7, 62, 2, 5, 63, 6, 1, 64, 4, 7, 65, 6, 5, 66, 4, 1, 67, 2, 3, 68, 6, 5, 69, 2, 7, 70, 4, 1, 71, 2, 5, 72, 4, 3, 73, 6, 7, 74, 2, 1, 75, 6, 3, 76, 4, 5, 77, 6, 7, 78, 2, 3, 79, 4, 1, 80, 2, 7, 81, 4+0x80, 9, /* kvb3 62 */ 0, 1, 83, 2, 3, 84, 4, 5, 85, 6, 7, 86, 4, 3, 87, 2, 1, 88, 6, 7, 89, 2, 5, 90, 6, 1, 91, 4, 7, 92, 6, 5, 93, 4, 1, 94, 2, 3, 95, 6, 5, 96, 2, 7, 97, 4, 1, 98, 6, 5, 99, 4, 3, 100, 2, 7, 101, 4, 1, 102, 2+0x80, 9 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt32 KidVid::ourSongStart[104] = { /* kvshared */ 44, /* Welcome + intro Berenstain Bears */ 980829, /* boulders in the road */ 1178398, /* standing ovations */ 1430063, /* brother bear */ 1691136, /* good work */ 1841665, /* crossing a bridge */ 2100386, /* not bad (applause) */ 2283843, /* ourgame */ 2629588, /* start the parade */ 2824805, /* rewind */ 3059116, /* kvs1 */ 44, /* Harmony into 1 */ 164685, /* falling notes (into 2) */ 395182, /* instructions */ 750335, /* high notes are high */ 962016, /* my hat's off to you */ 1204273, /* 1 2 3 do re mi */ 1538258, /* Harmony */ 1801683, /* concratulations (all of the Smurfs voted) */ 2086276, /* line or space */ 2399093, /* hooray */ 2589606, /* hear yeeh */ 2801287, /* over the river */ 3111752, /* musical deduction */ 3436329, /* kvs2 */ 44, /* Handy intro + instructions */ 778557, /* place in shape */ 1100782, /* sailor mate + whistle */ // 1281887, 1293648, /* attention */ 1493569, /* colours */ 1801682, /* congratulations (Handy and friends voted) */ 2086275, /* kvs3 */ 44, /* Greedy and Clumsy intro + instructions */ 686829, /* red */ 893806, /* don't count your chicken */ 1143119, /* yellow */ 1385376, /* thank you */ 1578241, /* mixin' and matchin' */ 1942802, /* fun / colour shake */ 2168595, /* colours can be usefull */ 2493172, /* hip hip horay */ 2662517, /* green */ 3022374, /* purple */ 3229351, /* white */ 3720920, /* kvb1 */ 44, /* 3 */ 592749, /* 5 */ 936142, /* 2 */ 1465343, /* 4 */ 1787568, /* 1 */ 2145073, /* 7 */ 2568434, /* 9 */ 2822451, /* 8 */ 3045892, /* 6 */ 3709157, /* 0 */ 4219542, /* kvb2 */ 44, /* A */ 303453, /* B */ 703294, /* C */ 1150175, /* D */ 1514736, /* E */ 2208577, /* F */ 2511986, /* G */ 2864787, /* H */ 3306964, /* I */ 3864389, /* J */ 4148982, /* K */ 4499431, /* L */ 4824008, /* M */ 5162697, /* N */ 5581354, /* O */ 5844779, /* P */ 6162300, /* Q */ 6590365, /* R */ 6839678, /* S */ 7225407, /* T */ 7552336, /* U */ 7867505, /* V */ 8316738, /* W */ 8608387, /* X */ 8940020, /* Y */ 9274005, /* Z */ 9593878, /* kvb3 */ 44, /* cat */ 341085, /* one */ 653902, /* red */ 1018463, /* two */ 1265424, /* dog */ 1669969, /* six */ 1919282, /* hat */ 2227395, /* ten */ 2535508, /* mom */ 3057653, /* dad */ 3375174, /* ball */ 3704455, /* fish */ 4092536, /* nine */ 4487673, /* bear */ 5026282, /* four */ 5416715, /* bird */ 5670732, /* tree */ 6225805, /* rock */ 6736190, /* book */ 7110159, /* road */ 7676992 }; stella-5.1.1/src/emucore/KidVid.hxx000066400000000000000000000063611324334165500171470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef KIDVID_HXX #define KIDVID_HXX #include class Event; #include "bspf.hxx" #include "Control.hxx" /** The KidVid Voice Module, created by Coleco. This class emulates the KVVM cassette player by mixing WAV data into the sound stream. The WAV files are located at: http://www.atariage.com/2600/archives/KidVidAudio/index.html This code was heavily borrowed from z26. @author Stephen Anthony & z26 team */ class KidVid : public Controller { public: /** Create a new KidVid controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller @param md5sum The md5 of the ROM using this controller */ KidVid(Jack jack, const Event& event, const System& system, const string& md5sum); virtual ~KidVid(); public: /** Update the entire digital and analog pin state according to the events currently set. */ void update() override; private: // Open/close a WAV sample file void openSampleFile(); void closeSampleFile(); // Jump to next song in the sequence void setNextSong(); // Generate next sample byte // TODO - rework this, perhaps send directly to sound class void getNextSampleByte(); private: enum { KVSMURFS = 0x44, KVBBEARS = 0x48, KVBLOCKS = 6, /* number of bytes / block */ KVBLOCKBITS = KVBLOCKS*8 /* number of bits / block */ }; // Whether the KidVid device is enabled (only for games that it // supports, and if it's plugged into the right port bool myEnabled; // The file handles for the WAV files FILE *mySampleFile, *mySharedSampleFile; // Indicates if sample files have been successfully opened bool myFileOpened; // Is the tape currently 'busy' / in use? bool myTapeBusy; uInt32 myFilePointer, mySongCounter; bool myBeep, mySharedData; uInt8 mySampleByte; uInt32 myGame, myTape; uInt32 myIdx, myBlock, myBlockIdx; // Number of blocks and data on tape static const uInt8 ourKVBlocks[6]; static const uInt8 ourKVData[6*8]; static const uInt8 ourSongPositions[44+38+42+62+80+62]; static const uInt32 ourSongStart[104]; private: // Following constructors and assignment operators not supported KidVid() = delete; KidVid(const KidVid&) = delete; KidVid(KidVid&&) = delete; KidVid& operator=(const KidVid&) = delete; KidVid& operator=(KidVid&&) = delete; }; #endif stella-5.1.1/src/emucore/M6502.cxx000066400000000000000000000442171324334165500165030ustar00rootroot00000000000000//============================================================================ // // MM MM 6666 555555 0000 2222 // MMMM MMMM 66 66 55 00 00 22 22 // MM MMM MM 66 55 00 00 22 // MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator" // MM MM 66 66 55 00 00 22 // MM MM 66 66 55 55 00 00 22 // MM MM 6666 5555 0000 222222 // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #include "Expression.hxx" #include "CartDebug.hxx" #include "PackedBitArray.hxx" #include "TIA.hxx" #include "Base.hxx" #include "M6532.hxx" // Flags for disassembly types #define DISASM_CODE CartDebug::CODE // #define DISASM_GFX CartDebug::GFX // TODO - uncomment when needed // #define DISASM_PGFX CartDebug::PGFX // TODO - uncomment when needed #define DISASM_DATA CartDebug::DATA // #define DISASM_ROW CartDebug::ROW // TODO - uncomment when needed #define DISASM_WRITE CartDebug::WRITE #define DISASM_NONE 0 #else // Flags for disassembly types #define DISASM_CODE 0 // #define DISASM_GFX 0 // TODO - uncomment when needed // #define DISASM_PGFX 0 // TODO - uncomment when needed #define DISASM_DATA 0 // #define DISASM_ROW 0 // TODO - uncomment when needed #define DISASM_NONE 0 #define DISASM_WRITE 0 #endif #include "Settings.hxx" #include "Vec.hxx" #include "System.hxx" #include "M6502.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6502::M6502(const Settings& settings) : myExecutionStatus(0), mySystem(nullptr), mySettings(settings), A(0), X(0), Y(0), SP(0), IR(0), PC(0), N(false), V(false), B(false), D(false), I(false), notZ(false), C(false), icycles(0), myNumberOfDistinctAccesses(0), myLastAddress(0), myLastPeekAddress(0), myLastPokeAddress(0), myLastPeekBaseAddress(0), myLastPokeBaseAddress(0), myLastSrcAddressS(-1), myLastSrcAddressA(-1), myLastSrcAddressX(-1), myLastSrcAddressY(-1), myDataAddressForPoke(0), myOnHaltCallback(nullptr), myHaltRequested(false), myGhostReadsTrap(true), myStepStateByInstruction(false) { #ifdef DEBUGGER_SUPPORT myDebugger = nullptr; myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::install(System& system) { // Remember which system I'm installed in mySystem = &system; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::reset() { // Clear the execution status flags myExecutionStatus = 0; // Set registers to random or default values bool devSettings = mySettings.getBool("dev.settings"); const string& cpurandom = mySettings.getString(devSettings ? "dev.cpurandom" : "plr.cpurandom"); SP = BSPF::containsIgnoreCase(cpurandom, "S") ? mySystem->randGenerator().next() : 0xfd; A = BSPF::containsIgnoreCase(cpurandom, "A") ? mySystem->randGenerator().next() : 0x00; X = BSPF::containsIgnoreCase(cpurandom, "X") ? mySystem->randGenerator().next() : 0x00; Y = BSPF::containsIgnoreCase(cpurandom, "Y") ? mySystem->randGenerator().next() : 0x00; PS(BSPF::containsIgnoreCase(cpurandom, "P") ? mySystem->randGenerator().next() : 0x20); icycles = 0; // Load PC from the reset vector PC = uInt16(mySystem->peek(0xfffc)) | (uInt16(mySystem->peek(0xfffd)) << 8); myLastAddress = myLastPeekAddress = myLastPokeAddress = myLastPeekBaseAddress = myLastPokeBaseAddress; myLastSrcAddressS = myLastSrcAddressA = myLastSrcAddressX = myLastSrcAddressY = -1; myDataAddressForPoke = 0; myHaltRequested = false; myGhostReadsTrap = mySettings.getBool("dbg.ghostreadstrap"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline uInt8 M6502::peek(uInt16 address, uInt8 flags) { handleHalt(); //////////////////////////////////////////////// // TODO - move this logic directly into CartAR if(address != myLastAddress) { myNumberOfDistinctAccesses++; myLastAddress = address; } //////////////////////////////////////////////// mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU); icycles += SYSTEM_CYCLES_PER_CPU; uInt8 result = mySystem->peek(address, flags); myLastPeekAddress = address; #ifdef DEBUGGER_SUPPORT if(myReadTraps.isInitialized() && myReadTraps.isSet(address) && (myGhostReadsTrap || flags != DISASM_NONE)) { myLastPeekBaseAddress = myDebugger->getBaseAddress(myLastPeekAddress, true); // mirror handling int cond = evalCondTraps(); if(cond > -1) { myJustHitReadTrapFlag = true; stringstream msg; msg << "RTrap" << (flags == DISASM_NONE ? "G[" : "[") << Common::Base::HEX2 << cond << "]" << (myTrapCondNames[cond].empty() ? ": " : "If: {" + myTrapCondNames[cond] + "} "); myHitTrapInfo.message = msg.str(); myHitTrapInfo.address = address; } } #endif // DEBUGGER_SUPPORT return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void M6502::poke(uInt16 address, uInt8 value, uInt8 flags) { //////////////////////////////////////////////// // TODO - move this logic directly into CartAR if(address != myLastAddress) { myNumberOfDistinctAccesses++; myLastAddress = address; } //////////////////////////////////////////////// mySystem->incrementCycles(SYSTEM_CYCLES_PER_CPU); icycles += SYSTEM_CYCLES_PER_CPU; mySystem->poke(address, value, flags); myLastPokeAddress = address; #ifdef DEBUGGER_SUPPORT if(myWriteTraps.isInitialized() && myWriteTraps.isSet(address)) { myLastPokeBaseAddress = myDebugger->getBaseAddress(myLastPokeAddress, false); // mirror handling int cond = evalCondTraps(); if(cond > -1) { myJustHitWriteTrapFlag = true; stringstream msg; msg << "WTrap[" << Common::Base::HEX2 << cond << "]" << (myTrapCondNames[cond].empty() ? ": " : "If: {" + myTrapCondNames[cond] + "} "); myHitTrapInfo.message = msg.str(); myHitTrapInfo.address = address; } } #endif // DEBUGGER_SUPPORT } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::requestHalt() { if (!myOnHaltCallback) throw runtime_error("onHaltCallback not configured"); myHaltRequested = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void M6502::handleHalt() { if (myHaltRequested) { myOnHaltCallback(); myHaltRequested = false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::updateStepStateByInstruction() { // Currently only used in debugger mode #ifdef DEBUGGER_SUPPORT myStepStateByInstruction = myCondBreaks.size() || myCondSaveStates.size() || myTrapConds.size(); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6502::execute(uInt32 number) { const bool status = _execute(number); #ifdef DEBUGGER_SUPPORT // Debugger hack: this ensures that stepping a "STA WSYNC" will actually end at the // beginning of the next line (otherwise, the next instruction would be stepped in order for // the halt to take effect). This is safe because as we know that the next cycle will be a read // cycle anyway. handleHalt(); // Make sure that the hardware state matches the current system clock. This is necessary // to maintain a consistent state for the debugger after stepping. mySystem->tia().updateEmulation(); mySystem->m6532().updateEmulation(); #endif return status; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline bool M6502::_execute(uInt32 number) { // Clear all of the execution status bits except for the fatal error bit myExecutionStatus &= FatalErrorBit; #ifdef DEBUGGER_SUPPORT TIA& tia = mySystem->tia(); M6532& riot = mySystem->m6532(); #endif // Loop until execution is stopped or a fatal error occurs for(;;) { for(; !myExecutionStatus && (number != 0); --number) { #ifdef DEBUGGER_SUPPORT if(myJustHitReadTrapFlag || myJustHitWriteTrapFlag) { bool read = myJustHitReadTrapFlag; myJustHitReadTrapFlag = myJustHitWriteTrapFlag = false; if(myDebugger && myDebugger->start(myHitTrapInfo.message, myHitTrapInfo.address, read)) { return true; } } if(myBreakPoints.isInitialized() && myBreakPoints.isSet(PC)) if(myDebugger && myDebugger->start("BP: ", PC)) return true; int cond = evalCondBreaks(); if(cond > -1) { stringstream msg; msg << "CBP[" << Common::Base::HEX2 << cond << "]: " << myCondBreakNames[cond]; if(myDebugger && myDebugger->start(msg.str())) return true; } cond = evalCondSaveStates(); if(cond > -1) { stringstream msg; msg << "conditional savestate [" << Common::Base::HEX2 << cond << "]"; myDebugger->addState(msg.str()); } #endif // DEBUGGER_SUPPORT uInt16 operandAddress = 0, intermediateAddress = 0; uInt8 operand = 0; // Reset the peek/poke address pointers myLastPeekAddress = myLastPokeAddress = myDataAddressForPoke = 0; icycles = 0; // Fetch instruction at the program counter IR = peek(PC++, DISASM_CODE); // This address represents a code section // Call code to execute the instruction switch(IR) { // 6502 instruction emulation is generated by an M4 macro file #include "M6502.ins" default: // Oops, illegal instruction executed so set fatal error flag myExecutionStatus |= FatalErrorBit; } #ifdef DEBUGGER_SUPPORT if(myStepStateByInstruction) { // Check out M6502::execute for an explanation. handleHalt(); tia.updateEmulation(); riot.updateEmulation(); } #endif } // See if we need to handle an interrupt if((myExecutionStatus & MaskableInterruptBit) || (myExecutionStatus & NonmaskableInterruptBit)) { // Yes, so handle the interrupt interruptHandler(); } // See if execution has been stopped if(myExecutionStatus & StopExecutionBit) { // Yes, so answer that everything finished fine return true; } // See if a fatal error has occured if(myExecutionStatus & FatalErrorBit) { // Yes, so answer that something when wrong return false; } // See if we've executed the specified number of instructions if(number == 0) { // Yes, so answer that everything finished fine return true; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::interruptHandler() { // Handle the interrupt if((myExecutionStatus & MaskableInterruptBit) && !I) { mySystem->incrementCycles(7 * SYSTEM_CYCLES_PER_CPU); mySystem->poke(0x0100 + SP--, (PC - 1) >> 8); mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff); mySystem->poke(0x0100 + SP--, PS() & (~0x10)); D = false; I = true; PC = uInt16(mySystem->peek(0xFFFE)) | (uInt16(mySystem->peek(0xFFFF)) << 8); } else if(myExecutionStatus & NonmaskableInterruptBit) { mySystem->incrementCycles(7 * SYSTEM_CYCLES_PER_CPU); mySystem->poke(0x0100 + SP--, (PC - 1) >> 8); mySystem->poke(0x0100 + SP--, (PC - 1) & 0x00ff); mySystem->poke(0x0100 + SP--, PS() & (~0x10)); D = false; PC = uInt16(mySystem->peek(0xFFFA)) | (uInt16(mySystem->peek(0xFFFB)) << 8); } // Clear the interrupt bits in myExecutionStatus myExecutionStatus &= ~(MaskableInterruptBit | NonmaskableInterruptBit); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6502::save(Serializer& out) const { const string& CPU = name(); try { out.putString(CPU); out.putByte(A); // Accumulator out.putByte(X); // X index register out.putByte(Y); // Y index register out.putByte(SP); // Stack Pointer out.putByte(IR); // Instruction register out.putShort(PC); // Program Counter out.putBool(N); // N flag for processor status register out.putBool(V); // V flag for processor status register out.putBool(B); // B flag for processor status register out.putBool(D); // D flag for processor status register out.putBool(I); // I flag for processor status register out.putBool(notZ); // Z flag complement for processor status register out.putBool(C); // C flag for processor status register out.putByte(myExecutionStatus); // Indicates the number of distinct memory accesses out.putInt(myNumberOfDistinctAccesses); // Indicates the last address(es) which was accessed out.putShort(myLastAddress); out.putShort(myLastPeekAddress); out.putShort(myLastPokeAddress); out.putShort(myDataAddressForPoke); out.putInt(myLastSrcAddressS); out.putInt(myLastSrcAddressA); out.putInt(myLastSrcAddressX); out.putInt(myLastSrcAddressY); out.putBool(myHaltRequested); out.putBool(myStepStateByInstruction); out.putBool(myGhostReadsTrap); } catch(...) { cerr << "ERROR: M6502::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6502::load(Serializer& in) { const string& CPU = name(); try { if(in.getString() != CPU) return false; A = in.getByte(); // Accumulator X = in.getByte(); // X index register Y = in.getByte(); // Y index register SP = in.getByte(); // Stack Pointer IR = in.getByte(); // Instruction register PC = in.getShort(); // Program Counter N = in.getBool(); // N flag for processor status register V = in.getBool(); // V flag for processor status register B = in.getBool(); // B flag for processor status register D = in.getBool(); // D flag for processor status register I = in.getBool(); // I flag for processor status register notZ = in.getBool(); // Z flag complement for processor status register C = in.getBool(); // C flag for processor status register myExecutionStatus = in.getByte(); // Indicates the number of distinct memory accesses myNumberOfDistinctAccesses = in.getInt(); // Indicates the last address(es) which was accessed myLastAddress = in.getShort(); myLastPeekAddress = in.getShort(); myLastPokeAddress = in.getShort(); myDataAddressForPoke = in.getShort(); myLastSrcAddressS = in.getInt(); myLastSrcAddressA = in.getInt(); myLastSrcAddressX = in.getInt(); myLastSrcAddressY = in.getInt(); myHaltRequested = in.getBool(); myStepStateByInstruction = in.getBool(); myGhostReadsTrap = in.getBool(); } catch(...) { cerr << "ERROR: M6502::load" << endl; return false; } return true; } #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::attach(Debugger& debugger) { // Remember the debugger for this microprocessor myDebugger = &debugger; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 M6502::addCondBreak(Expression* e, const string& name) { myCondBreaks.emplace_back(e); myCondBreakNames.push_back(name); updateStepStateByInstruction(); return uInt32(myCondBreaks.size() - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6502::delCondBreak(uInt32 idx) { if(idx < myCondBreaks.size()) { Vec::removeAt(myCondBreaks, idx); Vec::removeAt(myCondBreakNames, idx); updateStepStateByInstruction(); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::clearCondBreaks() { myCondBreaks.clear(); myCondBreakNames.clear(); updateStepStateByInstruction(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const StringList& M6502::getCondBreakNames() const { return myCondBreakNames; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 M6502::addCondSaveState(Expression* e, const string& name) { myCondSaveStates.emplace_back(e); myCondSaveStateNames.push_back(name); updateStepStateByInstruction(); return uInt32(myCondSaveStates.size() - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6502::delCondSaveState(uInt32 idx) { if(idx < myCondSaveStates.size()) { Vec::removeAt(myCondSaveStates, idx); Vec::removeAt(myCondSaveStateNames, idx); updateStepStateByInstruction(); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::clearCondSaveStates() { myCondSaveStates.clear(); myCondSaveStateNames.clear(); updateStepStateByInstruction(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const StringList& M6502::getCondSaveStateNames() const { return myCondSaveStateNames; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 M6502::addCondTrap(Expression* e, const string& name) { myTrapConds.emplace_back(e); myTrapCondNames.push_back(name); updateStepStateByInstruction(); return uInt32(myTrapConds.size() - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6502::delCondTrap(uInt32 brk) { if(brk < myTrapConds.size()) { Vec::removeAt(myTrapConds, brk); Vec::removeAt(myTrapCondNames, brk); updateStepStateByInstruction(); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6502::clearCondTraps() { myTrapConds.clear(); myTrapCondNames.clear(); updateStepStateByInstruction(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const StringList& M6502::getCondTrapNames() const { return myTrapCondNames; } #endif // DEBUGGER_SUPPORT stella-5.1.1/src/emucore/M6502.hxx000066400000000000000000000342631324334165500165100ustar00rootroot00000000000000//============================================================================ // // MM MM 6666 555555 0000 2222 // MMMM MMMM 66 66 55 00 00 22 22 // MM MMM MM 66 55 00 00 22 // MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator" // MM MM 66 66 55 00 00 22 // MM MM 66 66 55 55 00 00 22 // MM MM 6666 5555 0000 222222 // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef M6502_HXX #define M6502_HXX #include class Settings; class System; #ifdef DEBUGGER_SUPPORT class Debugger; class CpuDebug; #include "Expression.hxx" #include "PackedBitArray.hxx" #include "TrapArray.hxx" #endif #include "bspf.hxx" #include "Serializable.hxx" /** The 6502 is an 8-bit microprocessor that has a 64K addressing space. This class provides a high compatibility 6502 microprocessor emulator. The memory accesses and cycle counts it generates are valid at the sub-instruction level and "false" reads are generated (such as the ones produced by the Indirect,X addressing when it crosses a page boundary). This provides provides better compatibility for hardware that has side effects and for games which are very time sensitive. @author Bradford W. Mott */ class M6502 : public Serializable { // The 6502 and Cart debugger classes are friends who need special access friend class CartDebug; friend class CpuDebug; public: using onHaltCallback = std::function; public: /** Create a new 6502 microprocessor. */ M6502(const Settings& settings); virtual ~M6502() = default; public: /** Install the processor in the specified system. Invoked by the system when the processor is attached to it. @param system The system the processor should install itself in */ void install(System& system); /** Reset the processor to its power-on state. This method should not be invoked until the entire 6502 system is constructed and installed since it involves reading the reset vector from memory. */ void reset(); /** Request a maskable interrupt */ void irq() { myExecutionStatus |= MaskableInterruptBit; } /** Request a non-maskable interrupt */ void nmi() { myExecutionStatus |= NonmaskableInterruptBit; } /** Set the callback for handling a halt condition */ void setOnHaltCallback(onHaltCallback callback) { myOnHaltCallback = callback; } /** RDY pulled low --- halt on next read. */ void requestHalt(); /** Pull RDY high again before the callback was triggered. */ void clearHaltRequest() { myHaltRequested = false; } /** Execute instructions until the specified number of instructions is executed, someone stops execution, or an error occurs. Answers true iff execution stops normally. @param number Indicates the number of instructions to execute @return true iff execution stops normally */ bool execute(uInt32 number); /** Tell the processor to stop executing instructions. Invoking this method while the processor is executing instructions will stop execution as soon as possible. */ void stop() { myExecutionStatus |= StopExecutionBit; } /** Answer true iff a fatal error has occured from which the processor cannot recover (i.e. illegal instruction, etc.) @return true iff a fatal error has occured */ bool fatalError() const { return myExecutionStatus & FatalErrorBit; } /** Get the 16-bit value of the Program Counter register. @return The program counter register */ uInt16 getPC() const { return PC; } /** Return the last address that was part of a read/peek. Note that reads which are part of a write are not considered here, unless they're not the same as the last write address. This eliminates accesses that are part of a normal read/write cycle. @return The address of the last read */ uInt16 lastReadAddress() const { return myLastPokeAddress ? (myLastPokeAddress != myLastPeekAddress ? myLastPeekAddress : 0) : myLastPeekAddress; } /** Return the last address that was part of a read/peek. @return The address of the last read */ uInt16 lastReadBaseAddress() const { return myLastPeekBaseAddress; } /** Return the last address that was part of a write/poke. @return The address of the last write */ uInt16 lastWriteBaseAddress() const { return myLastPokeBaseAddress; } /** Return the source of the address that was used for a write/poke. Note that this isn't the same as the address that is poked, but is instead the address of the *data* that is poked (if any). @return The address of the data used in the last poke, else 0 */ uInt16 lastDataAddressForPoke() const { return myDataAddressForPoke; } /** Return the last data address used as part of a peek operation for the S/A/X/Y registers. Note that if an address wasn't used (as in immediate mode), then the address is -1. @return The address of the data used in the last peek, else -1 */ Int32 lastSrcAddressS() const { return myLastSrcAddressS; } Int32 lastSrcAddressA() const { return myLastSrcAddressA; } Int32 lastSrcAddressX() const { return myLastSrcAddressX; } Int32 lastSrcAddressY() const { return myLastSrcAddressY; } /** Get the number of memory accesses to distinct memory locations @return The number of memory accesses to distinct memory locations */ uInt32 distinctAccesses() const { return myNumberOfDistinctAccesses; } /** Saves the current state of this device to the given Serializer. @param out The serializer device to save to. @return The result of the save. True on success, false on failure. */ bool save(Serializer& out) const override; /** Loads the current state of this device from the given Serializer. @param in The Serializer device to load from. @return The result of the load. True on success, false on failure. */ bool load(Serializer& in) override; /** Get a null terminated string which is the processor's name (i.e. "M6532") @return The name of the device */ string name() const override { return "M6502"; } #ifdef DEBUGGER_SUPPORT public: // Attach the specified debugger. void attach(Debugger& debugger); PackedBitArray& breakPoints() { return myBreakPoints; } TrapArray& readTraps() { return myReadTraps; } TrapArray& writeTraps() { return myWriteTraps; } // methods for 'breakif' handling uInt32 addCondBreak(Expression* e, const string& name); bool delCondBreak(uInt32 idx); void clearCondBreaks(); const StringList& getCondBreakNames() const; // methods for 'savestateif' handling uInt32 addCondSaveState(Expression* e, const string& name); bool delCondSaveState(uInt32 idx); void clearCondSaveStates(); const StringList& getCondSaveStateNames() const; // methods for 'trapif' handling uInt32 addCondTrap(Expression* e, const string& name); bool delCondTrap(uInt32 brk); void clearCondTraps(); const StringList& getCondTrapNames() const; void setGhostReadsTrap(bool enable) { myGhostReadsTrap = enable; } #endif // DEBUGGER_SUPPORT private: /** Get the byte at the specified address and update the cycle count. Addresses marked as code are hints to the debugger/disassembler to conclusively determine code sections, even if the disassembler cannot find them itself. @param address The address from which the value should be loaded @param flags Indicates that this address has the given flags for type of access (CODE, DATA, GFX, etc) @return The byte at the specified address */ uInt8 peek(uInt16 address, uInt8 flags); /** Change the byte at the specified address to the given value and update the cycle count. @param address The address where the value should be stored @param value The value to be stored at the address */ void poke(uInt16 address, uInt8 value, uInt8 flags = 0); /** Get the 8-bit value of the Processor Status register. @return The processor status register */ uInt8 PS() const { uInt8 ps = 0x20; if(N) ps |= 0x80; if(V) ps |= 0x40; if(B) ps |= 0x10; if(D) ps |= 0x08; if(I) ps |= 0x04; if(!notZ) ps |= 0x02; if(C) ps |= 0x01; return ps; } /** Change the Processor Status register to correspond to the given value. @param ps The value to set the processor status register to */ void PS(uInt8 ps) { N = ps & 0x80; V = ps & 0x40; B = true; // B = ps & 0x10; The 6507's B flag always true D = ps & 0x08; I = ps & 0x04; notZ = !(ps & 0x02); C = ps & 0x01; } /** Called after an interrupt has be requested using irq() or nmi() */ void interruptHandler(); /** Check whether halt was requested (RDY low) and notify */ void handleHalt(); /** Check whether we are required to update hardware (TIA + RIOT) in lockstep with the CPU and update the flag accordingly. */ void updateStepStateByInstruction(); /** This is the actual dispatch function that does the grunt work. M6502::execute wraps it and makes sure that any pending halt is processed before returning. */ bool _execute(uInt32 number); private: /** Bit fields used to indicate that certain conditions need to be handled such as stopping execution, fatal errors, maskable interrupts and non-maskable interrupts (in myExecutionStatus) */ enum { StopExecutionBit = 0x01, FatalErrorBit = 0x02, MaskableInterruptBit = 0x04, NonmaskableInterruptBit = 0x08 }; uInt8 myExecutionStatus; /// Pointer to the system the processor is installed in or the null pointer System* mySystem; /// Reference to the settings const Settings& mySettings; uInt8 A; // Accumulator uInt8 X; // X index register uInt8 Y; // Y index register uInt8 SP; // Stack Pointer uInt8 IR; // Instruction register uInt16 PC; // Program Counter bool N; // N flag for processor status register bool V; // V flag for processor status register bool B; // B flag for processor status register bool D; // D flag for processor status register bool I; // I flag for processor status register bool notZ; // Z flag complement for processor status register bool C; // C flag for processor status register uInt8 icycles; // cycles of last instruction /// Indicates the numer of distinct memory accesses uInt32 myNumberOfDistinctAccesses; /// Indicates the last address which was accessed uInt16 myLastAddress; /// Indicates the last address which was accessed specifically /// by a peek or poke command uInt16 myLastPeekAddress, myLastPokeAddress; /// Indicates the last base (= non-mirrored) address which was /// accessed specifically by a peek or poke command uInt16 myLastPeekBaseAddress, myLastPokeBaseAddress; /// Indicates the last address used to access data by a peek command /// for the CPU registers (S/A/X/Y) Int32 myLastSrcAddressS, myLastSrcAddressA, myLastSrcAddressX, myLastSrcAddressY; /// Indicates the data address used by the last command that performed /// a poke (currently, the last address used by STx) /// If an address wasn't used (ie, as in immediate mode), the address /// is set to zero uInt16 myDataAddressForPoke; /// Indicates the number of system cycles per processor cycle static constexpr uInt32 SYSTEM_CYCLES_PER_CPU = 1; /// Called when the processor enters halt state onHaltCallback myOnHaltCallback; /// Indicates whether RDY was pulled low bool myHaltRequested; #ifdef DEBUGGER_SUPPORT enum CondAction { breakAction, saveStateAction }; Int32 evalCondBreaks() { for(uInt32 i = 0; i < myCondBreaks.size(); i++) if(myCondBreaks[i]->evaluate()) return i; return -1; // no break hit } Int32 evalCondSaveStates() { for(uInt32 i = 0; i < myCondSaveStates.size(); i++) if(myCondSaveStates[i]->evaluate()) return i; return -1; // no save state point hit } Int32 evalCondTraps() { for(uInt32 i = 0; i < myTrapConds.size(); i++) if(myTrapConds[i]->evaluate()) return i; return -1; // no trapif hit } /// Pointer to the debugger for this processor or the null pointer Debugger* myDebugger; // Addresses for which the specified action should occur PackedBitArray myBreakPoints;// , myReadTraps, myWriteTraps, myReadTrapIfs, myWriteTrapIfs; TrapArray myReadTraps, myWriteTraps; // Did we just now hit a trap? bool myJustHitReadTrapFlag; bool myJustHitWriteTrapFlag; struct HitTrapInfo { string message; int address; }; HitTrapInfo myHitTrapInfo; vector> myCondBreaks; StringList myCondBreakNames; vector> myCondSaveStates; StringList myCondSaveStateNames; vector> myTrapConds; StringList myTrapCondNames; #endif // DEBUGGER_SUPPORT // These are both used only by the debugger, but since they're included // in save states, they cannot be conditionally compiled bool myGhostReadsTrap; // trap on ghost reads bool myStepStateByInstruction; private: // Following constructors and assignment operators not supported M6502() = delete; M6502(const M6502&) = delete; M6502(M6502&&) = delete; M6502& operator=(const M6502&) = delete; M6502& operator=(M6502&&) = delete; }; #endif stella-5.1.1/src/emucore/M6502.ins000066400000000000000000002641611324334165500164740ustar00rootroot00000000000000//============================================================================ // // MM MM 6666 555555 0000 2222 // MMMM MMMM 66 66 55 00 00 22 22 // MM MMM MM 66 55 00 00 22 // MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator" // MM MM 66 66 55 00 00 22 // MM MM 66 66 55 55 00 00 22 // MM MM 6666 5555 0000 222222 // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ /** Code and cases to emulate each of the 6502 instructions. Recompile with the following: 'm4 M6502.m4 > M6502.ins' @author Bradford W. Mott and Stephen Anthony */ #ifndef NOTSAMEPAGE #define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00) #endif #ifndef SET_LAST_PEEK #ifdef DEBUGGER_SUPPORT #define SET_LAST_PEEK(_addr1, _addr2) _addr1 = _addr2; #else #define SET_LAST_PEEK(_addr1, _addr2) #endif #endif #ifndef CLEAR_LAST_PEEK #ifdef DEBUGGER_SUPPORT #define CLEAR_LAST_PEEK(_addr) _addr = -1; #else #define CLEAR_LAST_PEEK(_addr) #endif #endif #ifndef SET_LAST_POKE #ifdef DEBUGGER_SUPPORT #define SET_LAST_POKE(_addr) myDataAddressForPoke = _addr; #else #define SET_LAST_POKE(_addr) #endif #endif ////////////////////////////////////////////////// // ADC case 0x69: { operand = peek(PC++, DISASM_CODE); } { if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x65: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x75: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } { if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x6d: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x7d: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x79: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x61: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x71: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; ////////////////////////////////////////////////// // ASR case 0x4b: { operand = peek(PC++, DISASM_CODE); } { A &= operand; // Set carry flag according to the right-most bit C = A & 0x01; A = (A >> 1) & 0x7f; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // ANC case 0x0b: case 0x2b: { operand = peek(PC++, DISASM_CODE); } { A &= operand; notZ = A; N = A & 0x80; C = N; } break; ////////////////////////////////////////////////// // AND case 0x29: { operand = peek(PC++, DISASM_CODE); } { A &= operand; notZ = A; N = A & 0x80; } break; case 0x25: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { A &= operand; notZ = A; N = A & 0x80; } break; case 0x35: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } { A &= operand; notZ = A; N = A & 0x80; } break; case 0x2d: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { A &= operand; notZ = A; N = A & 0x80; } break; case 0x3d: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { A &= operand; notZ = A; N = A & 0x80; } break; case 0x39: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { A &= operand; notZ = A; N = A & 0x80; } break; case 0x21: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { A &= operand; notZ = A; N = A & 0x80; } break; case 0x31: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { A &= operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // ANE case 0x8b: { operand = peek(PC++, DISASM_CODE); } { // NOTE: The implementation of this instruction is based on // information from the 64doc.txt file. This instruction is // reported to be unstable! A = (A | 0xee) & X & operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // ARR case 0x6b: { operand = peek(PC++, DISASM_CODE); } { // NOTE: The implementation of this instruction is based on // information from the 64doc.txt file. There are mixed // reports on its operation! if(!D) { A &= operand; A = ((A >> 1) & 0x7f) | (C ? 0x80 : 0x00); C = A & 0x40; V = (A & 0x40) ^ ((A & 0x20) << 1); notZ = A; N = A & 0x80; } else { uInt8 value = A & operand; A = ((value >> 1) & 0x7f) | (C ? 0x80 : 0x00); N = C; notZ = A; V = (value ^ A) & 0x40; if(((value & 0x0f) + (value & 0x01)) > 0x05) { A = (A & 0xf0) | ((A + 0x06) & 0x0f); } if(((value & 0xf0) + (value & 0x10)) > 0x50) { A = (A + 0x60) & 0xff; C = 1; } else { C = 0; } } } break; ////////////////////////////////////////////////// // ASL case 0x0a: { peek(PC, DISASM_NONE); } { // Set carry flag according to the left-most bit in A C = A & 0x80; A <<= 1; notZ = A; N = A & 0x80; } break; case 0x06: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x16: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x0e: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x1e: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; ////////////////////////////////////////////////// // BIT case 0x24: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { notZ = (A & operand); N = operand & 0x80; V = operand & 0x40; } break; case 0x2C: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { notZ = (A & operand); N = operand & 0x80; V = operand & 0x40; } break; ////////////////////////////////////////////////// // Branches case 0x90: { operand = peek(PC++, DISASM_CODE); } { if(!C) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } } break; case 0xb0: { operand = peek(PC++, DISASM_CODE); } { if(C) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } } break; case 0xf0: { operand = peek(PC++, DISASM_CODE); } { if(!notZ) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } } break; case 0x30: { operand = peek(PC++, DISASM_CODE); } { if(N) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } } break; case 0xD0: { operand = peek(PC++, DISASM_CODE); } { if(notZ) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } } break; case 0x10: { operand = peek(PC++, DISASM_CODE); } { if(!N) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } } break; case 0x50: { operand = peek(PC++, DISASM_CODE); } { if(!V) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } } break; case 0x70: { operand = peek(PC++, DISASM_CODE); } { if(V) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } } break; ////////////////////////////////////////////////// // BRK case 0x00: { peek(PC++, DISASM_NONE); B = true; poke(0x0100 + SP--, PC >> 8, DISASM_WRITE); poke(0x0100 + SP--, PC & 0x00ff, DISASM_WRITE); poke(0x0100 + SP--, PS(), DISASM_WRITE); I = true; PC = peek(0xfffe, DISASM_DATA); PC |= (uInt16(peek(0xffff, DISASM_DATA)) << 8); } break; ////////////////////////////////////////////////// // CLC case 0x18: { peek(PC, DISASM_NONE); } { C = false; } break; ////////////////////////////////////////////////// // CLD case 0xd8: { peek(PC, DISASM_NONE); } { D = false; } break; ////////////////////////////////////////////////// // CLI case 0x58: { peek(PC, DISASM_NONE); } { I = false; } break; ////////////////////////////////////////////////// // CLV case 0xb8: { peek(PC, DISASM_NONE); } { V = false; } break; ////////////////////////////////////////////////// // CMP case 0xc9: { operand = peek(PC++, DISASM_CODE); } { uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xc5: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xd5: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } { uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xcd: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xdd: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xd9: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xc1: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xd1: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; ////////////////////////////////////////////////// // CPX case 0xe0: { operand = peek(PC++, DISASM_CODE); } { uInt16 value = uInt16(X) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xe4: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { uInt16 value = uInt16(X) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xec: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { uInt16 value = uInt16(X) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; ////////////////////////////////////////////////// // CPY case 0xc0: { operand = peek(PC++, DISASM_CODE); } { uInt16 value = uInt16(Y) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xc4: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { uInt16 value = uInt16(Y) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; case 0xcc: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { uInt16 value = uInt16(Y) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); } break; ////////////////////////////////////////////////// // DCP case 0xcf: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); uInt16 value2 = uInt16(A) - uInt16(value); notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); } break; case 0xdf: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); uInt16 value2 = uInt16(A) - uInt16(value); notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); } break; case 0xdb: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); uInt16 value2 = uInt16(A) - uInt16(value); notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); } break; case 0xc7: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); uInt16 value2 = uInt16(A) - uInt16(value); notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); } break; case 0xd7: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); uInt16 value2 = uInt16(A) - uInt16(value); notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); } break; case 0xc3: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); uInt16 value2 = uInt16(A) - uInt16(value); notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); } break; case 0xd3: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); uInt16 value2 = uInt16(A) - uInt16(value); notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); } break; ////////////////////////////////////////////////// // DEC case 0xc6: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; } break; case 0xd6: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; } break; case 0xce: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; } break; case 0xde: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; } break; ////////////////////////////////////////////////// // DEX case 0xca: { peek(PC, DISASM_NONE); } { X--; notZ = X; N = X & 0x80; } break; ////////////////////////////////////////////////// // DEY case 0x88: { peek(PC, DISASM_NONE); } { Y--; notZ = Y; N = Y & 0x80; } break; ////////////////////////////////////////////////// // EOR case 0x49: { operand = peek(PC++, DISASM_CODE); } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0x45: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0x55: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0x4d: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0x5d: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0x59: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0x41: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { A ^= operand; notZ = A; N = A & 0x80; } break; case 0x51: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { A ^= operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // INC case 0xe6: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand + 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; } break; case 0xf6: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand + 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; } break; case 0xee: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand + 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; } break; case 0xfe: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = operand + 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; } break; ////////////////////////////////////////////////// // INX case 0xe8: { peek(PC, DISASM_NONE); } { X++; notZ = X; N = X & 0x80; } break; ////////////////////////////////////////////////// // INY case 0xc8: { peek(PC, DISASM_NONE); } { Y++; notZ = Y; N = Y & 0x80; } break; ////////////////////////////////////////////////// // ISB case 0xef: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { operand = operand + 1; poke(operandAddress, operand, DISASM_WRITE); // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xff: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { operand = operand + 1; poke(operandAddress, operand, DISASM_WRITE); // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xfb: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { operand = operand + 1; poke(operandAddress, operand, DISASM_WRITE); // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xe7: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { operand = operand + 1; poke(operandAddress, operand, DISASM_WRITE); // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xf7: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { operand = operand + 1; poke(operandAddress, operand, DISASM_WRITE); // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xe3: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { operand = operand + 1; poke(operandAddress, operand, DISASM_WRITE); // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xf3: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { operand = operand + 1; poke(operandAddress, operand, DISASM_WRITE); // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; ////////////////////////////////////////////////// // JMP case 0x4c: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); } { PC = operandAddress; } break; case 0x6c: { uInt16 addr = peek(PC++, DISASM_CODE); addr |= (uInt16(peek(PC++, DISASM_CODE)) << 8); // Simulate the error in the indirect addressing mode! uInt16 high = NOTSAMEPAGE(addr, addr + 1) ? (addr & 0xff00) : (addr + 1); operandAddress = peek(addr, DISASM_DATA); operandAddress |= (uInt16(peek(high, DISASM_DATA)) << 8); } { PC = operandAddress; } break; ////////////////////////////////////////////////// // JSR case 0x20: { uInt8 low = peek(PC++, DISASM_CODE); peek(0x0100 + SP, DISASM_NONE); // It seems that the 650x does not push the address of the next instruction // on the stack it actually pushes the address of the next instruction // minus one. This is compensated for in the RTS instruction poke(0x0100 + SP--, PC >> 8, DISASM_WRITE); poke(0x0100 + SP--, PC & 0xff, DISASM_WRITE); PC = (low | (uInt16(peek(PC, DISASM_CODE)) << 8)); } break; ////////////////////////////////////////////////// // LAS case 0xbb: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { A = X = SP = SP & operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // LAX case 0xaf: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) { A = operand; X = operand; notZ = A; N = A & 0x80; } break; case 0xbf: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) { A = operand; X = operand; notZ = A; N = A & 0x80; } break; case 0xa7: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) { A = operand; X = operand; notZ = A; N = A & 0x80; } break; case 0xb7: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += Y; operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) // TODO - check this SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) { A = operand; X = operand; notZ = A; N = A & 0x80; } break; case 0xa3: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) // TODO - check this { A = operand; X = operand; notZ = A; N = A & 0x80; } break; case 0xb3: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) // TODO - check this { A = operand; X = operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // LDA case 0xa9: { operand = peek(PC++, DISASM_CODE); } CLEAR_LAST_PEEK(myLastSrcAddressA) { A = operand; notZ = A; N = A & 0x80; } break; case 0xa5: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A = operand; notZ = A; N = A & 0x80; } break; case 0xb5: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A = operand; notZ = A; N = A & 0x80; } break; case 0xad: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A = operand; notZ = A; N = A & 0x80; } break; case 0xbd: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A = operand; notZ = A; N = A & 0x80; } break; case 0xb9: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A = operand; notZ = A; N = A & 0x80; } break; case 0xa1: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A = operand; notZ = A; N = A & 0x80; } break; case 0xb1: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A = operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // LDX case 0xa2: { operand = peek(PC++, DISASM_CODE); } CLEAR_LAST_PEEK(myLastSrcAddressX) { X = operand; notZ = X; N = X & 0x80; } break; case 0xa6: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) { X = operand; notZ = X; N = X & 0x80; } break; case 0xb6: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += Y; operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) { X = operand; notZ = X; N = X & 0x80; } break; case 0xae: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) { X = operand; notZ = X; N = X & 0x80; } break; case 0xbe: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) { X = operand; notZ = X; N = X & 0x80; } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // LDY case 0xa0: { operand = peek(PC++, DISASM_CODE); } CLEAR_LAST_PEEK(myLastSrcAddressY) { Y = operand; notZ = Y; N = Y & 0x80; } break; case 0xa4: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) { Y = operand; notZ = Y; N = Y & 0x80; } break; case 0xb4: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) { Y = operand; notZ = Y; N = Y & 0x80; } break; case 0xac: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) { Y = operand; notZ = Y; N = Y & 0x80; } break; case 0xbc: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) { Y = operand; notZ = Y; N = Y & 0x80; } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // LSR case 0x4a: { peek(PC, DISASM_NONE); } { // Set carry flag according to the right-most bit C = A & 0x01; A = (A >> 1) & 0x7f; notZ = A; N = A & 0x80; } break; case 0x46: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x56: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x4e: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x5e: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; ////////////////////////////////////////////////// // LXA case 0xab: { operand = peek(PC++, DISASM_CODE); } { // NOTE: The implementation of this instruction is based on // information from the 64doc.txt file. This instruction is // reported to be very unstable! A = X = (A | 0xee) & operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // NOP case 0x1a: case 0x3a: case 0x5a: case 0x7a: case 0xda: case 0xea: case 0xfa: { peek(PC, DISASM_NONE); } { } break; case 0x80: case 0x82: case 0x89: case 0xc2: case 0xe2: { operand = peek(PC++, DISASM_CODE); } { } break; case 0x04: case 0x44: case 0x64: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { } break; case 0x14: case 0x34: case 0x54: case 0x74: case 0xd4: case 0xf4: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } { } break; case 0x0c: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { } break; case 0x1c: case 0x3c: case 0x5c: case 0x7c: case 0xdc: case 0xfc: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { } break; ////////////////////////////////////////////////// // ORA case 0x09: { operand = peek(PC++, DISASM_CODE); } CLEAR_LAST_PEEK(myLastSrcAddressA) { A |= operand; notZ = A; N = A & 0x80; } break; case 0x05: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A |= operand; notZ = A; N = A & 0x80; } break; case 0x15: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A |= operand; notZ = A; N = A & 0x80; } break; case 0x0d: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A |= operand; notZ = A; N = A & 0x80; } break; case 0x1d: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A |= operand; notZ = A; N = A & 0x80; } break; case 0x19: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A |= operand; notZ = A; N = A & 0x80; } break; case 0x01: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A |= operand; notZ = A; N = A & 0x80; } break; case 0x11: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) { A |= operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // PHA case 0x48: { peek(PC, DISASM_NONE); } // TODO - add tracking for this opcode { poke(0x0100 + SP--, A, DISASM_WRITE); } break; ////////////////////////////////////////////////// // PHP case 0x08: { peek(PC, DISASM_NONE); } // TODO - add tracking for this opcode { poke(0x0100 + SP--, PS(), DISASM_WRITE); } break; ////////////////////////////////////////////////// // PLA case 0x68: { peek(PC, DISASM_NONE); } // TODO - add tracking for this opcode { peek(0x0100 + SP++, DISASM_NONE); A = peek(0x0100 + SP, DISASM_DATA); notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // PLP case 0x28: { peek(PC, DISASM_NONE); } // TODO - add tracking for this opcode { peek(0x0100 + SP++, DISASM_NONE); PS(peek(0x0100 + SP, DISASM_DATA)); } break; ////////////////////////////////////////////////// // RLA case 0x2f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value, DISASM_WRITE); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; case 0x3f: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value, DISASM_WRITE); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; case 0x3b: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value, DISASM_WRITE); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; case 0x27: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value, DISASM_WRITE); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; case 0x37: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value, DISASM_WRITE); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; case 0x23: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value, DISASM_WRITE); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; case 0x33: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value, DISASM_WRITE); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // ROL case 0x2a: { peek(PC, DISASM_NONE); } { bool oldC = C; // Set carry flag according to the left-most bit C = A & 0x80; A = (A << 1) | (oldC ? 1 : 0); notZ = A; N = A & 0x80; } break; case 0x26: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the left-most bit in operand C = operand & 0x80; operand = (operand << 1) | (oldC ? 1 : 0); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x36: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the left-most bit in operand C = operand & 0x80; operand = (operand << 1) | (oldC ? 1 : 0); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x2e: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the left-most bit in operand C = operand & 0x80; operand = (operand << 1) | (oldC ? 1 : 0); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x3e: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the left-most bit in operand C = operand & 0x80; operand = (operand << 1) | (oldC ? 1 : 0); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; ////////////////////////////////////////////////// // ROR case 0x6a: { peek(PC, DISASM_NONE); } { bool oldC = C; // Set carry flag according to the right-most bit C = A & 0x01; A = ((A >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); notZ = A; N = A & 0x80; } break; case 0x66: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x76: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x6e: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; case 0x7e: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; } break; ////////////////////////////////////////////////// // RRA case 0x6f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x7f: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x7b: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x67: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x77: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x63: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; case 0x73: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } } break; ////////////////////////////////////////////////// // RTI case 0x40: { peek(PC, DISASM_NONE); } { peek(0x0100 + SP++, DISASM_NONE); PS(peek(0x0100 + SP++, DISASM_NONE)); PC = peek(0x0100 + SP++, DISASM_NONE); PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8); } break; ////////////////////////////////////////////////// // RTS case 0x60: { peek(PC, DISASM_NONE); } { peek(0x0100 + SP++, DISASM_NONE); PC = peek(0x0100 + SP++, DISASM_NONE); PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8); peek(PC++, DISASM_NONE); } break; ////////////////////////////////////////////////// // SAX case 0x8f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); } { poke(operandAddress, A & X, DISASM_WRITE); } break; case 0x87: { operandAddress = peek(PC++, DISASM_CODE); } { poke(operandAddress, A & X, DISASM_WRITE); } break; case 0x97: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + Y) & 0xFF; } { poke(operandAddress, A & X, DISASM_WRITE); } break; case 0x83: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); } { poke(operandAddress, A & X, DISASM_WRITE); } break; ////////////////////////////////////////////////// // SBC case 0xe9: case 0xeb: { operand = peek(PC++, DISASM_CODE); } { // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xe5: { intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); } { // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xf5: { intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); } { // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xed: { intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xfd: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xf9: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xe1: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); } { // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; case 0xf1: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } } { // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; } break; ////////////////////////////////////////////////// // SBX case 0xcb: { operand = peek(PC++, DISASM_CODE); } { uInt16 value = uInt16(X & A) - uInt16(operand); X = (value & 0xff); notZ = X; N = X & 0x80; C = !(value & 0x0100); } break; ////////////////////////////////////////////////// // SEC case 0x38: { peek(PC, DISASM_NONE); } { C = true; } break; ////////////////////////////////////////////////// // SED case 0xf8: { peek(PC, DISASM_NONE); } { D = true; } break; ////////////////////////////////////////////////// // SEI case 0x78: { peek(PC, DISASM_NONE); } { I = true; } break; ////////////////////////////////////////////////// // SHA case 0x9f: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; } { // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); } break; case 0x93: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; } { // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); } break; ////////////////////////////////////////////////// // SHS case 0x9b: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; } { // NOTE: There are mixed reports on the actual operation // of this instruction! SP = A & X; poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); } break; ////////////////////////////////////////////////// // SHX case 0x9e: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; } { // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); } break; ////////////////////////////////////////////////// // SHY case 0x9c: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; } { // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); } break; ////////////////////////////////////////////////// // SLO case 0x0f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); A |= operand; notZ = A; N = A & 0x80; } break; case 0x1f: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); A |= operand; notZ = A; N = A & 0x80; } break; case 0x1b: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); A |= operand; notZ = A; N = A & 0x80; } break; case 0x07: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); A |= operand; notZ = A; N = A & 0x80; } break; case 0x17: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); A |= operand; notZ = A; N = A & 0x80; } break; case 0x03: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); A |= operand; notZ = A; N = A & 0x80; } break; case 0x13: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); A |= operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // SRE case 0x4f: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x5f: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x5b: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x47: { operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x57: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x43: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); A ^= operand; notZ = A; N = A & 0x80; } break; case 0x53: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); } { // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); A ^= operand; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// // STA case 0x85: { operandAddress = peek(PC++, DISASM_CODE); } SET_LAST_POKE(myLastSrcAddressA) { poke(operandAddress, A, DISASM_WRITE); } break; case 0x95: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; } { poke(operandAddress, A, DISASM_WRITE); } break; case 0x8d: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); } { poke(operandAddress, A, DISASM_WRITE); } break; case 0x9d: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; } { poke(operandAddress, A, DISASM_WRITE); } break; case 0x99: { uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; } { poke(operandAddress, A, DISASM_WRITE); } break; case 0x81: { uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); } { poke(operandAddress, A, DISASM_WRITE); } break; case 0x91: { uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; } { poke(operandAddress, A, DISASM_WRITE); } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // STX case 0x86: { operandAddress = peek(PC++, DISASM_CODE); } SET_LAST_POKE(myLastSrcAddressX) { poke(operandAddress, X, DISASM_WRITE); } break; case 0x96: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + Y) & 0xFF; } { poke(operandAddress, X, DISASM_WRITE); } break; case 0x8e: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); } { poke(operandAddress, X, DISASM_WRITE); } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // STY case 0x84: { operandAddress = peek(PC++, DISASM_CODE); } SET_LAST_POKE(myLastSrcAddressY) { poke(operandAddress, Y, DISASM_WRITE); } break; case 0x94: { operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; } { poke(operandAddress, Y, DISASM_WRITE); } break; case 0x8c: { operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); } { poke(operandAddress, Y, DISASM_WRITE); } break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // Remaining MOVE opcodes case 0xaa: { peek(PC, DISASM_NONE); } SET_LAST_PEEK(myLastSrcAddressX, myLastSrcAddressA) { X = A; notZ = X; N = X & 0x80; } break; case 0xa8: { peek(PC, DISASM_NONE); } SET_LAST_PEEK(myLastSrcAddressY, myLastSrcAddressA) { Y = A; notZ = Y; N = Y & 0x80; } break; case 0xba: { peek(PC, DISASM_NONE); } SET_LAST_PEEK(myLastSrcAddressX, myLastSrcAddressS) { X = SP; notZ = X; N = X & 0x80; } break; case 0x8a: { peek(PC, DISASM_NONE); } SET_LAST_PEEK(myLastSrcAddressA, myLastSrcAddressX) { A = X; notZ = A; N = A & 0x80; } break; case 0x9a: { peek(PC, DISASM_NONE); } SET_LAST_PEEK(myLastSrcAddressS, myLastSrcAddressX) { SP = X; } break; case 0x98: { peek(PC, DISASM_NONE); } SET_LAST_PEEK(myLastSrcAddressA, myLastSrcAddressY) { A = Y; notZ = A; N = A & 0x80; } break; ////////////////////////////////////////////////// stella-5.1.1/src/emucore/M6502.m4000066400000000000000000001154111324334165500162140ustar00rootroot00000000000000//============================================================================ // // MM MM 6666 555555 0000 2222 // MMMM MMMM 66 66 55 00 00 22 22 // MM MMM MM 66 55 00 00 22 // MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator" // MM MM 66 66 55 00 00 22 // MM MM 66 66 55 55 00 00 22 // MM MM 6666 5555 0000 222222 // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ /** Code and cases to emulate each of the 6502 instructions. Recompile with the following: 'm4 M6502.m4 > M6502.ins' @author Bradford W. Mott and Stephen Anthony */ #ifndef NOTSAMEPAGE #define NOTSAMEPAGE(_addr1, _addr2) (((_addr1) ^ (_addr2)) & 0xff00) #endif #ifndef SET_LAST_PEEK #ifdef DEBUGGER_SUPPORT #define SET_LAST_PEEK(_addr1, _addr2) _addr1 = _addr2; #else #define SET_LAST_PEEK(_addr1, _addr2) #endif #endif #ifndef CLEAR_LAST_PEEK #ifdef DEBUGGER_SUPPORT #define CLEAR_LAST_PEEK(_addr) _addr = -1; #else #define CLEAR_LAST_PEEK(_addr) #endif #endif #ifndef SET_LAST_POKE #ifdef DEBUGGER_SUPPORT #define SET_LAST_POKE(_addr) myDataAddressForPoke = _addr; #else #define SET_LAST_POKE(_addr) #endif #endif define(M6502_IMPLIED, `{ peek(PC, DISASM_NONE); }') define(M6502_IMMEDIATE_READ, `{ operand = peek(PC++, DISASM_CODE); }') define(M6502_ABSOLUTE_READ, `{ intermediateAddress = peek(PC++, DISASM_CODE); intermediateAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(intermediateAddress, DISASM_DATA); }') define(M6502_ABSOLUTE_WRITE, `{ operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); }') define(M6502_ABSOLUTE_READMODIFYWRITE, `{ operandAddress = peek(PC++, DISASM_CODE); operandAddress |= (uInt16(peek(PC++, DISASM_CODE)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); }') define(M6502_ABSOLUTEX_READ, `{ uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + X); if((low + X) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + X; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } }') define(M6502_ABSOLUTEX_WRITE, `{ uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; }') define(M6502_ABSOLUTEX_READMODIFYWRITE, `{ uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + X), DISASM_NONE); operandAddress = (high | low) + X; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); }') define(M6502_ABSOLUTEY_READ, `{ uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } }') define(M6502_ABSOLUTEY_WRITE, `{ uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; }') define(M6502_ABSOLUTEY_READMODIFYWRITE, `{ uInt16 low = peek(PC++, DISASM_CODE); uInt16 high = (uInt16(peek(PC++, DISASM_CODE)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); }') define(M6502_ZERO_READ, `{ intermediateAddress = peek(PC++, DISASM_CODE); operand = peek(intermediateAddress, DISASM_DATA); }') define(M6502_ZERO_WRITE, `{ operandAddress = peek(PC++, DISASM_CODE); }') define(M6502_ZERO_READMODIFYWRITE, `{ operandAddress = peek(PC++, DISASM_CODE); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); }') define(M6502_ZEROX_READ, `{ intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += X; operand = peek(intermediateAddress, DISASM_DATA); }') define(M6502_ZEROX_WRITE, `{ operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; }') define(M6502_ZEROX_READMODIFYWRITE, `{ operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + X) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); }') define(M6502_ZEROY_READ, `{ intermediateAddress = peek(PC++, DISASM_CODE); peek(intermediateAddress, DISASM_NONE); intermediateAddress += Y; operand = peek(intermediateAddress, DISASM_DATA); }') define(M6502_ZEROY_WRITE, `{ operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + Y) & 0xFF; }') define(M6502_ZEROY_READMODIFYWRITE, `{ operandAddress = peek(PC++, DISASM_CODE); peek(operandAddress, DISASM_NONE); operandAddress = (operandAddress + Y) & 0xFF; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); }') define(M6502_INDIRECT, `{ uInt16 addr = peek(PC++, DISASM_CODE); addr |= (uInt16(peek(PC++, DISASM_CODE)) << 8); // Simulate the error in the indirect addressing mode! uInt16 high = NOTSAMEPAGE(addr, addr + 1) ? (addr & 0xff00) : (addr + 1); operandAddress = peek(addr, DISASM_DATA); operandAddress |= (uInt16(peek(high, DISASM_DATA)) << 8); }') define(M6502_INDIRECTX_READ, `{ uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; intermediateAddress = peek(pointer++, DISASM_DATA); intermediateAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(intermediateAddress, DISASM_DATA); }') define(M6502_INDIRECTX_WRITE, `{ uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); }') define(M6502_INDIRECTX_READMODIFYWRITE, `{ uInt8 pointer = peek(PC++, DISASM_CODE); peek(pointer, DISASM_NONE); pointer += X; operandAddress = peek(pointer++, DISASM_DATA); operandAddress |= (uInt16(peek(pointer, DISASM_DATA)) << 8); operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); }') define(M6502_INDIRECTY_READ, `{ uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); intermediateAddress = high | uInt8(low + Y); if((low + Y) > 0xFF) { operand = peek(intermediateAddress, DISASM_NONE); intermediateAddress = (high | low) + Y; operand = peek(intermediateAddress, DISASM_DATA); } else { operand = peek(intermediateAddress, DISASM_DATA); } }') define(M6502_INDIRECTY_WRITE, `{ uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; }') define(M6502_INDIRECTY_READMODIFYWRITE, `{ uInt8 pointer = peek(PC++, DISASM_CODE); uInt16 low = peek(pointer++, DISASM_DATA); uInt16 high = (uInt16(peek(pointer, DISASM_DATA)) << 8); peek(high | uInt8(low + Y), DISASM_NONE); operandAddress = (high | low) + Y; operand = peek(operandAddress, DISASM_DATA); poke(operandAddress, operand, DISASM_WRITE); }') define(M6502_BCC, `{ if(!C) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } }') define(M6502_BCS, `{ if(C) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } }') define(M6502_BEQ, `{ if(!notZ) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } }') define(M6502_BMI, `{ if(N) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } }') define(M6502_BNE, `{ if(notZ) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } }') define(M6502_BPL, `{ if(!N) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } }') define(M6502_BVC, `{ if(!V) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } }') define(M6502_BVS, `{ if(V) { peek(PC, DISASM_NONE); uInt16 address = PC + Int8(operand); if(NOTSAMEPAGE(PC, address)) peek((PC & 0xFF00) | (address & 0x00FF), DISASM_NONE); PC = address; } }') define(M6502_ADC, `{ if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } }') define(M6502_ANC, `{ A &= operand; notZ = A; N = A & 0x80; C = N; }') define(M6502_AND, `{ A &= operand; notZ = A; N = A & 0x80; }') define(M6502_ANE, `{ // NOTE: The implementation of this instruction is based on // information from the 64doc.txt file. This instruction is // reported to be unstable! A = (A | 0xee) & X & operand; notZ = A; N = A & 0x80; }') define(M6502_ARR, `{ // NOTE: The implementation of this instruction is based on // information from the 64doc.txt file. There are mixed // reports on its operation! if(!D) { A &= operand; A = ((A >> 1) & 0x7f) | (C ? 0x80 : 0x00); C = A & 0x40; V = (A & 0x40) ^ ((A & 0x20) << 1); notZ = A; N = A & 0x80; } else { uInt8 value = A & operand; A = ((value >> 1) & 0x7f) | (C ? 0x80 : 0x00); N = C; notZ = A; V = (value ^ A) & 0x40; if(((value & 0x0f) + (value & 0x01)) > 0x05) { A = (A & 0xf0) | ((A + 0x06) & 0x0f); } if(((value & 0xf0) + (value & 0x10)) > 0x50) { A = (A + 0x60) & 0xff; C = 1; } else { C = 0; } } }') define(M6502_ASL, `{ // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; }') define(M6502_ASLA, `{ // Set carry flag according to the left-most bit in A C = A & 0x80; A <<= 1; notZ = A; N = A & 0x80; }') define(M6502_ASR, `{ A &= operand; // Set carry flag according to the right-most bit C = A & 0x01; A = (A >> 1) & 0x7f; notZ = A; N = A & 0x80; }') define(M6502_BIT, `{ notZ = (A & operand); N = operand & 0x80; V = operand & 0x40; }') define(M6502_BRK, `{ peek(PC++, DISASM_NONE); B = true; poke(0x0100 + SP--, PC >> 8, DISASM_WRITE); poke(0x0100 + SP--, PC & 0x00ff, DISASM_WRITE); poke(0x0100 + SP--, PS(), DISASM_WRITE); I = true; PC = peek(0xfffe, DISASM_DATA); PC |= (uInt16(peek(0xffff, DISASM_DATA)) << 8); }') define(M6502_CLC, `{ C = false; }') define(M6502_CLD, `{ D = false; }') define(M6502_CLI, `{ I = false; }') define(M6502_CLV, `{ V = false; }') define(M6502_CMP, `{ uInt16 value = uInt16(A) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); }') define(M6502_CPX, `{ uInt16 value = uInt16(X) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); }') define(M6502_CPY, `{ uInt16 value = uInt16(Y) - uInt16(operand); notZ = value; N = value & 0x0080; C = !(value & 0x0100); }') define(M6502_DCP, `{ uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); uInt16 value2 = uInt16(A) - uInt16(value); notZ = value2; N = value2 & 0x0080; C = !(value2 & 0x0100); }') define(M6502_DEC, `{ uInt8 value = operand - 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; }') define(M6502_DEX, `{ X--; notZ = X; N = X & 0x80; }') define(M6502_DEY, `{ Y--; notZ = Y; N = Y & 0x80; }') define(M6502_EOR, `{ A ^= operand; notZ = A; N = A & 0x80; }') define(M6502_INC, `{ uInt8 value = operand + 1; poke(operandAddress, value, DISASM_WRITE); notZ = value; N = value & 0x80; }') define(M6502_INX, `{ X++; notZ = X; N = X & 0x80; }') define(M6502_INY, `{ Y++; notZ = Y; N = Y & 0x80; }') define(M6502_ISB, `{ operand = operand + 1; poke(operandAddress, operand, DISASM_WRITE); // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; }') define(M6502_JMP, `{ PC = operandAddress; }') define(M6502_JSR, `{ uInt8 low = peek(PC++, DISASM_CODE); peek(0x0100 + SP, DISASM_NONE); // It seems that the 650x does not push the address of the next instruction // on the stack it actually pushes the address of the next instruction // minus one. This is compensated for in the RTS instruction poke(0x0100 + SP--, PC >> 8, DISASM_WRITE); poke(0x0100 + SP--, PC & 0xff, DISASM_WRITE); PC = (low | (uInt16(peek(PC, DISASM_CODE)) << 8)); }') define(M6502_LAS, `{ A = X = SP = SP & operand; notZ = A; N = A & 0x80; }') define(M6502_LAX, `{ A = operand; X = operand; notZ = A; N = A & 0x80; }') define(M6502_LDA, `{ A = operand; notZ = A; N = A & 0x80; }') define(M6502_LDX, `{ X = operand; notZ = X; N = X & 0x80; }') define(M6502_LDY, `{ Y = operand; notZ = Y; N = Y & 0x80; }') define(M6502_LSR, `{ // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; }') define(M6502_LSRA, `{ // Set carry flag according to the right-most bit C = A & 0x01; A = (A >> 1) & 0x7f; notZ = A; N = A & 0x80; }') define(M6502_LXA, `{ // NOTE: The implementation of this instruction is based on // information from the 64doc.txt file. This instruction is // reported to be very unstable! A = X = (A | 0xee) & operand; notZ = A; N = A & 0x80; }') define(M6502_NOP, `{ }') define(M6502_ORA, `{ A |= operand; notZ = A; N = A & 0x80; }') define(M6502_PHA, `{ poke(0x0100 + SP--, A, DISASM_WRITE); }') define(M6502_PHP, `{ poke(0x0100 + SP--, PS(), DISASM_WRITE); }') define(M6502_PLA, `{ peek(0x0100 + SP++, DISASM_NONE); A = peek(0x0100 + SP, DISASM_DATA); notZ = A; N = A & 0x80; }') define(M6502_PLP, `{ peek(0x0100 + SP++, DISASM_NONE); PS(peek(0x0100 + SP, DISASM_DATA)); }') define(M6502_RLA, `{ uInt8 value = (operand << 1) | (C ? 1 : 0); poke(operandAddress, value, DISASM_WRITE); A &= value; C = operand & 0x80; notZ = A; N = A & 0x80; }') define(M6502_ROL, `{ bool oldC = C; // Set carry flag according to the left-most bit in operand C = operand & 0x80; operand = (operand << 1) | (oldC ? 1 : 0); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; }') define(M6502_ROLA, `{ bool oldC = C; // Set carry flag according to the left-most bit C = A & 0x80; A = (A << 1) | (oldC ? 1 : 0); notZ = A; N = A & 0x80; }') define(M6502_ROR, `{ bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); notZ = operand; N = operand & 0x80; }') define(M6502_RORA, `{ bool oldC = C; // Set carry flag according to the right-most bit C = A & 0x01; A = ((A >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); notZ = A; N = A & 0x80; }') define(M6502_RRA, `{ bool oldC = C; // Set carry flag according to the right-most bit C = operand & 0x01; operand = ((operand >> 1) & 0x7f) | (oldC ? 0x80 : 0x00); poke(operandAddress, operand, DISASM_WRITE); if(!D) { Int32 sum = A + operand + (C ? 1 : 0); N = sum & 0x80; V = ~(A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; C = sum & 0xff00; A = uInt8(sum); } else { Int32 lo = (A & 0x0f) + (operand & 0x0f) + (C ? 1 : 0); Int32 hi = (A & 0xf0) + (operand & 0xf0); notZ = (lo+hi) & 0xff; if(lo > 0x09) { hi += 0x10; lo += 0x06; } N = hi & 0x80; V = ~(A ^ operand) & (A ^ hi) & 0x80; if(hi > 0x90) hi += 0x60; C = hi & 0xff00; A = (lo & 0x0f) + (hi & 0xf0); } }') define(M6502_RTI, `{ peek(0x0100 + SP++, DISASM_NONE); PS(peek(0x0100 + SP++, DISASM_NONE)); PC = peek(0x0100 + SP++, DISASM_NONE); PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8); }') define(M6502_RTS, `{ peek(0x0100 + SP++, DISASM_NONE); PC = peek(0x0100 + SP++, DISASM_NONE); PC |= (uInt16(peek(0x0100 + SP, DISASM_NONE)) << 8); peek(PC++, DISASM_NONE); }') define(M6502_SAX, `{ poke(operandAddress, A & X, DISASM_WRITE); }') define(M6502_SBC, `{ // N, V, Z, C flags are the same in either mode (C calculated at the end) Int32 sum = A - operand - (C ? 0 : 1); N = sum & 0x80; V = (A ^ operand) & (A ^ sum) & 0x80; notZ = sum & 0xff; if(!D) { A = uInt8(sum); } else { Int32 lo = (A & 0x0f) - (operand & 0x0f) - (C ? 0 : 1); Int32 hi = (A & 0xf0) - (operand & 0xf0); if(lo & 0x10) { lo -= 6; hi--; } if(hi & 0x0100) hi -= 0x60; A = (lo & 0x0f) | (hi & 0xf0); } C = (sum & 0xff00) == 0; }') define(M6502_SBX, `{ uInt16 value = uInt16(X & A) - uInt16(operand); X = (value & 0xff); notZ = X; N = X & 0x80; C = !(value & 0x0100); }') define(M6502_SEC, `{ C = true; }') define(M6502_SED, `{ D = true; }') define(M6502_SEI, `{ I = true; }') define(M6502_SHA, `{ // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); }') define(M6502_SHS, `{ // NOTE: There are mixed reports on the actual operation // of this instruction! SP = A & X; poke(operandAddress, A & X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); }') define(M6502_SHX, `{ // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, X & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); }') define(M6502_SHY, `{ // NOTE: There are mixed reports on the actual operation // of this instruction! poke(operandAddress, Y & (((operandAddress >> 8) & 0xff) + 1), DISASM_WRITE); }') define(M6502_SLO, `{ // Set carry flag according to the left-most bit in value C = operand & 0x80; operand <<= 1; poke(operandAddress, operand, DISASM_WRITE); A |= operand; notZ = A; N = A & 0x80; }') define(M6502_SRE, `{ // Set carry flag according to the right-most bit in value C = operand & 0x01; operand = (operand >> 1) & 0x7f; poke(operandAddress, operand, DISASM_WRITE); A ^= operand; notZ = A; N = A & 0x80; }') define(M6502_STA, `{ poke(operandAddress, A, DISASM_WRITE); }') define(M6502_STX, `{ poke(operandAddress, X, DISASM_WRITE); }') define(M6502_STY, `{ poke(operandAddress, Y, DISASM_WRITE); }') define(M6502_TAX, `{ X = A; notZ = X; N = X & 0x80; }') define(M6502_TAY, `{ Y = A; notZ = Y; N = Y & 0x80; }') define(M6502_TSX, `{ X = SP; notZ = X; N = X & 0x80; }') define(M6502_TXA, `{ A = X; notZ = A; N = A & 0x80; }') define(M6502_TXS, `{ SP = X; }') define(M6502_TYA, `{ A = Y; notZ = A; N = A & 0x80; }') ////////////////////////////////////////////////// // ADC case 0x69: M6502_IMMEDIATE_READ M6502_ADC break; case 0x65: M6502_ZERO_READ M6502_ADC break; case 0x75: M6502_ZEROX_READ M6502_ADC break; case 0x6d: M6502_ABSOLUTE_READ M6502_ADC break; case 0x7d: M6502_ABSOLUTEX_READ M6502_ADC break; case 0x79: M6502_ABSOLUTEY_READ M6502_ADC break; case 0x61: M6502_INDIRECTX_READ M6502_ADC break; case 0x71: M6502_INDIRECTY_READ M6502_ADC break; ////////////////////////////////////////////////// // ASR case 0x4b: M6502_IMMEDIATE_READ M6502_ASR break; ////////////////////////////////////////////////// // ANC case 0x0b: case 0x2b: M6502_IMMEDIATE_READ M6502_ANC break; ////////////////////////////////////////////////// // AND case 0x29: M6502_IMMEDIATE_READ M6502_AND break; case 0x25: M6502_ZERO_READ M6502_AND break; case 0x35: M6502_ZEROX_READ M6502_AND break; case 0x2d: M6502_ABSOLUTE_READ M6502_AND break; case 0x3d: M6502_ABSOLUTEX_READ M6502_AND break; case 0x39: M6502_ABSOLUTEY_READ M6502_AND break; case 0x21: M6502_INDIRECTX_READ M6502_AND break; case 0x31: M6502_INDIRECTY_READ M6502_AND break; ////////////////////////////////////////////////// // ANE case 0x8b: M6502_IMMEDIATE_READ M6502_ANE break; ////////////////////////////////////////////////// // ARR case 0x6b: M6502_IMMEDIATE_READ M6502_ARR break; ////////////////////////////////////////////////// // ASL case 0x0a: M6502_IMPLIED M6502_ASLA break; case 0x06: M6502_ZERO_READMODIFYWRITE M6502_ASL break; case 0x16: M6502_ZEROX_READMODIFYWRITE M6502_ASL break; case 0x0e: M6502_ABSOLUTE_READMODIFYWRITE M6502_ASL break; case 0x1e: M6502_ABSOLUTEX_READMODIFYWRITE M6502_ASL break; ////////////////////////////////////////////////// // BIT case 0x24: M6502_ZERO_READ M6502_BIT break; case 0x2C: M6502_ABSOLUTE_READ M6502_BIT break; ////////////////////////////////////////////////// // Branches case 0x90: M6502_IMMEDIATE_READ M6502_BCC break; case 0xb0: M6502_IMMEDIATE_READ M6502_BCS break; case 0xf0: M6502_IMMEDIATE_READ M6502_BEQ break; case 0x30: M6502_IMMEDIATE_READ M6502_BMI break; case 0xD0: M6502_IMMEDIATE_READ M6502_BNE break; case 0x10: M6502_IMMEDIATE_READ M6502_BPL break; case 0x50: M6502_IMMEDIATE_READ M6502_BVC break; case 0x70: M6502_IMMEDIATE_READ M6502_BVS break; ////////////////////////////////////////////////// // BRK case 0x00: M6502_BRK break; ////////////////////////////////////////////////// // CLC case 0x18: M6502_IMPLIED M6502_CLC break; ////////////////////////////////////////////////// // CLD case 0xd8: M6502_IMPLIED M6502_CLD break; ////////////////////////////////////////////////// // CLI case 0x58: M6502_IMPLIED M6502_CLI break; ////////////////////////////////////////////////// // CLV case 0xb8: M6502_IMPLIED M6502_CLV break; ////////////////////////////////////////////////// // CMP case 0xc9: M6502_IMMEDIATE_READ M6502_CMP break; case 0xc5: M6502_ZERO_READ M6502_CMP break; case 0xd5: M6502_ZEROX_READ M6502_CMP break; case 0xcd: M6502_ABSOLUTE_READ M6502_CMP break; case 0xdd: M6502_ABSOLUTEX_READ M6502_CMP break; case 0xd9: M6502_ABSOLUTEY_READ M6502_CMP break; case 0xc1: M6502_INDIRECTX_READ M6502_CMP break; case 0xd1: M6502_INDIRECTY_READ M6502_CMP break; ////////////////////////////////////////////////// // CPX case 0xe0: M6502_IMMEDIATE_READ M6502_CPX break; case 0xe4: M6502_ZERO_READ M6502_CPX break; case 0xec: M6502_ABSOLUTE_READ M6502_CPX break; ////////////////////////////////////////////////// // CPY case 0xc0: M6502_IMMEDIATE_READ M6502_CPY break; case 0xc4: M6502_ZERO_READ M6502_CPY break; case 0xcc: M6502_ABSOLUTE_READ M6502_CPY break; ////////////////////////////////////////////////// // DCP case 0xcf: M6502_ABSOLUTE_READMODIFYWRITE M6502_DCP break; case 0xdf: M6502_ABSOLUTEX_READMODIFYWRITE M6502_DCP break; case 0xdb: M6502_ABSOLUTEY_READMODIFYWRITE M6502_DCP break; case 0xc7: M6502_ZERO_READMODIFYWRITE M6502_DCP break; case 0xd7: M6502_ZEROX_READMODIFYWRITE M6502_DCP break; case 0xc3: M6502_INDIRECTX_READMODIFYWRITE M6502_DCP break; case 0xd3: M6502_INDIRECTY_READMODIFYWRITE M6502_DCP break; ////////////////////////////////////////////////// // DEC case 0xc6: M6502_ZERO_READMODIFYWRITE M6502_DEC break; case 0xd6: M6502_ZEROX_READMODIFYWRITE M6502_DEC break; case 0xce: M6502_ABSOLUTE_READMODIFYWRITE M6502_DEC break; case 0xde: M6502_ABSOLUTEX_READMODIFYWRITE M6502_DEC break; ////////////////////////////////////////////////// // DEX case 0xca: M6502_IMPLIED M6502_DEX break; ////////////////////////////////////////////////// // DEY case 0x88: M6502_IMPLIED M6502_DEY break; ////////////////////////////////////////////////// // EOR case 0x49: M6502_IMMEDIATE_READ M6502_EOR break; case 0x45: M6502_ZERO_READ M6502_EOR break; case 0x55: M6502_ZEROX_READ M6502_EOR break; case 0x4d: M6502_ABSOLUTE_READ M6502_EOR break; case 0x5d: M6502_ABSOLUTEX_READ M6502_EOR break; case 0x59: M6502_ABSOLUTEY_READ M6502_EOR break; case 0x41: M6502_INDIRECTX_READ M6502_EOR break; case 0x51: M6502_INDIRECTY_READ M6502_EOR break; ////////////////////////////////////////////////// // INC case 0xe6: M6502_ZERO_READMODIFYWRITE M6502_INC break; case 0xf6: M6502_ZEROX_READMODIFYWRITE M6502_INC break; case 0xee: M6502_ABSOLUTE_READMODIFYWRITE M6502_INC break; case 0xfe: M6502_ABSOLUTEX_READMODIFYWRITE M6502_INC break; ////////////////////////////////////////////////// // INX case 0xe8: M6502_IMPLIED M6502_INX break; ////////////////////////////////////////////////// // INY case 0xc8: M6502_IMPLIED M6502_INY break; ////////////////////////////////////////////////// // ISB case 0xef: M6502_ABSOLUTE_READMODIFYWRITE M6502_ISB break; case 0xff: M6502_ABSOLUTEX_READMODIFYWRITE M6502_ISB break; case 0xfb: M6502_ABSOLUTEY_READMODIFYWRITE M6502_ISB break; case 0xe7: M6502_ZERO_READMODIFYWRITE M6502_ISB break; case 0xf7: M6502_ZEROX_READMODIFYWRITE M6502_ISB break; case 0xe3: M6502_INDIRECTX_READMODIFYWRITE M6502_ISB break; case 0xf3: M6502_INDIRECTY_READMODIFYWRITE M6502_ISB break; ////////////////////////////////////////////////// // JMP case 0x4c: M6502_ABSOLUTE_WRITE M6502_JMP break; case 0x6c: M6502_INDIRECT M6502_JMP break; ////////////////////////////////////////////////// // JSR case 0x20: M6502_JSR break; ////////////////////////////////////////////////// // LAS case 0xbb: M6502_ABSOLUTEY_READ M6502_LAS break; ////////////////////////////////////////////////// // LAX case 0xaf: M6502_ABSOLUTE_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) M6502_LAX break; case 0xbf: M6502_ABSOLUTEY_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) M6502_LAX break; case 0xa7: M6502_ZERO_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) M6502_LAX break; case 0xb7: M6502_ZEROY_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) // TODO - check this SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) M6502_LAX break; case 0xa3: M6502_INDIRECTX_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) // TODO - check this M6502_LAX break; case 0xb3: M6502_INDIRECTY_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) // TODO - check this M6502_LAX break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // LDA case 0xa9: M6502_IMMEDIATE_READ CLEAR_LAST_PEEK(myLastSrcAddressA) M6502_LDA break; case 0xa5: M6502_ZERO_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_LDA break; case 0xb5: M6502_ZEROX_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_LDA break; case 0xad: M6502_ABSOLUTE_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_LDA break; case 0xbd: M6502_ABSOLUTEX_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_LDA break; case 0xb9: M6502_ABSOLUTEY_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_LDA break; case 0xa1: M6502_INDIRECTX_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_LDA break; case 0xb1: M6502_INDIRECTY_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_LDA break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // LDX case 0xa2: M6502_IMMEDIATE_READ CLEAR_LAST_PEEK(myLastSrcAddressX) M6502_LDX break; case 0xa6: M6502_ZERO_READ SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) M6502_LDX break; case 0xb6: M6502_ZEROY_READ SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) M6502_LDX break; case 0xae: M6502_ABSOLUTE_READ SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) M6502_LDX break; case 0xbe: M6502_ABSOLUTEY_READ SET_LAST_PEEK(myLastSrcAddressX, intermediateAddress) M6502_LDX break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // LDY case 0xa0: M6502_IMMEDIATE_READ CLEAR_LAST_PEEK(myLastSrcAddressY) M6502_LDY break; case 0xa4: M6502_ZERO_READ SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) M6502_LDY break; case 0xb4: M6502_ZEROX_READ SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) M6502_LDY break; case 0xac: M6502_ABSOLUTE_READ SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) M6502_LDY break; case 0xbc: M6502_ABSOLUTEX_READ SET_LAST_PEEK(myLastSrcAddressY, intermediateAddress) M6502_LDY break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // LSR case 0x4a: M6502_IMPLIED M6502_LSRA break; case 0x46: M6502_ZERO_READMODIFYWRITE M6502_LSR break; case 0x56: M6502_ZEROX_READMODIFYWRITE M6502_LSR break; case 0x4e: M6502_ABSOLUTE_READMODIFYWRITE M6502_LSR break; case 0x5e: M6502_ABSOLUTEX_READMODIFYWRITE M6502_LSR break; ////////////////////////////////////////////////// // LXA case 0xab: M6502_IMMEDIATE_READ M6502_LXA break; ////////////////////////////////////////////////// // NOP case 0x1a: case 0x3a: case 0x5a: case 0x7a: case 0xda: case 0xea: case 0xfa: M6502_IMPLIED M6502_NOP break; case 0x80: case 0x82: case 0x89: case 0xc2: case 0xe2: M6502_IMMEDIATE_READ M6502_NOP break; case 0x04: case 0x44: case 0x64: M6502_ZERO_READ M6502_NOP break; case 0x14: case 0x34: case 0x54: case 0x74: case 0xd4: case 0xf4: M6502_ZEROX_READ M6502_NOP break; case 0x0c: M6502_ABSOLUTE_READ M6502_NOP break; case 0x1c: case 0x3c: case 0x5c: case 0x7c: case 0xdc: case 0xfc: M6502_ABSOLUTEX_READ M6502_NOP break; ////////////////////////////////////////////////// // ORA case 0x09: M6502_IMMEDIATE_READ CLEAR_LAST_PEEK(myLastSrcAddressA) M6502_ORA break; case 0x05: M6502_ZERO_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_ORA break; case 0x15: M6502_ZEROX_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_ORA break; case 0x0d: M6502_ABSOLUTE_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_ORA break; case 0x1d: M6502_ABSOLUTEX_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_ORA break; case 0x19: M6502_ABSOLUTEY_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_ORA break; case 0x01: M6502_INDIRECTX_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_ORA break; case 0x11: M6502_INDIRECTY_READ SET_LAST_PEEK(myLastSrcAddressA, intermediateAddress) M6502_ORA break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // PHA case 0x48: M6502_IMPLIED // TODO - add tracking for this opcode M6502_PHA break; ////////////////////////////////////////////////// // PHP case 0x08: M6502_IMPLIED // TODO - add tracking for this opcode M6502_PHP break; ////////////////////////////////////////////////// // PLA case 0x68: M6502_IMPLIED // TODO - add tracking for this opcode M6502_PLA break; ////////////////////////////////////////////////// // PLP case 0x28: M6502_IMPLIED // TODO - add tracking for this opcode M6502_PLP break; ////////////////////////////////////////////////// // RLA case 0x2f: M6502_ABSOLUTE_READMODIFYWRITE M6502_RLA break; case 0x3f: M6502_ABSOLUTEX_READMODIFYWRITE M6502_RLA break; case 0x3b: M6502_ABSOLUTEY_READMODIFYWRITE M6502_RLA break; case 0x27: M6502_ZERO_READMODIFYWRITE M6502_RLA break; case 0x37: M6502_ZEROX_READMODIFYWRITE M6502_RLA break; case 0x23: M6502_INDIRECTX_READMODIFYWRITE M6502_RLA break; case 0x33: M6502_INDIRECTY_READMODIFYWRITE M6502_RLA break; ////////////////////////////////////////////////// // ROL case 0x2a: M6502_IMPLIED M6502_ROLA break; case 0x26: M6502_ZERO_READMODIFYWRITE M6502_ROL break; case 0x36: M6502_ZEROX_READMODIFYWRITE M6502_ROL break; case 0x2e: M6502_ABSOLUTE_READMODIFYWRITE M6502_ROL break; case 0x3e: M6502_ABSOLUTEX_READMODIFYWRITE M6502_ROL break; ////////////////////////////////////////////////// // ROR case 0x6a: M6502_IMPLIED M6502_RORA break; case 0x66: M6502_ZERO_READMODIFYWRITE M6502_ROR break; case 0x76: M6502_ZEROX_READMODIFYWRITE M6502_ROR break; case 0x6e: M6502_ABSOLUTE_READMODIFYWRITE M6502_ROR break; case 0x7e: M6502_ABSOLUTEX_READMODIFYWRITE M6502_ROR break; ////////////////////////////////////////////////// // RRA case 0x6f: M6502_ABSOLUTE_READMODIFYWRITE M6502_RRA break; case 0x7f: M6502_ABSOLUTEX_READMODIFYWRITE M6502_RRA break; case 0x7b: M6502_ABSOLUTEY_READMODIFYWRITE M6502_RRA break; case 0x67: M6502_ZERO_READMODIFYWRITE M6502_RRA break; case 0x77: M6502_ZEROX_READMODIFYWRITE M6502_RRA break; case 0x63: M6502_INDIRECTX_READMODIFYWRITE M6502_RRA break; case 0x73: M6502_INDIRECTY_READMODIFYWRITE M6502_RRA break; ////////////////////////////////////////////////// // RTI case 0x40: M6502_IMPLIED M6502_RTI break; ////////////////////////////////////////////////// // RTS case 0x60: M6502_IMPLIED M6502_RTS break; ////////////////////////////////////////////////// // SAX case 0x8f: M6502_ABSOLUTE_WRITE M6502_SAX break; case 0x87: M6502_ZERO_WRITE M6502_SAX break; case 0x97: M6502_ZEROY_WRITE M6502_SAX break; case 0x83: M6502_INDIRECTX_WRITE M6502_SAX break; ////////////////////////////////////////////////// // SBC case 0xe9: case 0xeb: M6502_IMMEDIATE_READ M6502_SBC break; case 0xe5: M6502_ZERO_READ M6502_SBC break; case 0xf5: M6502_ZEROX_READ M6502_SBC break; case 0xed: M6502_ABSOLUTE_READ M6502_SBC break; case 0xfd: M6502_ABSOLUTEX_READ M6502_SBC break; case 0xf9: M6502_ABSOLUTEY_READ M6502_SBC break; case 0xe1: M6502_INDIRECTX_READ M6502_SBC break; case 0xf1: M6502_INDIRECTY_READ M6502_SBC break; ////////////////////////////////////////////////// // SBX case 0xcb: M6502_IMMEDIATE_READ M6502_SBX break; ////////////////////////////////////////////////// // SEC case 0x38: M6502_IMPLIED M6502_SEC break; ////////////////////////////////////////////////// // SED case 0xf8: M6502_IMPLIED M6502_SED break; ////////////////////////////////////////////////// // SEI case 0x78: M6502_IMPLIED M6502_SEI break; ////////////////////////////////////////////////// // SHA case 0x9f: M6502_ABSOLUTEY_WRITE M6502_SHA break; case 0x93: M6502_INDIRECTY_WRITE M6502_SHA break; ////////////////////////////////////////////////// // SHS case 0x9b: M6502_ABSOLUTEY_WRITE M6502_SHS break; ////////////////////////////////////////////////// // SHX case 0x9e: M6502_ABSOLUTEY_WRITE M6502_SHX break; ////////////////////////////////////////////////// // SHY case 0x9c: M6502_ABSOLUTEX_WRITE M6502_SHY break; ////////////////////////////////////////////////// // SLO case 0x0f: M6502_ABSOLUTE_READMODIFYWRITE M6502_SLO break; case 0x1f: M6502_ABSOLUTEX_READMODIFYWRITE M6502_SLO break; case 0x1b: M6502_ABSOLUTEY_READMODIFYWRITE M6502_SLO break; case 0x07: M6502_ZERO_READMODIFYWRITE M6502_SLO break; case 0x17: M6502_ZEROX_READMODIFYWRITE M6502_SLO break; case 0x03: M6502_INDIRECTX_READMODIFYWRITE M6502_SLO break; case 0x13: M6502_INDIRECTY_READMODIFYWRITE M6502_SLO break; ////////////////////////////////////////////////// // SRE case 0x4f: M6502_ABSOLUTE_READMODIFYWRITE M6502_SRE break; case 0x5f: M6502_ABSOLUTEX_READMODIFYWRITE M6502_SRE break; case 0x5b: M6502_ABSOLUTEY_READMODIFYWRITE M6502_SRE break; case 0x47: M6502_ZERO_READMODIFYWRITE M6502_SRE break; case 0x57: M6502_ZEROX_READMODIFYWRITE M6502_SRE break; case 0x43: M6502_INDIRECTX_READMODIFYWRITE M6502_SRE break; case 0x53: M6502_INDIRECTY_READMODIFYWRITE M6502_SRE break; ////////////////////////////////////////////////// // STA case 0x85: M6502_ZERO_WRITE SET_LAST_POKE(myLastSrcAddressA) M6502_STA break; case 0x95: M6502_ZEROX_WRITE M6502_STA break; case 0x8d: M6502_ABSOLUTE_WRITE M6502_STA break; case 0x9d: M6502_ABSOLUTEX_WRITE M6502_STA break; case 0x99: M6502_ABSOLUTEY_WRITE M6502_STA break; case 0x81: M6502_INDIRECTX_WRITE M6502_STA break; case 0x91: M6502_INDIRECTY_WRITE M6502_STA break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // STX case 0x86: M6502_ZERO_WRITE SET_LAST_POKE(myLastSrcAddressX) M6502_STX break; case 0x96: M6502_ZEROY_WRITE M6502_STX break; case 0x8e: M6502_ABSOLUTE_WRITE M6502_STX break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // STY case 0x84: M6502_ZERO_WRITE SET_LAST_POKE(myLastSrcAddressY) M6502_STY break; case 0x94: M6502_ZEROX_WRITE M6502_STY break; case 0x8c: M6502_ABSOLUTE_WRITE M6502_STY break; ////////////////////////////////////////////////// ////////////////////////////////////////////////// // Remaining MOVE opcodes case 0xaa: M6502_IMPLIED SET_LAST_PEEK(myLastSrcAddressX, myLastSrcAddressA) M6502_TAX break; case 0xa8: M6502_IMPLIED SET_LAST_PEEK(myLastSrcAddressY, myLastSrcAddressA) M6502_TAY break; case 0xba: M6502_IMPLIED SET_LAST_PEEK(myLastSrcAddressX, myLastSrcAddressS) M6502_TSX break; case 0x8a: M6502_IMPLIED SET_LAST_PEEK(myLastSrcAddressA, myLastSrcAddressX) M6502_TXA break; case 0x9a: M6502_IMPLIED SET_LAST_PEEK(myLastSrcAddressS, myLastSrcAddressX) M6502_TXS break; case 0x98: M6502_IMPLIED SET_LAST_PEEK(myLastSrcAddressA, myLastSrcAddressY) M6502_TYA break; ////////////////////////////////////////////////// stella-5.1.1/src/emucore/M6532.cxx000066400000000000000000000350331324334165500165020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "Console.hxx" #include "Settings.hxx" #include "Switches.hxx" #include "System.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDebug.hxx" #endif #include "M6532.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M6532::M6532(const Console& console, const Settings& settings) : myConsole(console), mySettings(settings), myTimer(0), mySubTimer(0), myDivider(1), myTimerWrapped(false), myWrappedThisCycle(false), mySetTimerCycle(0), myLastCycle(0), myDDRA(0), myDDRB(0), myOutA(0), myOutB(0), myInterruptFlag(false), myEdgeDetectPositive(false) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::reset() { static constexpr uInt8 RAM_7800[128] = { 0xA9, 0x00, 0xAA, 0x85, 0x01, 0x95, 0x03, 0xE8, 0xE0, 0x2A, 0xD0, 0xF9, 0x85, 0x02, 0xA9, 0x04, 0xEA, 0x30, 0x23, 0xA2, 0x04, 0xCA, 0x10, 0xFD, 0x9A, 0x8D, 0x10, 0x01, 0x20, 0xCB, 0x04, 0x20, 0xCB, 0x04, 0x85, 0x11, 0x85, 0x1B, 0x85, 0x1C, 0x85, 0x0F, 0xEA, 0x85, 0x02, 0xA9, 0x00, 0xEA, 0x30, 0x04, 0x24, 0x03, 0x30, 0x09, 0xA9, 0x02, 0x85, 0x09, 0x8D, 0x12, 0xF1, 0xD0, 0x1E, 0x24, 0x02, 0x30, 0x0C, 0xA9, 0x02, 0x85, 0x06, 0x8D, 0x18, 0xF1, 0x8D, 0x60, 0xF4, 0xD0, 0x0E, 0x85, 0x2C, 0xA9, 0x08, 0x85, 0x1B, 0x20, 0xCB, 0x04, 0xEA, 0x24, 0x02, 0x30, 0xD9, 0xA9, 0xFD, 0x85, 0x08, 0x6C, 0xFC, 0xFF, 0xEA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // Initialize the 128 bytes of memory bool devSettings = mySettings.getBool("dev.settings"); if(mySettings.getString(devSettings ? "dev.console" : "plr.console") == "7800") for(uInt32 t = 0; t < 128; ++t) myRAM[t] = RAM_7800[t]; else if(mySettings.getBool(devSettings ? "dev.ramrandom" : "plr.ramrandom")) for(uInt32 t = 0; t < 128; ++t) myRAM[t] = mySystem->randGenerator().next(); else memset(myRAM, 0, 128); myTimer = mySystem->randGenerator().next() & 0xff; myDivider = 1024; mySubTimer = 0; myTimerWrapped = false; myWrappedThisCycle = false; mySetTimerCycle = myLastCycle = 0; // Zero the I/O registers myDDRA = myDDRB = myOutA = myOutB = 0x00; // Zero the timer registers myOutTimer[0] = myOutTimer[1] = myOutTimer[2] = myOutTimer[3] = 0x00; // Zero the interrupt flag register and mark D7 as invalid myInterruptFlag = 0x00; // Edge-detect set to negative (high to low) myEdgeDetectPositive = false; // Let the controllers know about the reset myConsole.leftController().reset(); myConsole.rightController().reset(); #ifdef DEBUGGER_SUPPORT createAccessBases(); #endif // DEBUGGER_SUPPORT } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::update() { Controller& port0 = myConsole.leftController(); Controller& port1 = myConsole.rightController(); // Get current PA7 state bool prevPA7 = port0.myDigitalPinState[Controller::Four]; // Update entire port state port0.update(); port1.update(); myConsole.switches().update(); // Get new PA7 state bool currPA7 = port0.myDigitalPinState[Controller::Four]; // PA7 Flag is set on active transition in appropriate direction if((!myEdgeDetectPositive && prevPA7 && !currPA7) || (myEdgeDetectPositive && !prevPA7 && currPA7)) myInterruptFlag |= PA7Bit; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::updateEmulation() { uInt32 cycles = uInt32(mySystem->cycles() - myLastCycle); uInt32 subTimer = mySubTimer; // Guard against further state changes if the debugger alread forwarded emulation // state (in particular myWrappedThisCycle) if (cycles == 0) return; myWrappedThisCycle = false; mySubTimer = (cycles + mySubTimer) % myDivider; if(!myTimerWrapped) { uInt32 timerTicks = (cycles + subTimer) / myDivider; if(timerTicks > myTimer) { cycles -= ((myTimer + 1) * myDivider - subTimer); myWrappedThisCycle = cycles == 0; myTimer = 0xFF; myTimerWrapped = true; myInterruptFlag |= TimerBit; } else { myTimer -= timerTicks; cycles = 0; } } if(myTimerWrapped) myTimer = (myTimer - cycles) & 0xFF; myLastCycle = mySystem->cycles(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::install(System& system) { installDelegate(system, *this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::installDelegate(System& system, Device& device) { // Remember which system I'm installed in mySystem = &system; // All accesses are to the given device System::PageAccess access(&device, System::PA_READWRITE); // Map all peek/poke to mirrors of RIOT address space to this class // That is, all mirrors of ZP RAM ($80 - $FF) and IO ($280 - $29F) in the // lower 4K of the 2600 address space are mapped here // The two types of addresses are differentiated in peek/poke as follows: // (addr & 0x0200) == 0x0200 is IO (A9 is 1) // (addr & 0x0300) == 0x0100 is Stack (A8 is 1, A9 is 0) // (addr & 0x0300) == 0x0000 is ZP RAM (A8 is 0, A9 is 0) for (uInt16 addr = 0; addr < 0x1000; addr += System::PAGE_SIZE) if ((addr & 0x0080) == 0x0080) { mySystem->setPageAccess(addr, access); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 M6532::peek(uInt16 addr) { updateEmulation(); // A9 distinguishes I/O registers from ZP RAM // A9 = 1 is read from I/O // A9 = 0 is read from RAM if((addr & 0x0200) == 0x0000) return myRAM[addr & 0x007f]; switch(addr & 0x07) { case 0x00: // SWCHA - Port A I/O Register (Joystick) { uInt8 value = (myConsole.leftController().read() << 4) | myConsole.rightController().read(); // Each pin is high (1) by default and will only go low (0) if either // (a) External device drives the pin low // (b) Corresponding bit in SWACNT = 1 and SWCHA = 0 // Thanks to A. Herbert for this info return (myOutA | ~myDDRA) & value; } case 0x01: // SWACNT - Port A Data Direction Register { return myDDRA; } case 0x02: // SWCHB - Port B I/O Register (Console switches) { return (myOutB | ~myDDRB) & (myConsole.switches().read() | myDDRB); } case 0x03: // SWBCNT - Port B Data Direction Register { return myDDRB; } case 0x04: // INTIM - Timer Output case 0x06: { // Timer Flag is always cleared when accessing INTIM if (!myWrappedThisCycle) myInterruptFlag &= ~TimerBit; myTimerWrapped = false; return myTimer; } case 0x05: // TIMINT/INSTAT - Interrupt Flag case 0x07: { // PA7 Flag is always cleared after accessing TIMINT uInt8 result = myInterruptFlag; myInterruptFlag &= ~PA7Bit; return result; } default: { #ifdef DEBUG_ACCESSES cerr << "BAD M6532 Peek: " << hex << addr << endl; #endif return 0; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6532::poke(uInt16 addr, uInt8 value) { updateEmulation(); // A9 distinguishes I/O registers from ZP RAM // A9 = 1 is write to I/O // A9 = 0 is write to RAM if((addr & 0x0200) == 0x0000) { myRAM[addr & 0x007f] = value; return true; } // A2 distinguishes I/O registers from the timer // A2 = 1 is write to timer // A2 = 0 is write to I/O if((addr & 0x04) != 0) { // A4 = 1 is write to TIMxT (x = 1, 8, 64, 1024) // A4 = 0 is write to edge detect control if((addr & 0x10) != 0) setTimerRegister(value, addr & 0x03); // A1A0 determines interval else myEdgeDetectPositive = addr & 0x01; // A0 determines direction } else { switch(addr & 0x03) { case 0: // SWCHA - Port A I/O Register (Joystick) { myOutA = value; setPinState(true); break; } case 1: // SWACNT - Port A Data Direction Register { myDDRA = value; setPinState(false); break; } case 2: // SWCHB - Port B I/O Register (Console switches) { myOutB = value; break; } case 3: // SWBCNT - Port B Data Direction Register { myDDRB = value; break; } } } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::setTimerRegister(uInt8 value, uInt8 interval) { static constexpr uInt32 divider[] = { 1, 8, 64, 1024 }; myDivider = divider[interval]; myOutTimer[interval] = value; myTimer = value; mySubTimer = myDivider - 1; myTimerWrapped = false; // Interrupt timer flag is cleared (and invalid) when writing to the timer myInterruptFlag &= ~TimerBit; mySetTimerCycle = mySystem->cycles(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::setPinState(bool swcha) { /* When a bit in the DDR is set as input, +5V is placed on its output pin. When it's set as output, either +5V or 0V (depending on the contents of SWCHA) will be placed on the output pin. The standard macros for the AtariVox and SaveKey use this fact to send data to the port. This is represented by the following algorithm: if(DDR bit is input) set output as 1 else if(DDR bit is output) set output as bit in ORA */ Controller& port0 = myConsole.leftController(); Controller& port1 = myConsole.rightController(); uInt8 ioport = myOutA | ~myDDRA; port0.write(Controller::One, ioport & 0x10); port0.write(Controller::Two, ioport & 0x20); port0.write(Controller::Three, ioport & 0x40); port0.write(Controller::Four, ioport & 0x80); port1.write(Controller::One, ioport & 0x01); port1.write(Controller::Two, ioport & 0x02); port1.write(Controller::Three, ioport & 0x04); port1.write(Controller::Four, ioport & 0x08); if(swcha) { port0.controlWrite(ioport); port1.controlWrite(ioport); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6532::save(Serializer& out) const { try { out.putString(name()); out.putByteArray(myRAM, 128); out.putInt(myTimer); out.putInt(mySubTimer); out.putInt(myDivider); out.putBool(myTimerWrapped); out.putBool(myWrappedThisCycle); out.putLong(myLastCycle); out.putLong(mySetTimerCycle); out.putByte(myDDRA); out.putByte(myDDRB); out.putByte(myOutA); out.putByte(myOutB); out.putByte(myInterruptFlag); out.putBool(myEdgeDetectPositive); out.putByteArray(myOutTimer, 4); } catch(...) { cerr << "ERROR: M6532::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool M6532::load(Serializer& in) { try { if(in.getString() != name()) return false; in.getByteArray(myRAM, 128); myTimer = in.getInt(); mySubTimer = in.getInt(); myDivider = in.getInt(); myTimerWrapped = in.getBool(); myWrappedThisCycle = in.getBool(); myLastCycle = in.getLong(); mySetTimerCycle = in.getLong(); myDDRA = in.getByte(); myDDRB = in.getByte(); myOutA = in.getByte(); myOutB = in.getByte(); myInterruptFlag = in.getByte(); myEdgeDetectPositive = in.getBool(); in.getByteArray(myOutTimer, 4); } catch(...) { cerr << "ERROR: M6532::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 M6532::intim() { updateEmulation(); return myTimer; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 M6532::timint() { updateEmulation(); return myInterruptFlag; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int32 M6532::intimClocks() { updateEmulation(); // This method is similar to intim(), except instead of giving the actual // INTIM value, it will give the current number of clocks between one // INTIM value and the next return myTimerWrapped ? 1 : (myDivider - mySubTimer); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 M6532::timerClocks() const { return uInt32(mySystem->cycles() - mySetTimerCycle); } #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::createAccessBases() { myRAMAccessBase = make_unique(RAM_SIZE); memset(myRAMAccessBase.get(), CartDebug::NONE, RAM_SIZE); myStackAccessBase = make_unique(STACK_SIZE); memset(myStackAccessBase.get(), CartDebug::NONE, STACK_SIZE); myIOAccessBase = make_unique(IO_SIZE); memset(myIOAccessBase.get(), CartDebug::NONE, IO_SIZE); myZPAccessDelay = make_unique(RAM_SIZE); memset(myZPAccessDelay.get(), ZP_DELAY, RAM_SIZE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 M6532::getAccessFlags(uInt16 address) const { if (address & IO_BIT) return myIOAccessBase[address & IO_MASK]; else if (address & STACK_BIT) return myStackAccessBase[address & STACK_MASK]; else return myRAMAccessBase[address & RAM_MASK]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void M6532::setAccessFlags(uInt16 address, uInt8 flags) { // ignore none flag if (flags != CartDebug::NONE) { if (address & IO_BIT) myIOAccessBase[address & IO_MASK] |= flags; else { // the first access, either by direct RAM or stack access is assumed as initialization if (myZPAccessDelay[address & RAM_MASK]) myZPAccessDelay[address & RAM_MASK]--; else if (address & STACK_BIT) myStackAccessBase[address & STACK_MASK] |= flags; else myRAMAccessBase[address & RAM_MASK] |= flags; } } } #endif // DEBUGGER_SUPPORT stella-5.1.1/src/emucore/M6532.hxx000066400000000000000000000152221324334165500165050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef M6532_HXX #define M6532_HXX class Console; class RiotDebug; class System; class Settings; #include "bspf.hxx" #include "Device.hxx" /** This class models the M6532 RAM-I/O-Timer (aka RIOT) chip in the 2600 console. Note that since the M6507 CPU doesn't contain an interrupt line, the following functionality relating to the RIOT IRQ line is not emulated: - A3 to enable/disable interrupt from timer to IRQ - A1 to enable/disable interrupt from PA7 to IRQ @author Bradford W. Mott and Stephen Anthony */ class M6532 : public Device { public: /** The RIOT debugger class is a friend who needs special access */ friend class RiotDebug; public: /** Create a new 6532 for the specified console @param console The console the 6532 is associated with @param settings The settings used by the system */ M6532(const Console& console, const Settings& settings); virtual ~M6532() = default; public: /** Reset cartridge to its power-on state */ void reset() override; /** Update the entire digital and analog pin state of ports A and B. */ void update(); /** Install 6532 in the specified system. Invoked by the system when the 6532 is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Install 6532 in the specified system and device. Invoked by the system when the 6532 is attached to it. All devices which invoke this method take responsibility for chaining requests back to *this* device. @param system The system the device should install itself in @param device The device responsible for this address space */ void installDelegate(System& system, Device& device); /** Save the current state of this device to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this device from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "M6532"; } public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; /** * Update RIOT state to the current timestamp. */ void updateEmulation(); private: void setTimerRegister(uInt8 data, uInt8 interval); void setPinState(bool shcha); // The following are used by the debugger to read INTIM/TIMINT // We need separate methods to do this, so the state of the system // isn't changed uInt8 intim(); uInt8 timint(); Int32 intimClocks(); uInt32 timerClocks() const; #ifdef DEBUGGER_SUPPORT void createAccessBases(); /** Query the given address type for the associated disassembly flags. @param address The address to query */ uInt8 getAccessFlags(uInt16 address) const override; /** Change the given address to use the given disassembly flags. @param address The address to modify @param flags A bitfield of DisasmType directives for the given address */ void setAccessFlags(uInt16 address, uInt8 flags) override; #endif // DEBUGGER_SUPPORT private: // Accessible bits in the interrupt flag register // All other bits are always zeroed enum { TimerBit = 0x80, PA7Bit = 0x40 }; // Reference to the console const Console& myConsole; // Reference to the settings const Settings& mySettings; // An amazing 128 bytes of RAM uInt8 myRAM[128]; // Current value of the timer uInt8 myTimer; // Current number of clocks "queued" for the divider uInt32 mySubTimer; // The divider uInt32 myDivider; // Has the timer wrapped? bool myTimerWrapped; bool myWrappedThisCycle; // Cycle when the timer set. Debugging only. uInt64 mySetTimerCycle; // Last cycle considered in emu updates uInt64 myLastCycle; // Data Direction Register for Port A uInt8 myDDRA; // Data Direction Register for Port B uInt8 myDDRB; // Last value written to Port A uInt8 myOutA; // Last value written to Port B uInt8 myOutB; // Interrupt Flag Register uInt8 myInterruptFlag; // Used to determine whether an active transition on PA7 has occurred // True is positive edge-detect, false is negative edge-detect bool myEdgeDetectPositive; // Last value written to the timer registers uInt8 myOutTimer[4]; #ifdef DEBUGGER_SUPPORT // The arrays containing information about every byte of RIOT // indicating whether and how (RW) it is used. BytePtr myRAMAccessBase; BytePtr myStackAccessBase; BytePtr myIOAccessBase; // The array used to skip the first ZP access tracking BytePtr myZPAccessDelay; static constexpr uInt16 RAM_SIZE = 0x80, RAM_MASK = RAM_SIZE - 1, STACK_SIZE = RAM_SIZE, STACK_MASK = RAM_MASK, STACK_BIT = 0x100, IO_SIZE = 0x20, IO_MASK = IO_SIZE - 1, IO_BIT = 0x200, ZP_DELAY = 1; #endif // DEBUGGER_SUPPORT private: // Following constructors and assignment operators not supported M6532() = delete; M6532(const M6532&) = delete; M6532(M6532&&) = delete; M6532& operator=(const M6532&) = delete; M6532& operator=(M6532&&) = delete; }; #endif stella-5.1.1/src/emucore/MD5.cxx000066400000000000000000000262551324334165500163610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // This file is derived from the RSA Data Security, Inc. MD5 Message-Digest // Algorithm. See the header below for copyright information. // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "FSNode.hxx" #include "MD5.hxx" /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ namespace MD5 { // Setup the types used by the MD5 routines using POINTER = uInt8*; // MD5 context. struct MD5_CTX { uInt32 state[4]; /* state (ABCD) */ uInt32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ uInt8 buffer[64]; /* input buffer */ }; // Constants for MD5Transform routine. #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #define S42 10 #define S43 15 #define S44 21 static void MD5Init(MD5_CTX*); static void MD5Update(MD5_CTX*, const uInt8*, uInt32); static void MD5Final(uInt8[16], MD5_CTX*); static void MD5Transform(uInt32 [4], const uInt8 [64]); static void Encode(uInt8*, uInt32*, uInt32); static void Decode(uInt32*, const uInt8*, uInt32); static uInt8 PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // F, G, H and I are basic MD5 functions. #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | (~z))) // ROTATE_LEFT rotates x left n bits. #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. // Rotation is separate from addition to prevent recomputation. #define FF(a, b, c, d, x, s, ac) { \ (a) += F ((b), (c), (d)) + (x) + uInt32(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define GG(a, b, c, d, x, s, ac) { \ (a) += G ((b), (c), (d)) + (x) + uInt32(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define HH(a, b, c, d, x, s, ac) { \ (a) += H ((b), (c), (d)) + (x) + uInt32(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } #define II(a, b, c, d, x, s, ac) { \ (a) += I ((b), (c), (d)) + (x) + uInt32(ac); \ (a) = ROTATE_LEFT ((a), (s)); \ (a) += (b); \ } // MD5 initialization. Begins an MD5 operation, writing a new context. static void MD5Init(MD5_CTX* context) { context->count[0] = context->count[1] = 0; /* Load magic initialization constants. */ context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; context->state[2] = 0x98badcfe; context->state[3] = 0x10325476; } // MD5 block update operation. Continues an MD5 message-digest // operation, processing another message block, and updating the // context. static void MD5Update(MD5_CTX* context, const uInt8* input, uInt32 inputLen) { uInt32 i, index, partLen; /* Compute number of bytes mod 64 */ index = uInt32((context->count[0] >> 3) & 0x3F); /* Update number of bits */ if ((context->count[0] += (uInt32(inputLen) << 3)) < (uInt32(inputLen) << 3)) context->count[1]++; context->count[1] += (uInt32(inputLen) >> 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen >= partLen) { memcpy (const_cast(&context->buffer[index]), const_cast(input), partLen); MD5Transform (context->state, context->buffer); for (i = partLen; i + 63 < inputLen; i += 64) MD5Transform (context->state, &input[i]); index = 0; } else i = 0; /* Buffer remaining input */ memcpy(const_cast(&context->buffer[index]), const_cast(&input[i]), inputLen-i); } // MD5 finalization. Ends an MD5 message-digest operation, writing the // the message digest and zeroizing the context. static void MD5Final(uInt8 digest[16], MD5_CTX* context) { uInt8 bits[8]; uInt32 index, padLen; /* Save number of bits */ Encode (bits, context->count, 8); /* Pad out to 56 mod 64. */ index = uInt32((context->count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); MD5Update (context, PADDING, padLen); /* Append length (before padding) */ MD5Update (context, bits, 8); /* Store state in digest */ Encode (digest, context->state, 16); /* Zeroize sensitive information. */ memset (reinterpret_cast(context), 0, sizeof(*context)); } // MD5 basic transformation. Transforms state based on block. static void MD5Transform(uInt32 state[4], const uInt8 block[64]) { uInt32 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode (x, block, 64); /* Round 1 */ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ memset (reinterpret_cast(x), 0, sizeof(x)); } // Encodes input (uInt32) into output (uInt8). Assumes len is // a multiple of 4. static void Encode(uInt8* output, uInt32* input, uInt32 len) { uInt32 i, j; for (i = 0, j = 0; j < len; i++, j += 4) { output[j] = uInt8(input[i] & 0xff); output[j+1] = uInt8((input[i] >> 8) & 0xff); output[j+2] = uInt8((input[i] >> 16) & 0xff); output[j+3] = uInt8((input[i] >> 24) & 0xff); } } // Decodes input (uInt8) into output (uInt32). Assumes len is // a multiple of 4. static void Decode(uInt32* output, const uInt8* input, uInt32 len) { uInt32 i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = (uInt32(input[j])) | ((uInt32(input[j+1])) << 8) | ((uInt32(input[j+2])) << 16) | ((uInt32(input[j+3])) << 24); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string hash(const BytePtr& buffer, uInt32 length) { return hash(buffer.get(), length); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string hash(const uInt8* buffer, uInt32 length) { char hex[] = "0123456789abcdef"; MD5_CTX context; uInt8 md5[16]; MD5Init(&context); MD5Update(&context, buffer, length); MD5Final(md5, &context); string result; for(int t = 0; t < 16; ++t) { result += hex[(md5[t] >> 4) & 0x0f]; result += hex[md5[t] & 0x0f]; } return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string hash(const FilesystemNode& node) { BytePtr image; uInt32 size = 0; try { size = node.read(image); } catch(...) { return EmptyString; } const string& md5 = hash(image, size); return md5; } } // Namespace MD5 stella-5.1.1/src/emucore/MD5.hxx000066400000000000000000000026141324334165500163570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef MD5_HXX #define MD5_HXX class FilesystemNode; #include "bspf.hxx" namespace MD5 { /** Get the MD5 Message-Digest of the specified message with the given length. The digest consists of 32 hexadecimal digits. @param buffer The message to compute the digest of @param length The length of the message @return The message-digest */ string hash(const BytePtr& buffer, uInt32 length); string hash(const uInt8* buffer, uInt32 length); /** Get the MD5 Message-Digest of the file contained in 'node'. The digest consists of 32 hexadecimal digits. @param node The file node to compute the digest of @return The message-digest */ string hash(const FilesystemNode& node); } // Namespace MD5 #endif stella-5.1.1/src/emucore/MT24LC256.cxx000066400000000000000000000261241324334165500171310ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "System.hxx" #include "Settings.hxx" #include "MT24LC256.hxx" #define DEBUG_EEPROM 0 #if DEBUG_EEPROM char jpee_msg[256]; #define JPEE_LOG0(msg) jpee_logproc(msg) #define JPEE_LOG1(msg,arg1) sprintf(jpee_msg,(msg),(arg1)), jpee_logproc(jpee_msg) #define JPEE_LOG2(msg,arg1,arg2) sprintf(jpee_msg,(msg),(arg1),(arg2)), jpee_logproc(jpee_msg) #else #define JPEE_LOG0(msg) { } #define JPEE_LOG1(msg,arg1) { } #define JPEE_LOG2(msg,arg1,arg2) { } #endif /* State values for I2C: 0 - Idle 1 - Byte going to chip (shift left until bit 8 is set) 2 - Chip outputting acknowledgement 3 - Byte coming in from chip (shift left until lower 8 bits are clear) 4 - Chip waiting for acknowledgement */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MT24LC256::MT24LC256(const string& filename, const System& system) : mySystem(system), mySDA(false), mySCL(false), myTimerActive(false), myCyclesWhenTimerSet(0), myCyclesWhenSDASet(0), myCyclesWhenSCLSet(0), myDataFile(filename), myDataFileExists(false), myDataChanged(false), jpee_mdat(0), jpee_sdat(0), jpee_mclk(0), jpee_sizemask(0), jpee_pagemask(0), jpee_smallmode(0), jpee_logmode(0), jpee_pptr(0), jpee_state(0), jpee_nb(0), jpee_address(0), jpee_ad_known(0) { // Load the data from an external file (if it exists) ifstream in(myDataFile, std::ios_base::binary); if(in.is_open()) { // Get length of file; it must be 32768 in.seekg(0, std::ios::end); if(uInt32(in.tellg()) == FLASH_SIZE) { in.seekg(0, std::ios::beg); in.read(reinterpret_cast(myData), FLASH_SIZE); myDataFileExists = true; } } else myDataFileExists = false; // Then initialize the I2C state jpee_init(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MT24LC256::~MT24LC256() { // Save EEPROM data to external file only when necessary if(!myDataFileExists || myDataChanged) { ofstream out(myDataFile, std::ios_base::binary); if(out.is_open()) out.write(reinterpret_cast(myData), FLASH_SIZE); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::writeSDA(bool state) { mySDA = state; myCyclesWhenSDASet = mySystem.cycles(); update(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::writeSCL(bool state) { mySCL = state; myCyclesWhenSCLSet = mySystem.cycles(); update(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::update() { #define jpee_clock(x) ( (x) ? \ (jpee_mclk = 1) : \ (jpee_mclk && (jpee_clock_fall(),1), jpee_mclk = 0)) #define jpee_data(x) ( (x) ? \ (!jpee_mdat && jpee_sdat && jpee_mclk && (jpee_data_stop(),1), jpee_mdat = 1) : \ (jpee_mdat && jpee_sdat && jpee_mclk && (jpee_data_start(),1), jpee_mdat = 0)) // These pins have to be updated at the same time // However, there's no guarantee that the writeSDA() and writeSCL() // methods will be called at the same time or in the correct order, so // we only do the write when they have the same 'timestamp' if(myCyclesWhenSDASet == myCyclesWhenSCLSet) { #if DEBUG_EEPROM cerr << endl << " I2C_PIN_WRITE(SCL = " << mySCL << ", SDA = " << mySDA << ")" << " @ " << mySystem.cycles() << endl; #endif jpee_clock(mySCL); jpee_data(mySDA); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::systemReset() { myCyclesWhenSDASet = myCyclesWhenSCLSet = myCyclesWhenTimerSet = mySystem.cycles(); memset(myPageHit, false, sizeof(myPageHit)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::eraseAll() { memset(myData, INIT_VALUE, FLASH_SIZE); myDataChanged = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::eraseCurrent() { for(uInt32 page = 0; page < PAGE_NUM; page++) { if(myPageHit[page]) { memset(myData + page * PAGE_SIZE, INIT_VALUE, PAGE_SIZE); myDataChanged = true; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool MT24LC256::isPageUsed(uInt32 page) const { if(page < PAGE_NUM) return myPageHit[page]; else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::jpee_init() { jpee_sdat = 1; jpee_address = 0; jpee_state=0; jpee_sizemask = FLASH_SIZE - 1; jpee_pagemask = PAGE_SIZE - 1; jpee_smallmode = 0; jpee_logmode = -1; if(!myDataFileExists) memset(myData, INIT_VALUE, FLASH_SIZE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::jpee_data_start() { /* We have a start condition */ if (jpee_state == 1 && (jpee_nb != 1 || jpee_pptr != 3)) { JPEE_LOG0("I2C_WARNING ABANDON WRITE"); jpee_ad_known = 0; } if (jpee_state == 3) { JPEE_LOG0("I2C_WARNING ABANDON READ"); } if (!jpee_timercheck(0)) { JPEE_LOG0("I2C_START"); jpee_state = 2; } else { JPEE_LOG0("I2C_BUSY"); jpee_state = 0; } jpee_pptr = 0; jpee_nb = 0; jpee_packet[0] = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MT24LC256::jpee_data_stop() { if (jpee_state == 1 && jpee_nb != 1) { JPEE_LOG0("I2C_WARNING ABANDON_WRITE"); jpee_ad_known = 0; } if (jpee_state == 3) { JPEE_LOG0("I2C_WARNING ABANDON_READ"); jpee_ad_known = 0; } /* We have a stop condition. */ if (jpee_state == 1 && jpee_nb == 1 && jpee_pptr > 3) { jpee_timercheck(1); JPEE_LOG2("I2C_STOP(Write %d bytes at %04X)",jpee_pptr-3,jpee_address); if (((jpee_address + jpee_pptr-4) ^ jpee_address) & ~jpee_pagemask) { jpee_pptr = 4+jpee_pagemask-(jpee_address & jpee_pagemask); JPEE_LOG1("I2C_WARNING PAGECROSSING!(Truncate to %d bytes)",jpee_pptr-3); } for (int i=3; i> 1) & 7; if (jpee_packet[1] != (jpee_address >> 8) && (jpee_packet[0] & 1)) JPEE_LOG0("I2C_WARNING ADDRESS MSB CHANGED"); jpee_nb &= 0x1A1; } if (jpee_nb == 0x1A0) { JPEE_LOG1("I2C_SENT(%02X--start write)",jpee_packet[0]); jpee_state = 2; jpee_sdat = 0; } else if (jpee_nb == 0x1A1) { jpee_state = 4; JPEE_LOG2("I2C_SENT(%02X--start read @%04X)", jpee_packet[0],jpee_address); if (!jpee_ad_known) JPEE_LOG0("I2C_WARNING ADDRESS IS UNKNOWN"); jpee_sdat = 0; } else { JPEE_LOG1("I2C_WARNING ODDBALL FIRST BYTE!(%02X)",jpee_nb & 0xFF); jpee_state = 0; } } else { jpee_state = 2; jpee_sdat = 0; } } break; case 2: if (jpee_nb) { if (!jpee_pptr) { jpee_packet[0] = uInt8(jpee_nb); if (jpee_smallmode) jpee_pptr=2; else jpee_pptr=1; } else if (jpee_pptr < 70) { JPEE_LOG1("I2C_SENT(%02X)",jpee_nb & 0xFF); jpee_packet[jpee_pptr++] = uInt8(jpee_nb); jpee_address = (jpee_packet[1] << 8) | jpee_packet[2]; if (jpee_pptr > 2) jpee_ad_known = 1; } else JPEE_LOG0("I2C_WARNING OUTPUT_OVERFLOW!"); } jpee_sdat = 1; jpee_nb = 1; jpee_state=1; break; case 4: if (jpee_mdat && jpee_sdat) { JPEE_LOG0("I2C_READ_NAK"); jpee_state=0; break; } jpee_state=3; myPageHit[jpee_address / PAGE_SIZE] = true; { bool devSettings = mySystem.oSystem().settings().getBool("dev.settings"); if(mySystem.oSystem().settings().getBool(devSettings ? "dev.eepromaccess" : "plr.eepromaccess")) mySystem.oSystem().frameBuffer().showMessage("AtariVox/SaveKey EEPROM read"); } jpee_nb = (myData[jpee_address & jpee_sizemask] << 1) | 1; /* Fall through */ JPEE_LOG2("I2C_READ(%04X=%02X)",jpee_address,jpee_nb/2); [[fallthrough]]; case 3: jpee_sdat = !!(jpee_nb & 256); jpee_nb <<= 1; if (!(jpee_nb & 510)) { jpee_state = 4; jpee_sdat = 1; jpee_address++; } break; default: /* Do nothing */ break; } JPEE_LOG2("I2C_CLOCK (dat=%d/%d)",jpee_mdat,jpee_sdat); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool MT24LC256::jpee_timercheck(int mode) { /* Evaluate how long the EEPROM is busy. When invoked with an argument of 1, start a timer (probably about 5 milliseconds); when invoked with an argument of 0, return zero if the timer has expired or non-zero if it is still running. */ if(mode) // set timer { myCyclesWhenTimerSet = mySystem.cycles(); return myTimerActive = true; } else // read timer { if(myTimerActive) { uInt32 elapsed = uInt32(mySystem.cycles() - myCyclesWhenTimerSet); myTimerActive = elapsed < uInt32(5000000.0 / 838.0); } return myTimerActive; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int MT24LC256::jpee_logproc(char const *st) { cerr << " " << st << endl; return 0; } stella-5.1.1/src/emucore/MT24LC256.hxx000066400000000000000000000074311324334165500171360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef MT24LC256_HXX #define MT24LC256_HXX class Controller; class System; #include "bspf.hxx" /** Emulates a Microchip Technology Inc. 24LC256, a 32KB Serial Electrically Erasable PROM accessed using the I2C protocol. Thanks to J. Payson (aka Supercat) for the bulk of this code. @author Stephen Anthony & J. Payson */ class MT24LC256 { public: /** Create a new 24LC256 with its data stored in the given file @param filename Data file containing the EEPROM data @param system The system using the controller of this device */ MT24LC256(const string& filename, const System& system); ~MT24LC256(); private: // Sizes of the EEPROM static constexpr uInt32 FLASH_SIZE = 32 * 1024; public: static constexpr uInt32 PAGE_SIZE = 64; static constexpr uInt32 PAGE_NUM = FLASH_SIZE / PAGE_SIZE; /** Read boolean data from the SDA line */ bool readSDA() const { return jpee_mdat && jpee_sdat; } /** Write boolean data to the SDA and SCL lines */ void writeSDA(bool state); void writeSCL(bool state); /** Called when the system is being reset */ void systemReset(); /** Erase entire EEPROM to known state ($FF) */ void eraseAll(); /** Erase the pages used by the current ROM to known state ($FF) */ void eraseCurrent(); /** Returns true if the page is used by the current ROM */ bool isPageUsed(uInt32 page) const; private: // I2C access code provided by Supercat void jpee_init(); void jpee_data_start(); void jpee_data_stop(); void jpee_clock_fall(); int jpee_logproc(char const *st); bool jpee_timercheck(int mode); void update(); private: // Inital state value of flash EEPROM static constexpr uInt8 INIT_VALUE = 0xff; // The system of the parent controller const System& mySystem; // The EEPROM data uInt8 myData[FLASH_SIZE]; // Track which pages are used bool myPageHit[PAGE_NUM]; // Cached state of the SDA and SCL pins on the last write bool mySDA, mySCL; // Indicates that a timer has been set and hasn't expired yet bool myTimerActive; // Indicates when the timer was set uInt64 myCyclesWhenTimerSet; // Indicates when the SDA and SCL pins were set/written uInt64 myCyclesWhenSDASet, myCyclesWhenSCLSet; // The file containing the EEPROM data string myDataFile; // Indicates if a valid EEPROM data file exists/was successfully loaded bool myDataFileExists; // Indicates if the EEPROM has changed since class invocation bool myDataChanged; // Required for I2C functionality Int32 jpee_mdat, jpee_sdat, jpee_mclk; Int32 jpee_sizemask, jpee_pagemask, jpee_smallmode, jpee_logmode; Int32 jpee_pptr, jpee_state, jpee_nb; uInt32 jpee_address, jpee_ad_known; uInt8 jpee_packet[70]; private: // Following constructors and assignment operators not supported MT24LC256() = delete; MT24LC256(const MT24LC256&) = delete; MT24LC256(MT24LC256&&) = delete; MT24LC256& operator=(const MT24LC256&) = delete; MT24LC256& operator=(MT24LC256&&) = delete; }; #endif stella-5.1.1/src/emucore/MindLink.cxx000066400000000000000000000053221324334165500174710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Event.hxx" #include "MindLink.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MindLink::MindLink(Jack jack, const Event& event, const System& system) : Controller(jack, event, system, Controller::MindLink), myMindlinkPos(0x2800), myMindlinkShift(1), myMouseEnabled(false) { myDigitalPinState[One] = true; myDigitalPinState[Two] = true; myDigitalPinState[Three] = true; myDigitalPinState[Four] = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MindLink::update() { myDigitalPinState[One] = myDigitalPinState[Two] = myDigitalPinState[Three] = myDigitalPinState[Four] = true; if(!myMouseEnabled) return; myMindlinkPos = (myMindlinkPos & 0x3fffffff) + (myEvent.get(Event::MouseAxisXValue) << 3); if(myMindlinkPos < 0x2800) myMindlinkPos = 0x2800; if(myMindlinkPos >= 0x3800) myMindlinkPos = 0x3800; myMindlinkShift = 1; nextMindlinkBit(); if(myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)) myMindlinkPos |= 0x4000; // this bit starts a game } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MindLink::nextMindlinkBit() { if(myDigitalPinState[One]) { myDigitalPinState[Three] = false; myDigitalPinState[Four] = false; if(myMindlinkPos & myMindlinkShift) myDigitalPinState[Four] = true; myMindlinkShift <<= 1; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool MindLink::setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { // Currently, the mindlink takes full control of the mouse, but only ever // uses the x-axis, and both mouse buttons for the single mindlink button // As well, there's no separate setting for x and y axis, so any // combination of Controller and id is valid myMouseEnabled = (xtype == myType || ytype == myType) && (xid != -1 || yid != -1); return true; } stella-5.1.1/src/emucore/MindLink.hxx000066400000000000000000000076751324334165500175130ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef MINDLINK_HXX #define MINDLINK_HXX #include "bspf.hxx" #include "Control.hxx" /** The Atari Mindlink was an unreleased video game controller intended for release in 1984. The Mindlink was unique in that one had to move the muscles in one's head to control the game. These movements would be read by infrared sensors and transferred as movement in the game. For more information, see the following link: http://www.atarimuseum.com/videogames/consoles/2600/mindlink.html This code was heavily borrowed from z26, and uses conventions defined there. Specifically, IOPortA is treated as a complete uInt8, whereas the Stella core actually stores this information in boolean arrays addressable by DigitalPin number. @author Stephen Anthony & z26 team */ class MindLink : public Controller { public: /** Create a new MindLink controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ MindLink(Jack jack, const Event& event, const System& system); virtual ~MindLink() = default; public: /** Write the given value to the specified digital pin for this controller. Writing is only allowed to the pins associated with the PIA. Therefore you cannot write to pin six. @param pin The pin of the controller jack to write to @param value The value to write to the pin */ void write(DigitalPin pin, bool value) override { myDigitalPinState[pin] = value; } /** Called after *all* digital pins have been written on Port A. */ void controlWrite(uInt8) override { nextMindlinkBit(); } /** Update the entire digital and analog pin state according to the events currently set. */ void update() override; /** Determines how this controller will treat values received from the X/Y axis and left/right buttons of the mouse. Since not all controllers use the mouse the same way (or at all), it's up to the specific class to decide how to use this data. In the current implementation, the left button is tied to the X axis, and the right one tied to the Y axis. @param xtype The controller to use for x-axis data @param xid The controller ID to use for x-axis data (-1 for no id) @param ytype The controller to use for y-axis data @param yid The controller ID to use for y-axis data (-1 for no id) @return Whether the controller supports using the mouse */ bool setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; private: void nextMindlinkBit(); private: // Position value in Mindlink controller // Gets transferred bitwise (16 bits) int myMindlinkPos; // Which bit to transfer next int myMindlinkShift; // Whether to use the mouse to emulate this controller int myMouseEnabled; private: // Following constructors and assignment operators not supported MindLink() = delete; MindLink(const MindLink&) = delete; MindLink(MindLink&&) = delete; MindLink& operator=(const MindLink&) = delete; MindLink& operator=(MindLink&&) = delete; }; #endif stella-5.1.1/src/emucore/NullDev.hxx000066400000000000000000000060571324334165500173500ustar00rootroot00000000000000//============================================================================ // // MM MM 6666 555555 0000 2222 // MMMM MMMM 66 66 55 00 00 22 22 // MM MMM MM 66 55 00 00 22 // MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator" // MM MM 66 66 55 00 00 22 // MM MM 66 66 55 55 00 00 22 // MM MM 6666 5555 0000 222222 // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef NULLDEVICE_HXX #define NULLDEVICE_HXX class System; #include "bspf.hxx" #include "Device.hxx" /** Class that represents a "null" device. The basic idea is that a null device is installed in a 6502 based system anywhere there are holes in the address space (i.e. no real device attached). @author Bradford W. Mott */ class NullDevice : public Device { public: NullDevice() = default; virtual ~NullDevice() = default; public: /** Install device in the specified system. Invoked by the system when the device is attached to it. @param system The system the device should install itself in */ void install(System& system) override { mySystem = &system; } /** Reset device to its power-on state */ void reset() override { } /** Save the current state of this device to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override { return true; } /** Load the current state of this device from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override { return true; } /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "NullDevice"; } public: /** Get the byte at the specified address @return The byte at the specified address */ uInt8 peek(uInt16 address) override { cerr << "NullDevice: peek(" << address << ")\n"; return 0; } /** Change the byte at the specified address to the given value @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override { cerr << "NullDevice: poke(" << address << "," << value << ")\n"; return false; } private: // Following constructors and assignment operators not supported NullDevice(const NullDevice&) = delete; NullDevice(NullDevice&&) = delete; NullDevice& operator=(const NullDevice&) = delete; NullDevice& operator=(NullDevice&&) = delete; }; #endif stella-5.1.1/src/emucore/OSystem.cxx000066400000000000000000000503561324334165500173760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #ifdef HAVE_GETTIMEOFDAY #include #endif #include "bspf.hxx" #include "MediaFactory.hxx" #include "Sound.hxx" #ifdef DEBUGGER_SUPPORT #include "Debugger.hxx" #endif #ifdef CHEATCODE_SUPPORT #include "CheatManager.hxx" #endif #include "FSNode.hxx" #include "MD5.hxx" #include "Cart.hxx" #include "CartDetector.hxx" #include "FrameBuffer.hxx" #include "TIASurface.hxx" #include "Settings.hxx" #include "PropsSet.hxx" #include "EventHandler.hxx" #include "Menu.hxx" #include "CommandMenu.hxx" #include "Launcher.hxx" #include "TimeMachine.hxx" #include "PNGLibrary.hxx" #include "Widget.hxx" #include "Console.hxx" #include "Random.hxx" #include "SerialPort.hxx" #include "StateManager.hxx" #include "Version.hxx" #include "OSystem.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystem::OSystem() : myLauncherUsed(false), myQuitLoop(false) { // Calculate startup time myMillisAtStart = uInt32(time(nullptr) * 1000); // Get built-in features #ifdef SOUND_SUPPORT myFeatures += "Sound "; #endif #ifdef JOYSTICK_SUPPORT myFeatures += "Joystick "; #endif #ifdef DEBUGGER_SUPPORT myFeatures += "Debugger "; #endif #ifdef CHEATCODE_SUPPORT myFeatures += "Cheats"; #endif // Get build info ostringstream info; SDL_version ver; SDL_GetVersion(&ver); info << "Build " << STELLA_BUILD << ", using SDL " << int(ver.major) << "." << int(ver.minor) << "."<< int(ver.patch) << " [" << BSPF::ARCH << "]"; myBuildInfo = info.str(); mySettings = MediaFactory::createSettings(*this); myRandom = make_unique(*this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystem::~OSystem() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::create() { // Get updated paths for all configuration files setConfigPaths(); ostringstream buf; buf << "Stella " << STELLA_VERSION << endl << " Features: " << myFeatures << endl << " " << myBuildInfo << endl << endl << "Base directory: '" << FilesystemNode(myBaseDir).getShortPath() << "'" << endl << "Configuration file: '" << FilesystemNode(myConfigFile).getShortPath() << "'" << endl << "User game properties: '" << FilesystemNode(myPropertiesFile).getShortPath() << "'" << endl; logMessage(buf.str(), 1); // NOTE: The framebuffer MUST be created before any other object!!! // Get relevant information about the video hardware // This must be done before any graphics context is created, since // it may be needed to initialize the size of graphical objects try { myFrameBuffer = MediaFactory::createVideo(*this); } catch(...) { return false; } if(!myFrameBuffer->initialize()) return false; // Create the event handler for the system myEventHandler = MediaFactory::createEventHandler(*this); myEventHandler->initialize(); // Create a properties set for us to use and set it up myPropSet = make_unique(propertiesFile()); #ifdef CHEATCODE_SUPPORT myCheatManager = make_unique(*this); myCheatManager->loadCheatDatabase(); #endif // Create menu and launcher GUI objects myMenu = make_unique(*this); myCommandMenu = make_unique(*this); myTimeMachine = make_unique(*this); myLauncher = make_unique(*this); myStateManager = make_unique(*this); // Create the sound object; the sound subsystem isn't actually // opened until needed, so this is non-blocking (on those systems // that only have a single sound device (no hardware mixing) createSound(); // Create the serial port object // This is used by any controller that wants to directly access // a real serial port on the system mySerialPort = MediaFactory::createSerialPort(); // Re-initialize random seed myRandom->initSeed(); // Create PNG handler myPNGLib = make_unique(*myFrameBuffer); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::loadConfig() { mySettings->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::saveConfig() { // Ask all subsystems to save their settings if(myFrameBuffer) myFrameBuffer->tiaSurface().ntsc().saveConfig(*mySettings); if(mySettings) mySettings->saveConfig(); if(myPropSet) myPropSet->save(myPropertiesFile); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::setConfigPaths() { // Paths are saved with special characters preserved ('~' or '.') // We do some error checking here, so the rest of the codebase doesn't // have to worry about it FilesystemNode node; string s; validatePath(myStateDir, "statedir", myBaseDir + "state"); validatePath(mySnapshotSaveDir, "snapsavedir", defaultSaveDir()); validatePath(mySnapshotLoadDir, "snaploaddir", defaultLoadDir()); validatePath(myNVRamDir, "nvramdir", myBaseDir + "nvram"); validatePath(myCfgDir, "cfgdir", myBaseDir + "cfg"); s = mySettings->getString("cheatfile"); if(s == "") s = myBaseDir + "stella.cht"; node = FilesystemNode(s); myCheatFile = node.getPath(); mySettings->setValue("cheatfile", node.getShortPath()); s = mySettings->getString("palettefile"); if(s == "") s = myBaseDir + "stella.pal"; node = FilesystemNode(s); myPaletteFile = node.getPath(); mySettings->setValue("palettefile", node.getShortPath()); s = mySettings->getString("propsfile"); if(s == "") s = myBaseDir + "stella.pro"; node = FilesystemNode(s); myPropertiesFile = node.getPath(); mySettings->setValue("propsfile", node.getShortPath()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::setBaseDir(const string& basedir) { FilesystemNode node(basedir); if(!node.isDirectory()) node.makeDir(); myBaseDir = node.getPath(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::setConfigFile(const string& file) { myConfigFile = FilesystemNode(file).getPath(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::setFramerate(float framerate) { if(framerate > 0.0) { myDisplayFrameRate = framerate; myTimePerFrame = uInt32(1000000.0 / myDisplayFrameRate); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus OSystem::createFrameBuffer() { // Re-initialize the framebuffer to current settings FBInitStatus fbstatus = FBInitStatus::FailComplete; switch(myEventHandler->state()) { case EventHandlerState::EMULATION: case EventHandlerState::PAUSE: case EventHandlerState::OPTIONSMENU: case EventHandlerState::CMDMENU: case EventHandlerState::TIMEMACHINE: if((fbstatus = myConsole->initializeVideo()) != FBInitStatus::Success) return fbstatus; break; case EventHandlerState::LAUNCHER: if((fbstatus = myLauncher->initializeVideo()) != FBInitStatus::Success) return fbstatus; break; case EventHandlerState::DEBUGGER: #ifdef DEBUGGER_SUPPORT if((fbstatus = myDebugger->initializeVideo()) != FBInitStatus::Success) return fbstatus; #endif break; case EventHandlerState::NONE: // Should never happen logMessage("ERROR: Unknown emulation state in createFrameBuffer()", 0); break; } return fbstatus; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::createSound() { if(!mySound) mySound = MediaFactory::createAudio(*this); #ifndef SOUND_SUPPORT mySettings->setValue("sound", false); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystem::createConsole(const FilesystemNode& rom, const string& md5sum, bool newrom) { bool showmessage = false; // If same ROM has been given, we reload the current one (assuming one exists) if(!newrom && rom == myRomFile) { showmessage = true; // we show a message if a ROM is being reloaded } else { myRomFile = rom; myRomMD5 = md5sum; // Each time a new console is loaded, we simulate a cart removal // Some carts need knowledge of this, as they behave differently // based on how many power-cycles they've been through since plugged in mySettings->setValue("romloadcount", 0); } // Create an instance of the 2600 game console ostringstream buf; try { closeConsole(); myConsole = openConsole(myRomFile, myRomMD5); } catch(const runtime_error& e) { buf << "ERROR: Couldn't create console (" << e.what() << ")"; logMessage(buf.str(), 0); return buf.str(); } if(myConsole) { #ifdef DEBUGGER_SUPPORT myDebugger = make_unique(*this, *myConsole); myDebugger->initialize(); myConsole->attachDebugger(*myDebugger); #endif #ifdef CHEATCODE_SUPPORT myCheatManager->loadCheats(myRomMD5); #endif myEventHandler->reset(EventHandlerState::EMULATION); myEventHandler->setMouseControllerMode(mySettings->getString("usemouse")); if(createFrameBuffer() != FBInitStatus::Success) // Takes care of initializeVideo() { logMessage("ERROR: Couldn't create framebuffer for console", 0); myEventHandler->reset(EventHandlerState::LAUNCHER); return "ERROR: Couldn't create framebuffer for console"; } myConsole->initializeAudio(); if(showmessage) { const string& id = myConsole->cartridge().multiCartID(); if(id == "") myFrameBuffer->showMessage("New console created"); else myFrameBuffer->showMessage("Multicart " + myConsole->cartridge().detectedType() + ", loading ROM" + id); } buf << "Game console created:" << endl << " ROM file: " << myRomFile.getShortPath() << endl << endl << getROMInfo(*myConsole) << endl; logMessage(buf.str(), 1); // Update the timing info for a new console run resetLoopTiming(); myFrameBuffer->setCursorState(); // Also check if certain virtual buttons should be held down // These must be checked each time a new console is being created myEventHandler->handleConsoleStartupEvents(); } return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::reloadConsole() { return createConsole(myRomFile, myRomMD5, false) == EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::hasConsole() const { return myConsole != nullptr && myEventHandler->state() != EventHandlerState::LAUNCHER; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool OSystem::createLauncher(const string& startdir) { closeConsole(); if(mySound) mySound->close(); mySettings->setValue("tmpromdir", startdir); bool status = false; myEventHandler->reset(EventHandlerState::LAUNCHER); if(createFrameBuffer() == FBInitStatus::Success) { myLauncher->reStack(); myFrameBuffer->setCursorState(); setFramerate(30); resetLoopTiming(); status = true; } else logMessage("ERROR: Couldn't create launcher", 0); myLauncherUsed = myLauncherUsed || status; return status; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystem::getROMInfo(const FilesystemNode& romfile) { unique_ptr console; try { string md5; console = openConsole(romfile, md5); } catch(const runtime_error& e) { ostringstream buf; buf << "ERROR: Couldn't get ROM info (" << e.what() << ")"; return buf.str(); } return getROMInfo(*console); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::logMessage(const string& message, uInt8 level) { if(level == 0) { cout << message << endl << std::flush; myLogMessages += message + "\n"; } else if(level <= uInt8(mySettings->getInt("loglevel"))) { if(mySettings->getBool("logtoconsole")) cout << message << endl << std::flush; myLogMessages += message + "\n"; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unique_ptr OSystem::openConsole(const FilesystemNode& romfile, string& md5) { unique_ptr console; // Open the cartridge image and read it in BytePtr image; uInt32 size = 0; if((image = openROM(romfile, md5, size)) != nullptr) { // Get a valid set of properties, including any entered on the commandline // For initial creation of the Cart, we're only concerned with the BS type Properties props; myPropSet->getMD5(md5, props); auto CMDLINE_PROPS_UPDATE = [&](const string& name, PropertyType prop) { const string& s = mySettings->getString(name); if(s != "") props.set(prop, s); }; CMDLINE_PROPS_UPDATE("bs", Cartridge_Type); CMDLINE_PROPS_UPDATE("type", Cartridge_Type); // Now create the cartridge string cartmd5 = md5; const string& type = props.get(Cartridge_Type); unique_ptr cart = CartDetector::create(image, size, cartmd5, type, *this); // It's possible that the cart created was from a piece of the image, // and that the md5 (and hence the cart) has changed if(props.get(Cartridge_MD5) != cartmd5) { if(!myPropSet->getMD5(cartmd5, props)) { // Cart md5 wasn't found, so we create a new props for it props.set(Cartridge_MD5, cartmd5); props.set(Cartridge_Name, props.get(Cartridge_Name)+cart->multiCartID()); myPropSet->insert(props, false); } } CMDLINE_PROPS_UPDATE("channels", Cartridge_Sound); CMDLINE_PROPS_UPDATE("ld", Console_LeftDifficulty); CMDLINE_PROPS_UPDATE("rd", Console_RightDifficulty); CMDLINE_PROPS_UPDATE("tv", Console_TelevisionType); CMDLINE_PROPS_UPDATE("sp", Console_SwapPorts); CMDLINE_PROPS_UPDATE("lc", Controller_Left); CMDLINE_PROPS_UPDATE("rc", Controller_Right); const string& s = mySettings->getString("bc"); if(s != "") { props.set(Controller_Left, s); props.set(Controller_Right, s); } CMDLINE_PROPS_UPDATE("cp", Controller_SwapPaddles); CMDLINE_PROPS_UPDATE("ma", Controller_MouseAxis); CMDLINE_PROPS_UPDATE("format", Display_Format); CMDLINE_PROPS_UPDATE("ystart", Display_YStart); CMDLINE_PROPS_UPDATE("height", Display_Height); CMDLINE_PROPS_UPDATE("pp", Display_Phosphor); CMDLINE_PROPS_UPDATE("ppblend", Display_PPBlend); // Finally, create the cart with the correct properties if(cart) console = make_unique(*this, cart, props); } return console; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::closeConsole() { if(myConsole) { #ifdef CHEATCODE_SUPPORT // If a previous console existed, save cheats before creating a new one myCheatManager->saveCheats(myConsole->properties().get(Cartridge_MD5)); #endif myConsole.reset(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BytePtr OSystem::openROM(const FilesystemNode& rom, string& md5, uInt32& size) { // This method has a documented side-effect: // It not only loads a ROM and creates an array with its contents, // but also adds a properties entry if the one for the ROM doesn't // contain a valid name BytePtr image; if((size = rom.read(image)) == 0) return nullptr; // If we get to this point, we know we have a valid file to open // Now we make sure that the file has a valid properties entry // To save time, only generate an MD5 if we really need one if(md5 == "") md5 = MD5::hash(image, size); // Some games may not have a name, since there may not // be an entry in stella.pro. In that case, we use the rom name // and reinsert the properties object Properties props; myPropSet->getMD5WithInsert(rom, md5, props); return image; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystem::getROMInfo(const Console& console) { const ConsoleInfo& info = console.about(); ostringstream buf; buf << " Cart Name: " << info.CartName << endl << " Cart MD5: " << info.CartMD5 << endl << " Controller 0: " << info.Control0 << endl << " Controller 1: " << info.Control1 << endl << " Display Format: " << info.DisplayFormat << endl << " Bankswitch Type: " << info.BankSwitch << endl; return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::resetLoopTiming() { myTimingInfo.start = myTimingInfo.virt = getTicks(); myTimingInfo.current = 0; myTimingInfo.totalTime = 0; myTimingInfo.totalFrames = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::validatePath(string& path, const string& setting, const string& defaultpath) { const string& s = mySettings->getString(setting) == "" ? defaultpath : mySettings->getString(setting); FilesystemNode node(s); if(!node.isDirectory()) node.makeDir(); path = node.getPath(); mySettings->setValue(setting, node.getShortPath()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt64 OSystem::getTicks() const { #ifdef HAVE_GETTIMEOFDAY // Gettimeofday natively refers to the UNIX epoch (a set time in the past) timeval now; gettimeofday(&now, nullptr); return uInt64(now.tv_sec) * 1000000 + now.tv_usec; #else // We use SDL_GetTicks, but add in the time when the application was // initialized. This is necessary, since SDL_GetTicks only measures how // long SDL has been running, which can be the same between multiple runs // of the application. return uInt64(SDL_GetTicks() + myMillisAtStart) * 1000; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OSystem::mainLoop() { if(mySettings->getString("timing") == "sleep") { // Sleep-based wait: good for CPU, bad for graphical sync for(;;) { myTimingInfo.start = getTicks(); myEventHandler->poll(myTimingInfo.start); if(myQuitLoop) break; // Exit if the user wants to quit myFrameBuffer->update(); myTimingInfo.current = getTicks(); myTimingInfo.virt += myTimePerFrame; // Timestamps may periodically go out of sync, particularly on systems // that can have 'negative time' (ie, when the time seems to go backwards) // This normally results in having a very large delay time, so we check // for that and reset the timers when appropriate if((myTimingInfo.virt - myTimingInfo.current) > (myTimePerFrame << 1)) { myTimingInfo.current = myTimingInfo.virt = getTicks(); } if(myTimingInfo.current < myTimingInfo.virt) SDL_Delay(uInt32(myTimingInfo.virt - myTimingInfo.current) / 1000); myTimingInfo.totalTime += (getTicks() - myTimingInfo.start); myTimingInfo.totalFrames++; } } else { // Busy-wait: bad for CPU, good for graphical sync for(;;) { myTimingInfo.start = getTicks(); myEventHandler->poll(myTimingInfo.start); if(myQuitLoop) break; // Exit if the user wants to quit myFrameBuffer->update(); myTimingInfo.virt += myTimePerFrame; while(getTicks() < myTimingInfo.virt) ; // busy-wait myTimingInfo.totalTime += (getTicks() - myTimingInfo.start); myTimingInfo.totalFrames++; } } // Cleanup time #ifdef CHEATCODE_SUPPORT if(myConsole) myCheatManager->saveCheats(myConsole->properties().get(Cartridge_MD5)); myCheatManager->saveCheatDatabase(); #endif } stella-5.1.1/src/emucore/OSystem.hxx000066400000000000000000000413471324334165500174030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef OSYSTEM_HXX #define OSYSTEM_HXX #ifdef CHEATCODE_SUPPORT class CheatManager; #endif class CommandMenu; class Console; class Debugger; class Launcher; class Menu; class TimeMachine; class FrameBuffer; class EventHandler; class PNGLibrary; class Properties; class PropertiesSet; class Random; class SerialPort; class Settings; class Sound; class StateManager; class VideoDialog; #include "FSNode.hxx" #include "FrameBufferConstants.hxx" #include "EventHandlerConstants.hxx" #include "bspf.hxx" struct TimingInfo { uInt64 start; uInt64 current; uInt64 virt; uInt64 totalTime; uInt64 totalFrames; }; /** This class provides an interface for accessing operating system specific functions. It also comprises an overall parent object, to which all the other objects belong. @author Stephen Anthony */ class OSystem { friend class EventHandler; friend class VideoDialog; friend class DeveloperDialog; public: OSystem(); virtual ~OSystem(); /** Create all child objects which belong to this OSystem */ virtual bool create(); public: /** Get the event handler of the system. @return The event handler */ EventHandler& eventHandler() const { return *myEventHandler; } /** Get the frame buffer of the system. @return The frame buffer */ FrameBuffer& frameBuffer() const { return *myFrameBuffer; } /** Get the sound object of the system. @return The sound object */ Sound& sound() const { return *mySound; } /** Get the settings object of the system. @return The settings object */ Settings& settings() const { return *mySettings; } /** Get the random object of the system. @return The random object */ Random& random() const { return *myRandom; } /** Get the set of game properties for the system. @return The properties set object */ PropertiesSet& propSet() const { return *myPropSet; } /** Get the console of the system. The console won't always exist, so we should test if it's available. @return The console object */ Console& console() const { return *myConsole; } bool hasConsole() const; /** Get the serial port of the system. @return The serial port object */ SerialPort& serialPort() const { return *mySerialPort; } /** Get the settings menu of the system. @return The settings menu object */ Menu& menu() const { return *myMenu; } /** Get the command menu of the system. @return The command menu object */ CommandMenu& commandMenu() const { return *myCommandMenu; } /** Get the ROM launcher of the system. @return The launcher object */ Launcher& launcher() const { return *myLauncher; } /** Get the time machine of the system (manages state files). @return The time machine object */ TimeMachine& timeMachine() const { return *myTimeMachine; } /** Get the state manager of the system. @return The statemanager object */ StateManager& state() const { return *myStateManager; } /** Get the PNG handler of the system. @return The PNGlib object */ PNGLibrary& png() const { return *myPNGLib; } /** This method should be called to load the current settings from an rc file. It first loads the settings from the config file, then informs subsystems about the new settings. */ void loadConfig(); /** This method should be called to save the current settings to an rc file. It first asks each subsystem to update its settings, then it saves all settings to the config file. */ void saveConfig(); #ifdef DEBUGGER_SUPPORT /** Get the ROM debugger of the system. @return The debugger object */ Debugger& debugger() const { return *myDebugger; } #endif #ifdef CHEATCODE_SUPPORT /** Get the cheat manager of the system. @return The cheatmanager object */ CheatManager& cheat() const { return *myCheatManager; } #endif /** Set the framerate for the video system. It's placed in this class since the mainLoop() method is defined here. @param framerate The video framerate to use */ virtual void setFramerate(float framerate); /** Set all config file paths for the OSystem. */ void setConfigPaths(); /** Get the current framerate for the video system. @return The video framerate currently in use */ float frameRate() const { return myDisplayFrameRate; } /** Return the default full/complete directory name for storing data. */ const string& baseDir() const { return myBaseDir; } /** Return the full/complete directory name for storing state files. */ const string& stateDir() const { return myStateDir; } /** Return the full/complete directory name for saving and loading PNG snapshots. */ const string& snapshotSaveDir() const { return mySnapshotSaveDir; } const string& snapshotLoadDir() const { return mySnapshotLoadDir; } /** Return the full/complete directory name for storing nvram (flash/EEPROM) files. */ const string& nvramDir() const { return myNVRamDir; } /** Return the full/complete directory name for storing Distella cfg files. */ const string& cfgDir() const { return myCfgDir; } /** This method should be called to get the full path of the cheat file. @return String representing the full path of the cheat filename. */ const string& cheatFile() const { return myCheatFile; } /** This method should be called to get the full path of the config file. @return String representing the full path of the config filename. */ const string& configFile() const { return myConfigFile; } /** This method should be called to get the full path of the (optional) palette file. @return String representing the full path of the properties filename. */ const string& paletteFile() const { return myPaletteFile; } /** This method should be called to get the full path of the properties file (stella.pro). @return String representing the full path of the properties filename. */ const string& propertiesFile() const { return myPropertiesFile; } /** This method should be called to get the full path of the currently loaded ROM. @return FSNode object representing the ROM file. */ const FilesystemNode& romFile() const { return myRomFile; } /** Creates a new game console from the specified romfile, and correctly initializes the system state to start emulation of the Console. @param rom The FSNode of the ROM to use (contains path, etc) @param md5 The MD5sum of the ROM @param newrom Whether this is a new ROM, or a reload of current one @return String indicating any error message (EmptyString for no errors) */ string createConsole(const FilesystemNode& rom, const string& md5 = "", bool newrom = true); /** Reloads the current console (essentially deletes and re-creates it). This can be thought of as a real console off/on toggle. @return True on successful creation, otherwise false */ bool reloadConsole(); /** Creates a new ROM launcher, to select a new ROM to emulate. @param startdir The directory to use when opening the launcher; if blank, use 'romdir' setting. @return True on successful creation, otherwise false */ bool createLauncher(const string& startdir = ""); /** Answers whether the ROM launcher was actually successfully used at some point since the app started. @return True if launcher was ever used, otherwise false */ bool launcherUsed() const { return myLauncherUsed; } /** Gets all possible info about the ROM by creating a temporary Console object and querying it. @param romfile The file node of the ROM to use @return Some information about this ROM */ string getROMInfo(const FilesystemNode& romfile); /** The features which are conditionally compiled into Stella. @return The supported features */ const string& features() const { return myFeatures; } /** The build information for Stella (toolkit version, architecture, etc). @return The build info */ const string& buildInfo() const { return myBuildInfo; } /** Issue a quit event to the OSystem. */ void quit() { myQuitLoop = true; } /** Append a message to the internal log (a newline is automatically added). @param message The message to be appended @param level If 0, always output the message, only append when level is less than or equal to that in 'loglevel' */ void logMessage(const string& message, uInt8 level); /** Get the system messages logged up to this point. @return The list of log messages */ const string& logMessages() const { return myLogMessages; } /** Return timing information (start time of console, current number of frames rendered, etc. */ const TimingInfo& timingInfo() const { return myTimingInfo; } public: ////////////////////////////////////////////////////////////////////// // The following methods are system-specific and can be overrided in // derived classes. Otherwise, the base methods will be used. ////////////////////////////////////////////////////////////////////// /** This method returns number of ticks in microseconds since some pre-defined time in the past. *NOTE*: it is necessary that this pre-defined time exists between runs of the application, and must be (relatively) unique. For example, the time since the system started running is not a good choice, since it can be duplicated. The current implementation uses time since the UNIX epoch. @return Current time in microseconds. */ virtual uInt64 getTicks() const; /** This method runs the main loop. Since different platforms may use different timing methods and/or algorithms, this method can be overrided. However, the port then takes all responsibility for running the emulation and taking care of timing. */ virtual void mainLoop(); /** Informs the OSystem of a change in EventHandler state. */ virtual void stateChanged(EventHandlerState state) { } /** Returns the default save and load paths for various files (snapshots, disassembly, roms, etc). Since this varies greatly among different systems and is the one directory that most end-users care about (vs. config file stuff that usually isn't user-modifiable), we create a special method for it. */ virtual string defaultSaveDir() const { return string("~") + BSPF::PATH_SEPARATOR; } virtual string defaultLoadDir() const { return string("~") + BSPF::PATH_SEPARATOR; } protected: /** Set the base directory for all Stella files (these files may be located in other places through settings). */ void setBaseDir(const string& basedir); /** Set the locations of config file */ void setConfigFile(const string& file); protected: // Pointer to the EventHandler object unique_ptr myEventHandler; // Pointer to the FrameBuffer object unique_ptr myFrameBuffer; // Pointer to the Sound object unique_ptr mySound; // Pointer to the Settings object unique_ptr mySettings; // Pointer to the Random object unique_ptr myRandom; // Pointer to the PropertiesSet object unique_ptr myPropSet; // Pointer to the (currently defined) Console object unique_ptr myConsole; // Pointer to the serial port object unique_ptr mySerialPort; // Pointer to the Menu object unique_ptr myMenu; // Pointer to the CommandMenu object unique_ptr myCommandMenu; // Pointer to the Launcher object unique_ptr myLauncher; bool myLauncherUsed; // Pointer to the TimeMachine object unique_ptr myTimeMachine; #ifdef DEBUGGER_SUPPORT // Pointer to the Debugger object unique_ptr myDebugger; #endif #ifdef CHEATCODE_SUPPORT // Pointer to the CheatManager object unique_ptr myCheatManager; #endif // Pointer to the StateManager object unique_ptr myStateManager; // PNG object responsible for loading/saving PNG images unique_ptr myPNGLib; // The list of log messages string myLogMessages; // Number of times per second to iterate through the main loop float myDisplayFrameRate; // Time per frame for a video update, based on the current framerate uInt32 myTimePerFrame; // The time (in milliseconds) from the UNIX epoch when the application starts uInt32 myMillisAtStart; // Indicates whether to stop the main loop bool myQuitLoop; private: string myBaseDir; string myStateDir; string mySnapshotSaveDir; string mySnapshotLoadDir; string myNVRamDir; string myCfgDir; string myCheatFile; string myConfigFile; string myPaletteFile; string myPropertiesFile; FilesystemNode myRomFile; string myRomMD5; string myFeatures; string myBuildInfo; // Indicates whether the main processing loop should proceed TimingInfo myTimingInfo; private: /** Creates the various framebuffers/renderers available in this system. Note that it will only create one type per run of Stella. @return Success or failure of the framebuffer creation */ FBInitStatus createFrameBuffer(); /** Creates the various sound devices available in this system */ void createSound(); /** Creates an actual Console object based on the given info. @param romfile The file node of the ROM to use (contains path) @param md5 The MD5sum of the ROM @return The actual Console object, otherwise nullptr. */ unique_ptr openConsole(const FilesystemNode& romfile, string& md5); /** Close and finalize any currently open console. */ void closeConsole(); /** Open the given ROM and return an array containing its contents. Also, the properties database is updated with a valid ROM name for this ROM (if necessary). @param rom The file node of the ROM to open (contains path) @param md5 The md5 calculated from the ROM file (will be recalculated if necessary) @param size The amount of data read into the image array @return Unique pointer to the array */ BytePtr openROM(const FilesystemNode& rom, string& md5, uInt32& size); /** Gets all possible info about the given console. @param console The console to use @return Some information about this console */ string getROMInfo(const Console& console); /** Initializes the timing so that the mainloop is reset to its initial values. */ void resetLoopTiming(); /** Validate the directory name, and create it if necessary. Also, update the settings with the new name. For now, validation means that the path must always end with the appropriate separator. @param path The actual path being accessed and created @param setting The setting corresponding to the path being considered @param defaultpath The default path to use if the settings don't exist */ void validatePath(string& path, const string& setting, const string& defaultpath); // Following constructors and assignment operators not supported OSystem(const OSystem&) = delete; OSystem(OSystem&&) = delete; OSystem& operator=(const OSystem&) = delete; OSystem& operator=(OSystem&&) = delete; }; #endif stella-5.1.1/src/emucore/Paddles.cxx000066400000000000000000000370031324334165500173410ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Event.hxx" #include "Paddles.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Paddles::Paddles(Jack jack, const Event& event, const System& system, bool swappaddle, bool swapaxis, bool swapdir) : Controller(jack, event, system, Controller::Paddles), myMPaddleID(-1), myMPaddleIDX(-1), myMPaddleIDY(-1) { // We must start with minimum resistance; see commit // 38b452e1a047a0dca38c5bcce7c271d40f76736e for more information updateAnalogPin(Five, minimumResistance); updateAnalogPin(Nine, minimumResistance); // The following logic reflects that mapping paddles to different // devices can be extremely complex // As well, while many paddle games have horizontal movement of // objects (which maps nicely to horizontal movement of the joystick // or mouse), others have vertical movement // This vertical handling is taken care of by swapping the axes // On the other hand, some games treat paddle resistance differently, // (ie, increasing resistance can move an object right instead of left) // This is taken care of by swapping the direction of movement // Arrgh, did I mention that paddles are complex ... // As much as possible, precompute which events we care about for // a given port; this will speed up processing in update() // Consider whether this is the left or right port if(myJack == Left) { if(!swappaddle) // First paddle is 0, second is 1 { // These aren't affected by changes in axis orientation myP0AxisValue = Event::SALeftAxis0Value; myP1AxisValue = Event::SALeftAxis1Value; myP0FireEvent1 = Event::PaddleZeroFire; myP0FireEvent2 = Event::JoystickZeroFire; myP1FireEvent1 = Event::PaddleOneFire; myP1FireEvent2 = Event::JoystickZeroFire9; // Direction of movement is swapped // That is, moving in a certain direction on an axis can // result in either increasing or decreasing paddle movement if(!swapdir) { myP0DecEvent1 = Event::PaddleZeroDecrease; myP0DecEvent2 = Event::JoystickZeroRight; myP0IncEvent1 = Event::PaddleZeroIncrease; myP0IncEvent2 = Event::JoystickZeroLeft; myP1DecEvent1 = Event::PaddleOneDecrease; myP1DecEvent2 = Event::JoystickZeroDown; myP1IncEvent1 = Event::PaddleOneIncrease; myP1IncEvent2 = Event::JoystickZeroUp; } else { myP0DecEvent1 = Event::PaddleZeroIncrease; myP0DecEvent2 = Event::JoystickZeroLeft; myP0IncEvent1 = Event::PaddleZeroDecrease; myP0IncEvent2 = Event::JoystickZeroRight; myP1DecEvent1 = Event::PaddleOneIncrease; myP1DecEvent2 = Event::JoystickZeroUp; myP1IncEvent1 = Event::PaddleOneDecrease; myP1IncEvent2 = Event::JoystickZeroDown; } } else // First paddle is 1, second is 0 { // These aren't affected by changes in axis orientation myP0AxisValue = Event::SALeftAxis1Value; myP1AxisValue = Event::SALeftAxis0Value; myP0FireEvent1 = Event::PaddleOneFire; myP0FireEvent2 = Event::JoystickZeroFire9; myP1FireEvent1 = Event::PaddleZeroFire; myP1FireEvent2 = Event::JoystickZeroFire; // Direction of movement is swapped // That is, moving in a certain direction on an axis can // result in either increasing or decreasing paddle movement if(!swapdir) { myP0DecEvent1 = Event::PaddleOneDecrease; myP0DecEvent2 = Event::JoystickZeroDown; myP0IncEvent1 = Event::PaddleOneIncrease; myP0IncEvent2 = Event::JoystickZeroUp; myP1DecEvent1 = Event::PaddleZeroDecrease; myP1DecEvent2 = Event::JoystickZeroRight; myP1IncEvent1 = Event::PaddleZeroIncrease; myP1IncEvent2 = Event::JoystickZeroLeft; } else { myP0DecEvent1 = Event::PaddleOneIncrease; myP0DecEvent2 = Event::JoystickZeroUp; myP0IncEvent1 = Event::PaddleOneDecrease; myP0IncEvent2 = Event::JoystickZeroDown; myP1DecEvent1 = Event::PaddleZeroIncrease; myP1DecEvent2 = Event::JoystickZeroLeft; myP1IncEvent1 = Event::PaddleZeroDecrease; myP1IncEvent2 = Event::JoystickZeroRight; } } } else // Jack is right port { if(!swappaddle) // First paddle is 2, second is 3 { // These aren't affected by changes in axis orientation myP0AxisValue = Event::SARightAxis0Value; myP1AxisValue = Event::SARightAxis1Value; myP0FireEvent1 = Event::PaddleTwoFire; myP0FireEvent2 = Event::JoystickOneFire; myP1FireEvent1 = Event::PaddleThreeFire; myP1FireEvent2 = Event::JoystickOneFire9; // Direction of movement is swapped // That is, moving in a certain direction on an axis can // result in either increasing or decreasing paddle movement if(!swapdir) { myP0DecEvent1 = Event::PaddleTwoDecrease; myP0DecEvent2 = Event::JoystickOneRight; myP0IncEvent1 = Event::PaddleTwoIncrease; myP0IncEvent2 = Event::JoystickOneLeft; myP1DecEvent1 = Event::PaddleThreeDecrease; myP1DecEvent2 = Event::JoystickOneDown; myP1IncEvent1 = Event::PaddleThreeIncrease; myP1IncEvent2 = Event::JoystickOneUp; } else { myP0DecEvent1 = Event::PaddleTwoIncrease; myP0DecEvent2 = Event::JoystickOneLeft; myP0IncEvent1 = Event::PaddleTwoDecrease; myP0IncEvent2 = Event::JoystickOneRight; myP1DecEvent1 = Event::PaddleThreeIncrease; myP1DecEvent2 = Event::JoystickOneUp; myP1IncEvent1 = Event::PaddleThreeDecrease; myP1IncEvent2 = Event::JoystickOneDown; } } else // First paddle is 3, second is 2 { // These aren't affected by changes in axis orientation myP0AxisValue = Event::SARightAxis1Value; myP1AxisValue = Event::SARightAxis0Value; myP0FireEvent1 = Event::PaddleThreeFire; myP0FireEvent2 = Event::JoystickOneFire9; myP1FireEvent1 = Event::PaddleTwoFire; myP1FireEvent2 = Event::JoystickOneFire; // Direction of movement is swapped // That is, moving in a certain direction on an axis can // result in either increasing or decreasing paddle movement if(!swapdir) { myP0DecEvent1 = Event::PaddleThreeDecrease; myP0DecEvent2 = Event::JoystickOneDown; myP0IncEvent1 = Event::PaddleThreeIncrease; myP0IncEvent2 = Event::JoystickOneUp; myP1DecEvent1 = Event::PaddleTwoDecrease; myP1DecEvent2 = Event::JoystickOneRight; myP1IncEvent1 = Event::PaddleTwoIncrease; myP1IncEvent2 = Event::JoystickOneLeft; } else { myP0DecEvent1 = Event::PaddleThreeIncrease; myP0DecEvent2 = Event::JoystickOneUp; myP0IncEvent1 = Event::PaddleThreeDecrease; myP0IncEvent2 = Event::JoystickOneDown; myP1DecEvent1 = Event::PaddleTwoIncrease; myP1DecEvent2 = Event::JoystickOneLeft; myP1IncEvent1 = Event::PaddleTwoDecrease; myP1IncEvent2 = Event::JoystickOneRight; } } } // The following are independent of whether or not the port // is left or right MOUSE_SENSITIVITY = swapdir ? -abs(MOUSE_SENSITIVITY) : abs(MOUSE_SENSITIVITY); if(!swapaxis) { myAxisMouseMotion = Event::MouseAxisXValue; myAxisDigitalZero = 0; myAxisDigitalOne = 1; } else { myAxisMouseMotion = Event::MouseAxisYValue; myAxisDigitalZero = 1; myAxisDigitalOne = 0; } // Digital pins 1, 2 and 6 are not connected myDigitalPinState[One] = myDigitalPinState[Two] = myDigitalPinState[Six] = true; // Digital emulation of analog paddle movement myKeyRepeat0 = myKeyRepeat1 = false; myPaddleRepeat0 = myPaddleRepeat1 = myLastAxisX = myLastAxisY = 0; myCharge[0] = myCharge[1] = TRIGRANGE / 2; myLastCharge[0] = myLastCharge[1] = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Paddles::update() { myDigitalPinState[Three] = myDigitalPinState[Four] = true; // Digital events (from keyboard or joystick hats & buttons) myDigitalPinState[Three] = (myEvent.get(myP1FireEvent1) == 0 && myEvent.get(myP1FireEvent2) == 0); myDigitalPinState[Four] = (myEvent.get(myP0FireEvent1) == 0 && myEvent.get(myP0FireEvent2) == 0); // Paddle movement is a very difficult thing to accurately emulate, // since it originally came from an analog device that had very // peculiar behaviour // Compounding the problem is the fact that we'd like to emulate // movement with 'digital' data (like from a keyboard or a digital // joystick axis), but also from a mouse (relative values) // and Stelladaptor-like devices (absolute analog values clamped to // a certain range) // And to top it all off, we don't want one devices input to conflict // with the others ... // Analog axis events from Stelladaptor-like devices // These devices generate data in the range -32768 to 32767, // so we have to scale appropriately // Since these events are generated and stored indefinitely, // we only process the first one we see (when it differs from // previous values by a pre-defined amount) // Otherwise, it would always override input from digital and mouse bool sa_changed = false; int sa_xaxis = myEvent.get(myP0AxisValue); int sa_yaxis = myEvent.get(myP1AxisValue); if(abs(myLastAxisX - sa_xaxis) > 10) { updateAnalogPin(Nine, Int32(MAX_RESISTANCE * ((32767 - Int16(sa_xaxis)) / 65536.0))); sa_changed = true; } if(abs(myLastAxisY - sa_yaxis) > 10) { updateAnalogPin(Five, Int32(MAX_RESISTANCE * ((32767 - Int16(sa_yaxis)) / 65536.0))); sa_changed = true; } myLastAxisX = sa_xaxis; myLastAxisY = sa_yaxis; if(sa_changed) return; // Mouse motion events give relative movement // That is, they're only relevant if they're non-zero if(myMPaddleID > -1) { // We're in auto mode, where a single axis is used for one paddle only myCharge[myMPaddleID] = BSPF::clamp(myCharge[myMPaddleID] - (myEvent.get(myAxisMouseMotion) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); if(myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)) myDigitalPinState[ourButtonPin[myMPaddleID]] = false; } else { // Test for 'untied' mouse axis mode, where each axis is potentially // mapped to a separate paddle if(myMPaddleIDX > -1) { myCharge[myMPaddleIDX] = BSPF::clamp(myCharge[myMPaddleIDX] - (myEvent.get(Event::MouseAxisXValue) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); if(myEvent.get(Event::MouseButtonLeftValue)) myDigitalPinState[ourButtonPin[myMPaddleIDX]] = false; } if(myMPaddleIDY > -1) { myCharge[myMPaddleIDY] = BSPF::clamp(myCharge[myMPaddleIDY] - (myEvent.get(Event::MouseAxisYValue) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); if(myEvent.get(Event::MouseButtonRightValue)) myDigitalPinState[ourButtonPin[myMPaddleIDY]] = false; } } // Finally, consider digital input, where movement happens // until a digital event is released if(myKeyRepeat0) { myPaddleRepeat0++; if(myPaddleRepeat0 > DIGITAL_SENSITIVITY) myPaddleRepeat0 = DIGITAL_DISTANCE; } if(myKeyRepeat1) { myPaddleRepeat1++; if(myPaddleRepeat1 > DIGITAL_SENSITIVITY) myPaddleRepeat1 = DIGITAL_DISTANCE; } myKeyRepeat0 = false; myKeyRepeat1 = false; if(myEvent.get(myP0DecEvent1) || myEvent.get(myP0DecEvent2)) { myKeyRepeat0 = true; if(myCharge[myAxisDigitalZero] > myPaddleRepeat0) myCharge[myAxisDigitalZero] -= myPaddleRepeat0; } if(myEvent.get(myP0IncEvent1) || myEvent.get(myP0IncEvent2)) { myKeyRepeat0 = true; if((myCharge[myAxisDigitalZero] + myPaddleRepeat0) < TRIGRANGE) myCharge[myAxisDigitalZero] += myPaddleRepeat0; } if(myEvent.get(myP1DecEvent1) || myEvent.get(myP1DecEvent2)) { myKeyRepeat1 = true; if(myCharge[myAxisDigitalOne] > myPaddleRepeat1) myCharge[myAxisDigitalOne] -= myPaddleRepeat1; } if(myEvent.get(myP1IncEvent1) || myEvent.get(myP1IncEvent2)) { myKeyRepeat1 = true; if((myCharge[myAxisDigitalOne] + myPaddleRepeat1) < TRIGRANGE) myCharge[myAxisDigitalOne] += myPaddleRepeat1; } // Only change state if the charge has actually changed if(myCharge[1] != myLastCharge[1]) updateAnalogPin(Five, Int32(MAX_RESISTANCE * (myCharge[1] / float(TRIGMAX)))); if(myCharge[0] != myLastCharge[0]) updateAnalogPin(Nine, Int32(MAX_RESISTANCE * (myCharge[0] / float(TRIGMAX)))); myLastCharge[1] = myCharge[1]; myLastCharge[0] = myCharge[0]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Paddles::setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { // In 'automatic' mode, both axes on the mouse map to a single paddle, // and the paddle axis and direction settings are taken into account // This overrides any other mode if(xtype == Controller::Paddles && ytype == Controller::Paddles && xid == yid) { myMPaddleID = ((myJack == Left && (xid == 0 || xid == 1)) || (myJack == Right && (xid == 2 || xid == 3)) ) ? xid & 0x01 : -1; myMPaddleIDX = myMPaddleIDY = -1; } else { // The following is somewhat complex, but we need to pre-process as much // as possible, so that ::update() can run quickly myMPaddleID = -1; if(myJack == Left && xtype == Controller::Paddles) { myMPaddleIDX = (xid == 0 || xid == 1) ? xid & 0x01 : -1; myMPaddleIDY = (yid == 0 || yid == 1) ? yid & 0x01 : -1; } else if(myJack == Right && ytype == Controller::Paddles) { myMPaddleIDX = (xid == 2 || xid == 3) ? xid & 0x01 : -1; myMPaddleIDY = (yid == 2 || yid == 3) ? yid & 0x01 : -1; } } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Paddles::setDigitalSensitivity(int sensitivity) { DIGITAL_SENSITIVITY = BSPF::clamp(sensitivity, 1, MAX_DIGITAL_SENSE); DIGITAL_DISTANCE = 20 + (DIGITAL_SENSITIVITY << 3); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Paddles::setMouseSensitivity(int sensitivity) { MOUSE_SENSITIVITY = BSPF::clamp(sensitivity, 1, MAX_MOUSE_SENSE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Paddles::setPaddleRange(int range) { range = BSPF::clamp(range, 1, 100); TRIGRANGE = int(TRIGMAX * (range / 100.0)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Paddles::TRIGRANGE = Paddles::TRIGMAX; int Paddles::DIGITAL_SENSITIVITY = -1; int Paddles::DIGITAL_DISTANCE = -1; int Paddles::MOUSE_SENSITIVITY = -1; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Controller::DigitalPin Paddles::ourButtonPin[2] = { Four, Three }; stella-5.1.1/src/emucore/Paddles.hxx000066400000000000000000000131271324334165500173470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PADDLES_HXX #define PADDLES_HXX #include "bspf.hxx" #include "Control.hxx" #include "Event.hxx" /** The standard Atari 2600 pair of paddle controllers. @author Bradford W. Mott */ class Paddles : public Controller { public: /** Create a new pair of paddle controllers plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller @param swappaddle Whether to swap the paddles plugged into this jack @param swapaxis Whether to swap the axis on the paddle (x <-> y) @param swapdir Whether to swap the direction for which an axis causes movement (lesser axis values cause paddle resistance to decrease instead of increase) */ Paddles(Jack jack, const Event& event, const System& system, bool swappaddle, bool swapaxis, bool swapdir); virtual ~Paddles() = default; public: /** Update the entire digital and analog pin state according to the events currently set. */ void update() override; /** Determines how this controller will treat values received from the X/Y axis and left/right buttons of the mouse. Since not all controllers use the mouse the same way (or at all), it's up to the specific class to decide how to use this data. In the current implementation, the left button is tied to the X axis, and the right one tied to the Y axis. @param xtype The controller to use for x-axis data @param xid The controller ID to use for x-axis data (-1 for no id) @param ytype The controller to use for y-axis data @param yid The controller ID to use for y-axis data (-1 for no id) @return Whether the controller supports using the mouse */ bool setMouseControl(Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; /** Sets the sensitivity for digital emulation of paddle movement. This is only used for *digital* events (ie, buttons or keys, or digital joystick axis events); Stelladaptors or the mouse are not modified. @param sensitivity Value from 1 to MAX_DIGITAL_SENSE, with larger values causing more movement */ static void setDigitalSensitivity(int sensitivity); /** Sets the sensitivity for analog emulation of paddle movement using a mouse. @param sensitivity Value from 1 to MAX_MOUSE_SENSE, with larger values causing more movement */ static void setMouseSensitivity(int sensitivity); /** Sets the maximum upper range for digital/mouse emulation of paddle movement (ie, a value of 50 means to only use 50% of the possible range of movement). Note that this specfically does not apply to Stelladaptor-like devices, which uses an absolute value range. @param range Value from 1 to 100, representing the percentage of the range to use */ static void setPaddleRange(int range); static constexpr double MAX_RESISTANCE = 1400000.0; private: // Pre-compute the events we care about based on given port // This will eliminate test for left or right port in update() Event::Type myP0AxisValue, myP1AxisValue, myP0DecEvent1, myP0DecEvent2, myP0IncEvent1, myP0IncEvent2, myP1DecEvent1, myP1DecEvent2, myP1IncEvent1, myP1IncEvent2, myP0FireEvent1, myP0FireEvent2, myP1FireEvent1, myP1FireEvent2, myAxisMouseMotion; // The following are used for the various mouse-axis modes int myMPaddleID; // paddle to emulate in 'automatic' mode int myMPaddleIDX, myMPaddleIDY; // paddles to emulate in 'specific axis' mode bool myKeyRepeat0, myKeyRepeat1; int myPaddleRepeat0, myPaddleRepeat1; int myCharge[2], myLastCharge[2]; int myLastAxisX, myLastAxisY; int myAxisDigitalZero, myAxisDigitalOne; // Range of values over which digital and mouse movement is scaled // to paddle resistance static constexpr int TRIGMIN = 1; static constexpr int TRIGMAX = 4096; static int TRIGRANGE; // This one is variable for the upper range static constexpr int MAX_DIGITAL_SENSE = 20; static constexpr int MAX_MOUSE_SENSE = 20; static int DIGITAL_SENSITIVITY, DIGITAL_DISTANCE; static int MOUSE_SENSITIVITY; // Lookup table for associating paddle buttons with controller pins // Yes, this is hideously complex static const Controller::DigitalPin ourButtonPin[2]; private: // Following constructors and assignment operators not supported Paddles() = delete; Paddles(const Paddles&) = delete; Paddles(Paddles&&) = delete; Paddles& operator=(const Paddles&) = delete; Paddles& operator=(Paddles&&) = delete; }; #endif stella-5.1.1/src/emucore/PointingDevice.cxx000066400000000000000000000124601324334165500206740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "Control.hxx" #include "Event.hxx" #include "System.hxx" #include "TIA.hxx" #include "PointingDevice.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PointingDevice::PointingDevice(Jack jack, const Event& event, const System& system, Controller::Type type, float sensitivity) : Controller(jack, event, system, type), mySensitivity(sensitivity), myHCounterRemainder(0.0), myVCounterRemainder(0.0), myTrackBallLinesH(1), myTrackBallLinesV(1), myTrackBallLeft(false), myTrackBallDown(false), myCountH(0), myCountV(0), myScanCountH(0), myScanCountV(0), myFirstScanOffsetH(0), myFirstScanOffsetV(0), myMouseEnabled(false) { // The code in ::read() is set up to always return IOPortA values in // the lower 4 bits data value // As such, the jack type (left or right) isn't necessary here } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 PointingDevice::read() { int scanline = mySystem.tia().scanlines(); // Loop over all missed changes while(myScanCountH < scanline) { if(myTrackBallLeft) myCountH--; else myCountH++; // Define scanline of next change myScanCountH += myTrackBallLinesH; } // Loop over all missed changes while(myScanCountV < scanline) { if(myTrackBallDown) myCountV++; else myCountV--; // Define scanline of next change myScanCountV += myTrackBallLinesV; } myCountH &= 0b11; myCountV &= 0b11; uInt8 portA = ioPortA(myCountH, myCountV, myTrackBallLeft, myTrackBallDown); myDigitalPinState[One] = portA & 0b0001; myDigitalPinState[Two] = portA & 0b0010; myDigitalPinState[Three] = portA & 0b0100; myDigitalPinState[Four] = portA & 0b1000; return portA; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PointingDevice::update() { if(!myMouseEnabled) return; // Update horizontal direction updateDirection( myEvent.get(Event::MouseAxisXValue), myHCounterRemainder, myTrackBallLeft, myTrackBallLinesH, myScanCountH, myFirstScanOffsetH); // Update vertical direction updateDirection(-myEvent.get(Event::MouseAxisYValue), myVCounterRemainder, myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV); // Get mouse button state myDigitalPinState[Six] = (myEvent.get(Event::MouseButtonLeftValue) == 0) && (myEvent.get(Event::MouseButtonRightValue) == 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PointingDevice::setMouseControl( Controller::Type xtype, int xid, Controller::Type ytype, int yid) { // Currently, the various trakball controllers take full control of the // mouse, and use both mouse buttons for the single fire button // As well, there's no separate setting for x and y axis, so any // combination of Controller and id is valid myMouseEnabled = (xtype == myType || ytype == myType) && (xid != -1 || yid != -1); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PointingDevice::setSensitivity(int sensitivity) { BSPF::clamp(sensitivity, 1, 20, 10); TB_SENSITIVITY = sensitivity / 10.0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PointingDevice::updateDirection(int counter, float& counterRemainder, bool& trackBallDir, int& trackBallLines, int& scanCount, int& firstScanOffset) { // Apply sensitivity and calculate remainder float fTrackBallCount = counter * mySensitivity * TB_SENSITIVITY + counterRemainder; int trackBallCount = int(std::lround(fTrackBallCount)); counterRemainder = fTrackBallCount - trackBallCount; if(trackBallCount) { trackBallDir = (trackBallCount > 0); trackBallCount = abs(trackBallCount); // Calculate lines to wait between sending new horz/vert values trackBallLines = mySystem.tia().scanlinesLastFrame() / trackBallCount; // Set lower limit in case of (unrealistic) ultra fast mouse movements if (trackBallLines == 0) trackBallLines = 1; // Define scanline of first change scanCount = (trackBallLines * firstScanOffset) >> 12; } else { // Prevent any change scanCount = INT_MAX; // Define offset factor for first change, move randomly forward by up to 1/8th firstScanOffset = (((firstScanOffset << 3) + rand() % (1 << 12)) >> 3) & ((1 << 12) - 1); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - float PointingDevice::TB_SENSITIVITY = 1.0; stella-5.1.1/src/emucore/PointingDevice.hxx000066400000000000000000000106641324334165500207050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef POINTING_DEVICE_HXX #define POINTING_DEVICE_HXX class Controller; class Event; #include "Control.hxx" #include "bspf.hxx" /** Common controller class for pointing devices (Atari Mouse, Amiga Mouse, Trak-Ball) This code was heavily borrowed from z26. @author Stephen Anthony, Thomas Jentzsch & z26 team */ class PointingDevice : public Controller { friend class PointingDeviceWidget; public: PointingDevice(Jack jack, const Event& event, const System& system, Controller::Type type, float sensitivity); virtual ~PointingDevice() = default; public: using Controller::read; /** Read the entire state of all digital pins for this controller. Note that this method must use the lower 4 bits, and zero the upper bits. @return The state of all digital pins */ uInt8 read() override; /** Update the entire digital and analog pin state according to the events currently set. */ void update() override; /** Determines how this controller will treat values received from the X/Y axis and left/right buttons of the mouse. Since not all controllers use the mouse the same way (or at all), it's up to the specific class to decide how to use this data. In the current implementation, the left button is tied to the X axis, and the right one tied to the Y axis. @param xtype The controller to use for x-axis data @param xid The controller ID to use for x-axis data (-1 for no id) @param ytype The controller to use for y-axis data @param yid The controller ID to use for y-axis data (-1 for no id) @return Whether the controller supports using the mouse */ bool setMouseControl(Controller::Type xtype, int xid, Controller::Type ytype, int yid) override; /** Sets the sensitivity for analog emulation of trackball movement using a mouse. @param sensitivity Value from 1 to 20, with larger values causing more movement (10 represents the baseline) */ static void setSensitivity(int sensitivity); protected: // Each derived class must implement this, to determine how its // IOPortA values are calculated virtual uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) = 0; private: void updateDirection(int counter, float& counterRemainder, bool& trackBallDir, int& trackBallLines, int& scanCount, int& firstScanOffset); private: // Mouse input to sensitivity emulation float mySensitivity, myHCounterRemainder, myVCounterRemainder; // How many lines to wait between sending new horz and vert values int myTrackBallLinesH, myTrackBallLinesV; // Was TrackBall moved left or moved right instead bool myTrackBallLeft; // Was TrackBall moved down or moved up instead bool myTrackBallDown; // Counter to iterate through the gray codes uInt8 myCountH, myCountV; // Next scanline for change int myScanCountH, myScanCountV; // Offset factor for first scanline, 0..(1 << 12 - 1) int myFirstScanOffsetH, myFirstScanOffsetV; // Whether to use the mouse to emulate this controller bool myMouseEnabled; // User-defined sensitivity; adjustable since end-users may have different // mouse speeds static float TB_SENSITIVITY; private: // Following constructors and assignment operators not supported PointingDevice() = delete; PointingDevice(const PointingDevice&) = delete; PointingDevice(PointingDevice&&) = delete; PointingDevice& operator=(const PointingDevice&) = delete; PointingDevice& operator=(PointingDevice&&) = delete; }; #endif // POINTING_DEVICE_HXX stella-5.1.1/src/emucore/Props.cxx000066400000000000000000000231051324334165500170660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #include #include "bspf.hxx" #include "Props.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Properties::Properties() { setDefaults(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Properties::Properties(const Properties& properties) { copy(properties); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::set(PropertyType key, const string& value) { if(key != LastPropType) { myProperties[key] = value; if(BSPF::equalsIgnoreCase(myProperties[key], "AUTO-DETECT")) myProperties[key] = "AUTO"; switch(key) { case Cartridge_Type: case Display_Format: case Cartridge_Sound: case Console_LeftDifficulty: case Console_RightDifficulty: case Console_TelevisionType: case Console_SwapPorts: case Controller_Left: case Controller_Right: case Controller_SwapPaddles: case Controller_MouseAxis: case Display_Phosphor: { transform(myProperties[key].begin(), myProperties[key].end(), myProperties[key].begin(), ::toupper); break; } case Display_PPBlend: { int blend = atoi(myProperties[key].c_str()); if(blend < 1 || blend > 100) myProperties[key] = ourDefaultProperties[key]; break; } default: break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - istream& operator>>(istream& is, Properties& p) { p.setDefaults(); // Loop reading properties string key, value; for(;;) { // Get the key associated with this property key = p.readQuotedString(is); // Make sure the stream is still okay if(!is) return is; // A null key signifies the end of the property list if(key == "") break; // Get the value associated with this property value = p.readQuotedString(is); // Make sure the stream is still okay if(!is) return is; // Set the property PropertyType type = Properties::getPropertyType(key); p.set(type, value); } return is; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ostream& operator<<(ostream& os, const Properties& p) { // Write out each of the key and value pairs bool changed = false; for(int i = 0; i < LastPropType; ++i) { // Try to save some space by only saving the items that differ from default if(p.myProperties[i] != Properties::ourDefaultProperties[i]) { p.writeQuotedString(os, Properties::ourPropertyNames[i]); os.put(' '); p.writeQuotedString(os, p.myProperties[i]); os.put('\n'); changed = true; } } if(changed) { // Put a trailing null string so we know when to stop reading p.writeQuotedString(os, ""); os.put('\n'); os.put('\n'); } return os; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Properties::readQuotedString(istream& in) { // Read characters until we see a quote char c; while(in.get(c)) if(c == '"') break; // Read characters until we see the close quote string s; while(in.get(c)) { if((c == '\\') && (in.peek() == '"')) in.get(c); else if((c == '\\') && (in.peek() == '\\')) in.get(c); else if(c == '"') break; else if(c == '\r') continue; s += c; } return s; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::writeQuotedString(ostream& out, const string& s) { out.put('"'); for(uInt32 i = 0; i < s.length(); ++i) { if(s[i] == '\\') { out.put('\\'); out.put('\\'); } else if(s[i] == '\"') { out.put('\\'); out.put('"'); } else out.put(s[i]); } out.put('"'); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Properties::operator==(const Properties& properties) const { for(int i = 0; i < LastPropType; ++i) if(myProperties[i] != properties.myProperties[i]) return false; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Properties::operator!=(const Properties& properties) const { return !(*this == properties); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Properties& Properties::operator=(const Properties& properties) { // Do the assignment only if this isn't a self assignment if(this != &properties) { // Now, make myself a copy of the given object copy(properties); } return *this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::setDefault(PropertyType key, const string& value) { ourDefaultProperties[key] = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::copy(const Properties& properties) { // Now, copy each property from properties for(int i = 0; i < LastPropType; ++i) myProperties[i] = properties.myProperties[i]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::print() const { cout << get(Cartridge_MD5) << "|" << get(Cartridge_Name) << "|" << get(Cartridge_Manufacturer) << "|" << get(Cartridge_ModelNo) << "|" << get(Cartridge_Note) << "|" << get(Cartridge_Rarity) << "|" << get(Cartridge_Sound) << "|" << get(Cartridge_Type) << "|" << get(Console_LeftDifficulty) << "|" << get(Console_RightDifficulty)<< "|" << get(Console_TelevisionType) << "|" << get(Console_SwapPorts) << "|" << get(Controller_Left) << "|" << get(Controller_Right) << "|" << get(Controller_SwapPaddles) << "|" << get(Controller_MouseAxis) << "|" << get(Display_Format) << "|" << get(Display_YStart) << "|" << get(Display_Height) << "|" << get(Display_Phosphor) << "|" << get(Display_PPBlend) << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::setDefaults() { for(int i = 0; i < LastPropType; ++i) myProperties[i] = ourDefaultProperties[i]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PropertyType Properties::getPropertyType(const string& name) { for(int i = 0; i < LastPropType; ++i) if(ourPropertyNames[i] == name) return PropertyType(i); // Otherwise, indicate that the item wasn't found return LastPropType; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Properties::printHeader() { cout << "Cartridge_MD5|" << "Cartridge_Name|" << "Cartridge_Manufacturer|" << "Cartridge_ModelNo|" << "Cartridge_Note|" << "Cartridge_Rarity|" << "Cartridge_Sound|" << "Cartridge_Type|" << "Console_LeftDifficulty|" << "Console_RightDifficulty|" << "Console_TelevisionType|" << "Console_SwapPorts|" << "Controller_Left|" << "Controller_Right|" << "Controller_SwapPaddles|" << "Controller_MouseAxis|" << "Display_Format|" << "Display_YStart|" << "Display_Height|" << "Display_Phosphor|" << "Display_PPBlend" << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Properties::ourDefaultProperties[LastPropType] = { "", // Cartridge.MD5 "", // Cartridge.Manufacturer "", // Cartridge.ModelNo "Untitled", // Cartridge.Name "", // Cartridge.Note "", // Cartridge.Rarity "MONO", // Cartridge.Sound "AUTO", // Cartridge.Type "B", // Console.LeftDifficulty "B", // Console.RightDifficulty "COLOR", // Console.TelevisionType "NO", // Console.SwapPorts "JOYSTICK", // Controller.Left "JOYSTICK", // Controller.Right "NO", // Controller.SwapPaddles "AUTO", // Controller.MouseAxis "AUTO", // Display.Format "0", // Display.YStart "0", // Display.Height "NO", // Display.Phosphor "0" // Display.PPBlend }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* const Properties::ourPropertyNames[LastPropType] = { "Cartridge.MD5", "Cartridge.Manufacturer", "Cartridge.ModelNo", "Cartridge.Name", "Cartridge.Note", "Cartridge.Rarity", "Cartridge.Sound", "Cartridge.Type", "Console.LeftDifficulty", "Console.RightDifficulty", "Console.TelevisionType", "Console.SwapPorts", "Controller.Left", "Controller.Right", "Controller.SwapPaddles", "Controller.MouseAxis", "Display.Format", "Display.YStart", "Display.Height", "Display.Phosphor", "Display.PPBlend" }; stella-5.1.1/src/emucore/Props.hxx000066400000000000000000000127051324334165500170770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PROPERTIES_HXX #define PROPERTIES_HXX #include "bspf.hxx" enum PropertyType { Cartridge_MD5, Cartridge_Manufacturer, Cartridge_ModelNo, Cartridge_Name, Cartridge_Note, Cartridge_Rarity, Cartridge_Sound, Cartridge_Type, Console_LeftDifficulty, Console_RightDifficulty, Console_TelevisionType, Console_SwapPorts, Controller_Left, Controller_Right, Controller_SwapPaddles, Controller_MouseAxis, Display_Format, Display_YStart, Display_Height, Display_Phosphor, Display_PPBlend, LastPropType }; /** This class represents objects which maintain a collection of properties. A property is a key and its corresponding value. A properties object can contain a reference to another properties object as its "defaults"; this second properties object is searched if the property key is not found in the original property list. @author Bradford W. Mott */ class Properties { friend class PropertiesSet; public: /** Creates an empty properties object with the specified defaults. The new properties object does not claim ownership of the defaults. */ Properties(); /** Creates a properties list by copying another one @param properties The properties to copy */ Properties(const Properties& properties); public: /** Get the value assigned to the specified key. If the key does not exist then the empty string is returned. @param key The key of the property to lookup @return The value of the property */ const string& get(PropertyType key) const { return key != LastPropType ? myProperties[key] : EmptyString; } /** Set the value associated with key to the given value. @param key The key of the property to set @param value The value to assign to the property */ void set(PropertyType key, const string& value); /** Load properties from the specified input stream @param is The input stream to use @param p The Properties object to write to */ friend istream& operator>>(istream& is, Properties& p); /** Save properties to the specified output stream @param os The output stream to use @param p The Properties object to read from */ friend ostream& operator<<(ostream& os, const Properties& p); /** Print the attributes of this properties object */ void print() const; /** Resets all properties to their defaults */ void setDefaults(); /** Overloaded equality operator(s) @param properties The properties object to compare to @return True if the properties are equal, else false */ bool operator == (const Properties& properties) const; bool operator != (const Properties& properties) const; /** Overloaded assignment operator @param properties The properties object to set myself equal to @return Myself after assignment has taken place */ Properties& operator = (const Properties& properties); /** Set the default value associated with key to the given value. @param key The key of the property to set @param value The value to assign to the property */ static void setDefault(PropertyType key, const string& value); private: /** Helper function to perform a deep copy of the specified properties. Assumes that old properties have already been freed. @param properties The properties object to copy myself from */ void copy(const Properties& properties); /** Read the next quoted string from the specified input stream and returns it. @param in The input stream to use @return The string inside the quotes */ static string readQuotedString(istream& in); /** Write the specified string to the given output stream as a quoted string. @param out The output stream to use @param s The string to output */ static void writeQuotedString(ostream& out, const string& s); /** Get the property type associated with the named property @param name The PropertyType key associated with the given string */ static PropertyType getPropertyType(const string& name); /** When printing each collection of ROM properties, it is useful to see which columns correspond to the output fields; this method provides that output. */ static void printHeader(); private: // The array of properties string myProperties[LastPropType]; // List of default properties to use when none have been provided static string ourDefaultProperties[LastPropType]; // The text strings associated with each property type static const char* const ourPropertyNames[LastPropType]; }; #endif stella-5.1.1/src/emucore/PropsSet.cxx000066400000000000000000000145241324334165500175470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "FSNode.hxx" #include "DefProps.hxx" #include "Props.hxx" #include "PropsSet.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PropertiesSet::PropertiesSet(const string& propsfile) { load(propsfile); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::load(const string& filename) { ifstream in(filename); Properties prop; while(in >> prop) insert(prop); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PropertiesSet::save(const string& filename) const { ofstream out(filename); if(!out) return false; // Only save those entries in the external list for(const auto& i: myExternalProps) out << i.second; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PropertiesSet::getMD5(const string& md5, Properties& properties, bool useDefaults) const { properties.setDefaults(); bool found = false; // There are three lists to search when looking for a properties entry, // which must be done in the following order // If 'useDefaults' is specified, only use the built-in list // // 'save': entries previously inserted that are saved on program exit // 'temp': entries previously inserted that are discarded // 'builtin': the defaults compiled into the program // First check properties from external file if(!useDefaults) { // Check external list auto ext = myExternalProps.find(md5); if(ext != myExternalProps.end()) { properties = ext->second; found = true; } else // Search temp list { auto tmp = myTempProps.find(md5); if(tmp != myTempProps.end()) { properties = tmp->second; found = true; } } } // Otherwise, search the internal database using binary search if(!found) { int low = 0, high = DEF_PROPS_SIZE - 1; while(low <= high) { int i = (low + high) / 2; int cmp = BSPF::compareIgnoreCase(md5, DefProps[i][Cartridge_MD5]); if(cmp == 0) // found it { for(int p = 0; p < LastPropType; ++p) if(DefProps[i][p][0] != 0) properties.set(PropertyType(p), DefProps[i][p]); found = true; break; } else if(cmp < 0) high = i - 1; // look at lower range else low = i + 1; // look at upper range } } return found; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::getMD5WithInsert(const FilesystemNode& rom, const string& md5, Properties& properties) { if(!getMD5(md5, properties)) { properties.set(Cartridge_MD5, md5); // Create a name suitable for using in properties properties.set(Cartridge_Name, rom.getNameWithExt("")); insert(properties, false); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::insert(const Properties& properties, bool save) { // Note that the following code is optimized for insertion when an item // doesn't already exist, and when the external properties file is // relatively small (which is the case with current versions of Stella, // as the properties are built-in) // If an item does exist, it will be removed and insertion done again // This shouldn't be a speed issue, as insertions will only fail with // duplicates when you're changing the current ROM properties, which // most people tend not to do // Since the PropSet is keyed by md5, we can't insert without a valid one const string& md5 = properties.get(Cartridge_MD5); if(md5 == "") return; // Make sure the exact entry isn't already in any list Properties defaultProps; if(getMD5(md5, defaultProps, false) && defaultProps == properties) return; else if(getMD5(md5, defaultProps, true) && defaultProps == properties) { myExternalProps.erase(md5); return; } // The status of 'save' determines which list to save to PropsList& list = save ? myExternalProps : myTempProps; auto ret = list.emplace(md5, properties); if(ret.second == false) { // Remove old item and insert again list.erase(ret.first); list.emplace(md5, properties); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::removeMD5(const string& md5) { // We only remove from the external list myExternalProps.erase(md5); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PropertiesSet::print() const { // We only look at the external properties and the built-in ones; // the temp properties are ignored // Also, any properties entries in the external file override the built-in // ones // The easiest way to merge the lists is to create another temporary one // This isn't fast, but I suspect this method isn't used too often (or at all) // First insert all external props PropsList list = myExternalProps; // Now insert all the built-in ones // Note that if we try to insert a duplicate, the insertion will fail // This is fine, since a duplicate in the built-in list means it should // be overrided anyway (and insertion shouldn't be done) Properties properties; for(int i = 0; i < DEF_PROPS_SIZE; ++i) { properties.setDefaults(); for(int p = 0; p < LastPropType; ++p) if(DefProps[i][p][0] != 0) properties.set(PropertyType(p), DefProps[i][p]); list.emplace(DefProps[i][Cartridge_MD5], properties); } // Now, print the resulting list Properties::printHeader(); for(const auto& i: list) i.second.print(); } stella-5.1.1/src/emucore/PropsSet.hxx000066400000000000000000000104051324334165500175460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PROPERTIES_SET_HXX #define PROPERTIES_SET_HXX #include class FilesystemNode; class OSystem; #include "bspf.hxx" #include "Props.hxx" /** This class maintains an ordered collection of properties, maintained in a C++ map and accessible by ROM md5. The md5 is used since this is the attribute which must be present in each entry in stella.pro and least likely to change. A change in MD5 would mean a change in the game rom image (essentially a different game) and this would necessitate a new entry in the stella.pro file anyway. @author Stephen Anthony */ class PropertiesSet { public: /** Create a properties set object from the specified properties file. */ PropertiesSet(const string& propsfile); public: /** Load properties from the specified file, and create an internal searchable list. @param filename Full pathname of input file to use */ void load(const string& filename); /** Save properties to the specified file. @param filename Full pathname of output file to use @return True on success, false on failure Failure occurs if file couldn't be opened for writing */ bool save(const string& filename) const; /** Get the property from the set with the given MD5. @param md5 The md5 of the property to get @param properties The properties with the given MD5, or the default properties if not found @param useDefaults Use the built-in defaults, ignoring any properties from an external file @return True if the set with the specified md5 was found, else false */ bool getMD5(const string& md5, Properties& properties, bool useDefaults = false) const; /** Get the property from the set with the given MD5, at the same time checking if it exists. If it doesn't, insert a temporary copy into the set. @param rom The ROM file used to calculate the MD5 @param md5 The md5 of the property to get @param properties The properties with the given MD5, or the default properties if not found */ void getMD5WithInsert(const FilesystemNode& rom, const string& md5, Properties& properties); /** Insert the properties into the set. If a duplicate is inserted the old properties are overwritten with the new ones. @param properties The collection of properties @param save Indicates whether the properties should be saved when the program exits */ void insert(const Properties& properties, bool save = true); /** Marks the property with the given MD5 as being removed. @param md5 The md5 of the property to remove */ void removeMD5(const string& md5); /** Prints the contents of the PropertiesSet as a flat file. */ void print() const; private: using PropsList = std::map; // The properties read from an external 'stella.pro' file PropsList myExternalProps; // The properties temporarily inserted by the program, which should // be discarded when the program ends PropsList myTempProps; private: // Following constructors and assignment operators not supported PropertiesSet() = delete; PropertiesSet(const PropertiesSet&) = delete; PropertiesSet(PropertiesSet&&) = delete; PropertiesSet& operator=(const PropertiesSet&) = delete; PropertiesSet& operator=(PropertiesSet&&) = delete; }; #endif stella-5.1.1/src/emucore/Random.hxx000066400000000000000000000064431324334165500172160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef RANDOM_HXX #define RANDOM_HXX #include "bspf.hxx" #include "OSystem.hxx" #include "Serializable.hxx" /** This is a quick-and-dirty random number generator. It is based on information in Chapter 7 of "Numerical Recipes in C". It's a simple linear congruential generator. @author Bradford W. Mott */ class Random : public Serializable { public: /** Create a new random number generator */ Random(const OSystem& osystem) : myOSystem(osystem) { initSeed(); } /** Re-initialize the random number generator with a new seed, to generate a different set of random numbers. */ void initSeed() { myValue = uInt32(myOSystem.getTicks()); } /** Answer the next random number from the random number generator @return A random number */ uInt32 next() const { return (myValue = (myValue * 2416 + 374441) % 1771875); } /** Save the current state of this device to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override { try { out.putString(name()); out.putInt(myValue); } catch(...) { cerr << "ERROR: Random::save" << endl; return false; } return true; } /** Load the current state of this device from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override { try { if(in.getString() != name()) return false; myValue = in.getInt(); } catch(...) { cerr << "ERROR: Random::load" << endl; return false; } return true; } /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Random"; } private: // Set the OSystem we're using const OSystem& myOSystem; // Indicates the next random number // We make this mutable, since it's not immediately obvious that // calling next() should change internal state (ie, the *logical* // state of the object shouldn't change just by asking for another // random number) mutable uInt32 myValue; private: // Following constructors and assignment operators not supported Random() = delete; Random(const Random&) = delete; Random(Random&&) = delete; Random& operator=(const Random&) = delete; Random& operator=(Random&&) = delete; }; #endif stella-5.1.1/src/emucore/SaveKey.cxx000066400000000000000000000064741324334165500173440ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "MT24LC256.hxx" #include "System.hxx" #include "SaveKey.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SaveKey::SaveKey(Jack jack, const Event& event, const System& system, const string& eepromfile, Type type) : Controller(jack, event, system, type) { myEEPROM = make_unique(eepromfile, system); myDigitalPinState[One] = myDigitalPinState[Two] = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SaveKey::SaveKey(Jack jack, const Event& event, const System& system, const string& eepromfile) : SaveKey(jack, event, system, eepromfile, Controller::SaveKey) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SaveKey::~SaveKey() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SaveKey::read(DigitalPin pin) { // We need to override the Controller::read() method, since the timing // of the actual read is important for the EEPROM (we can't just read // 60 times per second in the ::update() method) switch(pin) { // Pin 3: EEPROM SDA // input data from the 24LC256 EEPROM using the I2C protocol case Three: return myDigitalPinState[Three] = myEEPROM->readSDA(); default: return Controller::read(pin); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SaveKey::write(DigitalPin pin, bool value) { // Change the pin state based on value switch(pin) { // Pin 3: EEPROM SDA // output data to the 24LC256 EEPROM using the I2C protocol case Three: myDigitalPinState[Three] = value; myEEPROM->writeSDA(value); break; // Pin 4: EEPROM SCL // output clock data to the 24LC256 EEPROM using the I2C protocol case Four: myDigitalPinState[Four] = value; myEEPROM->writeSCL(value); break; default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SaveKey::reset() { myEEPROM->systemReset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SaveKey::close() { myEEPROM.reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SaveKey::eraseAll() { myEEPROM->eraseAll(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SaveKey::eraseCurrent() { myEEPROM->eraseCurrent(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SaveKey::isPageUsed(const uInt32 page) const { return myEEPROM->isPageUsed(page); } stella-5.1.1/src/emucore/SaveKey.hxx000066400000000000000000000067231324334165500173460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SAVEKEY_HXX #define SAVEKEY_HXX class MT24LC256; #include "Control.hxx" /** Richard Hutchinson's SaveKey "controller", consisting of a 32KB EEPROM accessible using the I2C protocol. This code owes a great debt to Alex Herbert's AtariVox documentation and driver code. @author Stephen Anthony */ class SaveKey : public Controller { public: /** Create a new SaveKey controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller @param eepromfile The file containing the EEPROM data */ SaveKey(Jack jack, const Event& event, const System& system, const string& eepromfile); virtual ~SaveKey(); protected: /** Delegating constructor currently used by both this class and classes that inherit from SaveKey (currently, AtariVox) */ SaveKey(Jack jack, const Event& event, const System& system, const string& eepromfile, Type type); public: using Controller::read; /** Read the value of the specified digital pin for this controller. @param pin The pin of the controller jack to read @return The state of the pin */ bool read(DigitalPin pin) override; /** Write the given value to the specified digital pin for this controller. Writing is only allowed to the pins associated with the PIA. Therefore you cannot write to pin six. @param pin The pin of the controller jack to write to @param value The value to write to the pin */ void write(DigitalPin pin, bool value) override; /** Update the entire digital and analog pin state according to the events currently set. */ void update() override { } /** Notification method invoked by the system after its reset method has been called. It may be necessary to override this method for controllers that need to know a reset has occurred. */ void reset() override; /** Force the EEPROM object to cleanup */ void close() override; /** Erase entire EEPROM to known state ($FF) */ void eraseAll(); /** Erase the pages used by the current ROM to known state ($FF) */ void eraseCurrent(); /** Returns true if the page is used by the current ROM */ bool isPageUsed(const uInt32 page) const; private: // The EEPROM used in the SaveKey unique_ptr myEEPROM; private: // Following constructors and assignment operators not supported SaveKey() = delete; SaveKey(const SaveKey&) = delete; SaveKey(SaveKey&&) = delete; SaveKey& operator=(const SaveKey&) = delete; SaveKey& operator=(SaveKey&&) = delete; }; #endif stella-5.1.1/src/emucore/SerialPort.hxx000066400000000000000000000041461324334165500200600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SERIALPORT_HXX #define SERIALPORT_HXX #include "bspf.hxx" /** This class provides an interface for a standard serial port. For now, this is used when connecting a real AtariVox device, and as such it always uses 19200, 8n1, no flow control. @author Stephen Anthony */ class SerialPort { public: SerialPort() = default; virtual ~SerialPort() = default; /** Open the given serial port with the specified attributes. @param device The name of the port @return False on any errors, else true */ virtual bool openPort(const string& device) { return false; } /** Read a byte from the serial port. @param data Destination for the byte read from the port @return True if a byte was read, else false */ virtual bool readByte(uInt8* data) { return false; } /** Write a byte to the serial port. @param data The byte to write to the port @return True if a byte was written, else false */ virtual bool writeByte(const uInt8* data) { return false; } private: /** Close a previously opened serial port. */ virtual void closePort() { } private: // Following constructors and assignment operators not supported SerialPort(const SerialPort&) = delete; SerialPort(SerialPort&&) = delete; SerialPort& operator=(const SerialPort&) = delete; SerialPort& operator=(SerialPort&&) = delete; }; #endif stella-5.1.1/src/emucore/Serializable.hxx000066400000000000000000000035621324334165500204030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SERIALIZABLE_HXX #define SERIALIZABLE_HXX #include "Serializer.hxx" /** This class provides an interface for (de)serializing objects. It exists strictly to guarantee that all required classes use method signatures as defined below. @author Stephen Anthony */ class Serializable { public: Serializable() = default; virtual ~Serializable() = default; Serializable(const Serializable&) = default; Serializable(Serializable&&) = default; Serializable& operator=(const Serializable&) = default; Serializable& operator=(Serializable&&) = default; /** Save the current state of the object to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ virtual bool save(Serializer& out) const = 0; /** Load the current state of the object from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ virtual bool load(Serializer& in) = 0; /** Get a descriptor for the object name (used in error checking). @return The name of the object */ virtual string name() const = 0; }; #endif stella-5.1.1/src/emucore/Serializer.cxx000066400000000000000000000152371324334165500201030ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "FSNode.hxx" #include "Serializer.hxx" using std::ios; using std::ios_base; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Serializer::Serializer(const string& filename, bool readonly) : myStream(nullptr) { if(readonly) { FilesystemNode node(filename); if(node.isFile() && node.isReadable()) { unique_ptr str = make_unique(filename, ios::in | ios::binary); if(str && str->is_open()) { myStream = std::move(str); myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); rewind(); } } } else { // When using fstreams, we need to manually create the file first // if we want to use it in read/write mode, since it won't be created // if it doesn't already exist // However, if it *does* exist, we don't want to overwrite it // So we open in write and append mode - the write creates the file // when necessary, and the append doesn't delete any data if it // already exists fstream temp(filename, ios::out | ios::app); temp.close(); unique_ptr str = make_unique(filename, ios::in | ios::out | ios::binary); if(str && str->is_open()) { myStream = std::move(str); myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); rewind(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Serializer::Serializer() : myStream(nullptr) { myStream = make_unique(ios::in | ios::out | ios::binary); // For some reason, Windows and possibly OSX needs to store something in // the stream before it is used for the first time if(myStream) { myStream->exceptions( ios_base::failbit | ios_base::badbit | ios_base::eofbit ); putBool(true); rewind(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::rewind() { myStream->clear(); myStream->seekg(ios_base::beg); myStream->seekp(ios_base::beg); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Serializer::getByte() const { char buf; myStream->read(&buf, 1); return buf; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::getByteArray(uInt8* array, uInt32 size) const { myStream->read(reinterpret_cast(array), size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt16 Serializer::getShort() const { uInt16 val = 0; myStream->read(reinterpret_cast(&val), sizeof(uInt16)); return val; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::getShortArray(uInt16* array, uInt32 size) const { myStream->read(reinterpret_cast(array), sizeof(uInt16)*size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Serializer::getInt() const { uInt32 val = 0; myStream->read(reinterpret_cast(&val), sizeof(uInt32)); return val; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::getIntArray(uInt32* array, uInt32 size) const { myStream->read(reinterpret_cast(array), sizeof(uInt32)*size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt64 Serializer::getLong() const { uInt64 val = 0; myStream->read(reinterpret_cast(&val), sizeof(uInt64)); return val; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - double Serializer::getDouble() const { double val = 0.0; myStream->read(reinterpret_cast(&val), sizeof(double)); return val; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Serializer::getString() const { int len = getInt(); string str; str.resize(len); myStream->read(&str[0], len); return str; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Serializer::getBool() const { return getByte() == TruePattern; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putByte(uInt8 value) { myStream->write(reinterpret_cast(&value), 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putByteArray(const uInt8* array, uInt32 size) { myStream->write(reinterpret_cast(array), size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putShort(uInt16 value) { myStream->write(reinterpret_cast(&value), sizeof(uInt16)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putShortArray(const uInt16* array, uInt32 size) { myStream->write(reinterpret_cast(array), sizeof(uInt16)*size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putInt(uInt32 value) { myStream->write(reinterpret_cast(&value), sizeof(uInt32)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putIntArray(const uInt32* array, uInt32 size) { myStream->write(reinterpret_cast(array), sizeof(uInt32)*size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putLong(uInt64 value) { myStream->write(reinterpret_cast(&value), sizeof(uInt64)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putDouble(double value) { myStream->write(reinterpret_cast(&value), sizeof(double)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putString(const string& str) { int len = int(str.length()); putInt(len); myStream->write(str.data(), len); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Serializer::putBool(bool b) { putByte(b ? TruePattern: FalsePattern); } stella-5.1.1/src/emucore/Serializer.hxx000066400000000000000000000150321324334165500201010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SERIALIZER_HXX #define SERIALIZER_HXX #include "bspf.hxx" /** This class implements a Serializer device, whereby data is serialized and read from/written to a binary stream in a system-independent way. The stream can be either an actual file, or an in-memory structure. Bytes are written as characters, shorts as 2 characters (16-bits), integers as 4 characters (32-bits), long integers as 8 bytes (64-bits), strings are written as characters prepended by the length of the string, boolean values are written using a special character pattern. @author Stephen Anthony */ class Serializer { public: /** Creates a new Serializer device for streaming binary data. If a filename is provided, the stream will be to the given filename. Otherwise, the stream will be in memory. If a file is opened readonly, we can never write to it. The valid() method must immediately be called to verify the stream was correctly initialized. */ Serializer(const string& filename, bool readonly = false); Serializer(); public: /** Answers whether the serializer is currently initialized for reading and writing. */ explicit operator bool() const { return myStream != nullptr; } /** Resets the read/write location to the beginning of the stream. */ void rewind(); /** Reads a byte value (unsigned 8-bit) from the current input stream. @result The byte value which has been read from the stream. */ uInt8 getByte() const; /** Reads a byte array (unsigned 8-bit) from the current input stream. @param array The location to store the bytes read @param size The size of the array (number of bytes to read) */ void getByteArray(uInt8* array, uInt32 size) const; /** Reads a short value (unsigned 16-bit) from the current input stream. @result The short value which has been read from the stream. */ uInt16 getShort() const; /** Reads a short array (unsigned 16-bit) from the current input stream. @param array The location to store the shorts read @param size The size of the array (number of shorts to read) */ void getShortArray(uInt16* array, uInt32 size) const; /** Reads an int value (unsigned 32-bit) from the current input stream. @result The int value which has been read from the stream. */ uInt32 getInt() const; /** Reads an integer array (unsigned 32-bit) from the current input stream. @param array The location to store the integers read @param size The size of the array (number of integers to read) */ void getIntArray(uInt32* array, uInt32 size) const; /** Reads a long int value (unsigned 64-bit) from the current input stream. @result The long int value which has been read from the stream. */ uInt64 getLong() const; /** Reads a double value (signed 64-bit) from the current input stream. @result The double value which has been read from the stream. */ double getDouble() const; /** Reads a string from the current input stream. @result The string which has been read from the stream. */ string getString() const; /** Reads a boolean value from the current input stream. @result The boolean value which has been read from the stream. */ bool getBool() const; /** Writes an byte value (unsigned 8-bit) to the current output stream. @param value The byte value to write to the output stream. */ void putByte(uInt8 value); /** Writes a byte array (unsigned 8-bit) to the current output stream. @param array The bytes to write @param size The size of the array (number of bytes to write) */ void putByteArray(const uInt8* array, uInt32 size); /** Writes a short value (unsigned 16-bit) to the current output stream. @param value The short value to write to the output stream. */ void putShort(uInt16 value); /** Writes a short array (unsigned 16-bit) to the current output stream. @param array The short to write @param size The size of the array (number of shorts to write) */ void putShortArray(const uInt16* array, uInt32 size); /** Writes an int value (unsigned 32-bit) to the current output stream. @param value The int value to write to the output stream. */ void putInt(uInt32 value); /** Writes an integer array (unsigned 32-bit) to the current output stream. @param array The integers to write @param size The size of the array (number of integers to write) */ void putIntArray(const uInt32* array, uInt32 size); /** Writes a long int value (unsigned 64-bit) to the current output stream. @param value The long int value to write to the output stream. */ void putLong(uInt64 value); /** Writes a double value (signed 64-bit) to the current output stream. @param value The double value to write to the output stream. */ void putDouble(double value); /** Writes a string to the current output stream. @param str The string to write to the output stream. */ void putString(const string& str); /** Writes a boolean value to the current output stream. @param b The boolean value to write to the output stream. */ void putBool(bool b); private: // The stream to send the serialized data to. unique_ptr myStream; enum { TruePattern = 0xfe, FalsePattern = 0x01 }; private: // Following constructors and assignment operators not supported Serializer(const Serializer&) = delete; Serializer(Serializer&&) = delete; Serializer& operator=(const Serializer&) = delete; Serializer& operator=(Serializer&&) = delete; }; #endif stella-5.1.1/src/emucore/Settings.cxx000066400000000000000000000734571324334165500176020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "OSystem.hxx" #include "Version.hxx" #ifdef DEBUGGER_SUPPORT #include "DebuggerDialog.hxx" #endif #include "Settings.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Settings::Settings(OSystem& osystem) : myOSystem(osystem) { // Video-related options setInternal("video", ""); setInternal("framerate", "0"); setInternal("vsync", "true"); setInternal("fullscreen", "false"); setInternal("center", "false"); setInternal("palette", "standard"); setInternal("timing", "sleep"); setInternal("uimessages", "true"); // TIA specific options setInternal("tia.zoom", "3"); setInternal("tia.inter", "false"); setInternal("tia.aspectn", "91"); setInternal("tia.aspectp", "109"); setInternal("tia.fsfill", "false"); setInternal("tia.dbgcolors", "roygpb"); // TV filtering options setInternal("tv.filter", "0"); setInternal("tv.phosphor", "byrom"); setInternal("tv.phosblend", "50"); setInternal("tv.scanlines", "25"); setInternal("tv.scaninter", "true"); // TV options when using 'custom' mode setInternal("tv.contrast", "0.0"); setInternal("tv.brightness", "0.0"); setInternal("tv.hue", "0.0"); setInternal("tv.saturation", "0.0"); setInternal("tv.gamma", "0.0"); setInternal("tv.sharpness", "0.0"); setInternal("tv.resolution", "0.0"); setInternal("tv.artifacts", "0.0"); setInternal("tv.fringing", "0.0"); setInternal("tv.bleed", "0.0"); // Sound options setInternal("sound", "true"); setInternal("fragsize", "512"); setInternal("freq", "31400"); setInternal("volume", "100"); // Input event options setInternal("keymap", ""); setInternal("joymap", ""); setInternal("combomap", ""); setInternal("joydeadzone", "13"); setInternal("joyallow4", "false"); setInternal("usemouse", "analog"); setInternal("grabmouse", "true"); setInternal("cursor", "2"); setInternal("dsense", "10"); setInternal("msense", "10"); setInternal("tsense", "10"); setInternal("saport", "lr"); setInternal("ctrlcombo", "true"); // Snapshot options setInternal("snapsavedir", ""); setInternal("snaploaddir", ""); setInternal("snapname", "int"); setInternal("sssingle", "false"); setInternal("ss1x", "false"); setInternal("ssinterval", "2"); // Config files and paths setInternal("romdir", ""); setInternal("statedir", ""); setInternal("cheatfile", ""); setInternal("palettefile", ""); setInternal("propsfile", ""); setInternal("nvramdir", ""); setInternal("cfgdir", ""); // ROM browser options setInternal("exitlauncher", "false"); setInternal("launcherres", GUI::Size(900, 600)); setInternal("launcherfont", "medium"); setInternal("launcherexts", "allroms"); setInternal("romviewer", "1"); setInternal("lastrom", ""); // UI-related options #ifdef DEBUGGER_SUPPORT setInternal("dbg.res", GUI::Size(DebuggerDialog::kMediumFontMinW, DebuggerDialog::kMediumFontMinH)); #endif setInternal("uipalette", "standard"); setInternal("listdelay", "300"); setInternal("mwheel", "4"); // Misc options setInternal("autoslot", "false"); setInternal("loglevel", "1"); setInternal("logtoconsole", "0"); setInternal("avoxport", ""); setInternal("fastscbios", "true"); setInternal("threads", "false"); setExternal("romloadcount", "0"); setExternal("maxres", ""); #ifdef DEBUGGER_SUPPORT // Debugger/disassembly options setInternal("dbg.fontsize", "medium"); setInternal("dbg.fontstyle", "0"); setInternal("dbg.uhex", "false"); setInternal("dbg.ghostreadstrap", "true"); setInternal("dis.resolve", "true"); setInternal("dis.gfxformat", "2"); setInternal("dis.showaddr", "true"); setInternal("dis.relocate", "false"); #endif // player settings setInternal("plr.stats", "false"); setInternal("plr.bankrandom", "false"); setInternal("plr.ramrandom", "false"); setInternal("plr.cpurandom", ""); setInternal("plr.colorloss", "false"); setInternal("plr.tv.jitter", "true"); setInternal("plr.tv.jitter_recovery", "10"); setInternal("plr.debugcolors", "false"); setInternal("plr.tiadriven", "false"); setInternal("plr.console", "2600"); // 7800 setInternal("plr.timemachine", false); setInternal("plr.tm.size", 100); setInternal("plr.tm.uncompressed", 30); setInternal("plr.tm.interval", "30f"); // = 0.5 seconds setInternal("plr.tm.horizon", "10m"); // = ~10 minutes // Thumb ARM emulation options setInternal("plr.thumb.trapfatal", "false"); setInternal("plr.eepromaccess", "false"); // developer settings setInternal("dev.settings", "false"); setInternal("dev.stats", "true"); setInternal("dev.bankrandom", "true"); setInternal("dev.ramrandom", "true"); setInternal("dev.cpurandom", "SAXYP"); setInternal("dev.colorloss", "true"); setInternal("dev.tv.jitter", "true"); setInternal("dev.tv.jitter_recovery", "2"); setInternal("dev.debugcolors", "false"); setInternal("dev.tiadriven", "true"); setInternal("dev.console", "2600"); // 7800 setInternal("dev.timemachine", true); setInternal("dev.tm.size", 100); setInternal("dev.tm.uncompressed", 60); setInternal("dev.tm.interval", "1f"); // = 1 frame setInternal("dev.tm.horizon", "10s"); // = ~10 seconds // Thumb ARM emulation options setInternal("dev.thumb.trapfatal", "true"); setInternal("dev.eepromaccess", "true"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Settings::loadConfig() { string line, key, value; string::size_type equalPos, garbage; ifstream in(myOSystem.configFile()); if(!in || !in.is_open()) { myOSystem.logMessage("ERROR: Couldn't load settings file", 0); return; } while(getline(in, line)) { // Strip all whitespace and tabs from the line while((garbage = line.find("\t")) != string::npos) line.erase(garbage, 1); // Ignore commented and empty lines if((line.length() == 0) || (line[0] == ';')) continue; // Search for the equal sign and discard the line if its not found if((equalPos = line.find("=")) == string::npos) continue; // Split the line into key/value pairs and trim any whitespace key = line.substr(0, equalPos); value = line.substr(equalPos + 1, line.length() - key.length() - 1); key = trim(key); value = trim(value); // Check for absent key or value if((key.length() == 0) || (value.length() == 0)) continue; // Only settings which have been previously set are valid if(int idx = getInternalPos(key) != -1) setInternal(key, value, idx, true); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Settings::loadCommandLine(int argc, char** argv) { for(int i = 1; i < argc; ++i) { // strip off the '-' character string key = argv[i]; if(key[0] == '-') { key = key.substr(1, key.length()); // Take care of the arguments which are meant to be executed immediately // (and then Stella should exit) if(key == "help" || key == "listrominfo") { setExternal(key, "true"); return ""; } // Take care of arguments without an option or ones that shouldn't // be saved to the config file if(key == "rominfo" || key == "debug" || key == "holdreset" || key == "holdselect" || key == "takesnapshot") { setExternal(key, "true"); continue; } ostringstream buf; if(++i >= argc) { buf << "Missing argument for '" << key << "'" << endl; myOSystem.logMessage(buf.str(), 0); return ""; } string value = argv[i]; buf.str(""); buf << " key = '" << key << "', value = '" << value << "'"; // Settings read from the commandline must not be saved to // the rc-file, unless they were previously set if(int idx = getInternalPos(key) != -1) { setInternal(key, value, idx); // don't set initialValue here buf << "(I)\n"; } else { setExternal(key, value); buf << "(E)\n"; } myOSystem.logMessage(buf.str(), 2); } else return key; } return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Settings::validate() { string s; int i; s = getString("timing"); if(s != "sleep" && s != "busy") setInternal("timing", "sleep"); i = getInt("tia.aspectn"); if(i < 80 || i > 120) setInternal("tia.aspectn", "90"); i = getInt("tia.aspectp"); if(i < 80 || i > 120) setInternal("tia.aspectp", "100"); s = getString("tia.dbgcolors"); sort(s.begin(), s.end()); if(s != "bgopry") setInternal("tia.dbgcolors", "roygpb"); s = getString("tv.phosphor"); if(s != "always" && s != "byrom") setInternal("tv.phosphor", "byrom"); i = getInt("tv.phosblend"); if(i < 0 || i > 100) setInternal("tv.phosblend", "50"); i = getInt("tv.filter"); if(i < 0 || i > 5) setInternal("tv.filter", "0"); i = getInt("dev.tv.jitter_recovery"); if(i < 1 || i > 20) setInternal("dev.tv.jitter_recovery", "2"); int size = getInt("dev.tm.size"); if(size < 20 || size > 1000) { setInternal("dev.tm.size", 20); size = 20; } i = getInt("dev.tm.uncompressed"); if(i < 0 || i > size) setInternal("dev.tm.uncompressed", size); /*i = getInt("dev.tm.interval"); if(i < 0 || i > 5) setInternal("dev.tm.interval", 0); i = getInt("dev.tm.horizon"); if(i < 0 || i > 6) setInternal("dev.tm.horizon", 1);*/ i = getInt("plr.tv.jitter_recovery"); if(i < 1 || i > 20) setInternal("plr.tv.jitter_recovery", "10"); size = getInt("plr.tm.size"); if(size < 20 || size > 1000) { setInternal("plr.tm.size", 20); size = 20; } i = getInt("plr.tm.uncompressed"); if(i < 0 || i > size) setInternal("plr.tm.uncompressed", size); /*i = getInt("plr.tm.interval"); if(i < 0 || i > 5) setInternal("plr.tm.interval", 3); i = getInt("plr.tm.horizon"); if(i < 0 || i > 6) setInternal("plr.tm.horizon", 5);*/ #ifdef SOUND_SUPPORT i = getInt("volume"); if(i < 0 || i > 100) setInternal("volume", "100"); i = getInt("freq"); if(!(i == 11025 || i == 22050 || i == 31400 || i == 44100 || i == 48000)) setInternal("freq", "31400"); #endif i = getInt("joydeadzone"); if(i < 0) setInternal("joydeadzone", "0"); else if(i > 29) setInternal("joydeadzone", "29"); i = getInt("cursor"); if(i < 0 || i > 3) setInternal("cursor", "2"); i = getInt("dsense"); if(i < 1 || i > 20) setInternal("dsense", "10"); i = getInt("msense"); if(i < 1 || i > 20) setInternal("msense", "10"); i = getInt("tsense"); if(i < 1 || i > 20) setInternal("tsense", "10"); i = getInt("ssinterval"); if(i < 1) setInternal("ssinterval", "2"); else if(i > 10) setInternal("ssinterval", "10"); s = getString("palette"); if(s != "standard" && s != "z26" && s != "user") setInternal("palette", "standard"); s = getString("launcherfont"); if(s != "small" && s != "medium" && s != "large") setInternal("launcherfont", "medium"); s = getString("dbg.fontsize"); if(s != "small" && s != "medium" && s != "large") setInternal("dbg.fontsize", "medium"); i = getInt("romviewer"); if(i < 0) setInternal("romviewer", "0"); else if(i > 2) setInternal("romviewer", "2"); i = getInt("loglevel"); if(i < 0 || i > 2) setInternal("loglevel", "1"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Settings::usage() const { cout << endl << "Stella version " << STELLA_VERSION << endl << endl << "Usage: stella [options ...] romfile" << endl << " Run without any options or romfile to use the ROM launcher" << endl << " Consult the manual for more in-depth information" << endl << endl << "Valid options are:" << endl << endl << " -video Type is one of the following:\n" #ifdef BSPF_WINDOWS << " direct3d Direct3D acceleration\n" #endif << " opengl OpenGL acceleration\n" << " opengles2 OpenGLES 2 acceleration\n" << " opengles OpenGLES 1 acceleration\n" << " software Software mode (no acceleration)\n" << endl << " -vsync <1|0> Enable 'synchronize to vertical blank interrupt'\n" << " -fullscreen <1|0> Enable fullscreen mode\n" << " -center <1|0> Centers game window (if possible)\n" << " -palette \n" << " -framerate Display the given number of frames per second (0 to auto-calculate)\n" << " -timing Use the given type of wait between frames\n" << " -uimessages <1|0> Show onscreen UI messages for different events\n" << endl #ifdef SOUND_SUPPORT << " -sound <1|0> Enable sound generation\n" << " -fragsize The size of sound fragments (must be a power of two)\n" << " -freq Set sound sample output frequency (11025|22050|31400|44100|48000)\n" << " -volume Set the volume (0 - 100)\n" << endl #endif << " -tia.zoom Use the specified zoom level (windowed mode) for TIA image\n" << " -tia.inter <1|0> Enable interpolated (smooth) scaling for TIA image\n" << " -tia.aspectn Scale TIA width by the given percentage in NTSC mode\n" << " -tia.aspectp Scale TIA width by the given percentage in PAL mode\n" << " -tia.fsfill <1|0> Stretch TIA image to fill fullscreen mode\n" << " -tia.dbgcolors Debug colors to use for each object (see manual for description)\n" << endl << " -tv.filter <0-5> Set TV effects off (0) or to specified mode (1-5)\n" << " -tv.phosphor When to use phosphor mode\n" << " -tv.phosblend <0-100> Set default blend level in phosphor mode\n" << " -tv.scanlines <0-100> Set scanline intensity to percentage (0 disables completely)\n" << " -tv.scaninter <1|0> Enable interpolated (smooth) scanlines\n" << " -tv.contrast Set TV effects custom contrast to value 1.0 - 1.0\n" << " -tv.brightness Set TV effects custom brightness to value 1.0 - 1.0\n" << " -tv.hue Set TV effects custom hue to value 1.0 - 1.0\n" << " -tv.saturation Set TV effects custom saturation to value 1.0 - 1.0\n" << " -tv.gamma Set TV effects custom gamma to value 1.0 - 1.0\n" << " -tv.sharpness Set TV effects custom sharpness to value 1.0 - 1.0\n" << " -tv.resolution Set TV effects custom resolution to value 1.0 - 1.0\n" << " -tv.artifacts Set TV effects custom artifacts to value 1.0 - 1.0\n" << " -tv.fringing Set TV effects custom fringing to value 1.0 - 1.0\n" << " -tv.bleed Set TV effects custom bleed to value 1.0 - 1.0\n" << endl << " -cheat Use the specified cheatcode (see manual for description)\n" << " -loglevel <0|1|2> Set level of logging during application run\n" << " -logtoconsole <1|0> Log output to console/commandline\n" << " -joydeadzone Sets 'deadzone' area for analog joysticks (0-29)\n" << " -joyallow4 <1|0> Allow all 4 directions on a joystick to be pressed simultaneously\n" << " -usemouse Use mouse as a controller as specified by ROM properties in given mode(see manual)\n" << " -grabmouse <1|0> Locks the mouse cursor in the TIA window\n" << " -cursor <0,1,2,3> Set cursor state in UI/emulation modes\n" << " -dsense Sensitivity of digital emulated paddle movement (1-20)\n" << " -msense Sensitivity of mouse emulated paddle movement (1-20)\n" << " -tsense Sensitivity of mouse emulated trackball movement (1-20)\n" << " -saport How to assign virtual ports to multiple Stelladaptor/2600-daptors\n" << " -ctrlcombo <1|0> Use key combos involving the Control key (Control-Q for quit may be disabled!)\n" << " -autoslot <1|0> Automatically switch to next save slot when state saving\n" << " -fastscbios <1|0> Disable Supercharger BIOS progress loading bars\n" << " -threads <1|0> Whether to using multi-threading during emulation\n" << " -snapsavedir The directory to save snapshot files to\n" << " -snaploaddir The directory to load snapshot files from\n" << " -snapname Name snapshots according to internal database or ROM\n" << " -sssingle <1|0> Generate single snapshot instead of many\n" << " -ss1x <1|0> Generate TIA snapshot in 1x mode (ignore scaling/effects)\n" << " -ssinterval Display detailed information for the given ROM\n" << " -listrominfo Display contents of stella.pro, one line per ROM entry\n" << " -exitlauncher <1|0> On exiting a ROM, go back to the ROM launcher\n" << " -launcherres The resolution to use in ROM launcher mode\n" << " -launcherfont \n" << " -launcherexts Show ROM info viewer at given zoom level in ROM launcher (0 for off)\n" << " -listdelay Time to wait between keypresses in list widgets (300-1000)\n" << " -mwheel Number of lines the mouse wheel will scroll in UI\n" << " -romdir Directory in which to load ROM files\n" << " -statedir Directory in which to save/load state files\n" << " -cheatfile Full pathname of cheatfile database\n" << " -palettefile Full pathname of user-defined palette file\n" << " -propsfile Full pathname of ROM properties file\n" << " -nvramdir Directory in which to save/load flash/EEPROM files\n" << " -cfgdir Directory in which to save Distella config files\n" << " -avoxport The name of the serial port where an AtariVox is connected\n" << " -holdreset Start the emulator with the Game Reset switch held down\n" << " -holdselect Start the emulator with the Game Select switch held down\n" << " -holdjoy0 Start the emulator with the left joystick direction/fire button held down\n" << " -holdjoy1 Start the emulator with the right joystick direction/fire button held down\n" << " -maxres Used by developers to force the maximum size of the application window\n" << " -help Show the text you're now reading\n" #ifdef DEBUGGER_SUPPORT << endl << " The following options are meant for developers\n" << " Arguments are more fully explained in the manual\n" << endl << " -dis.resolve <1|0> Attempt to resolve code sections in disassembler\n" << " -dis.gfxformat <2|16> Set base to use for displaying GFX sections in disassembler\n" << " -dis.showaddr <1|0> Show opcode addresses in disassembler\n" << " -dis.relocate <1|0> Relocate calls out of address range in disassembler\n" << endl << " -dbg.res The resolution to use in debugger mode\n" << " -dbg.fontsize \n" << " -dbg.fontstyle <0-3> Font style to use in debugger window (bold vs. normal)\n" << " -dbg.ghostreadstrap <1|0> Debugger traps on 'ghost' reads\n" << " -dbg.uhex <0|1> lower-/uppercase HEX display\n" << " -break
Set a breakpoint at 'address'\n" << " -debug Start in debugger mode\n" << endl << " -bs Sets the 'Cartridge.Type' (bankswitch) property\n" << " -type Same as using -bs\n" << " -channels Sets the 'Cartridge.Sound' property\n" << " -ld Sets the 'Console.LeftDifficulty' property\n" << " -rd Sets the 'Console.RightDifficulty' property\n" << " -tv Sets the 'Console.TelevisionType' property\n" << " -sp Sets the 'Console.SwapPorts' property\n" << " -lc Sets the 'Controller.Left' property\n" << " -rc Sets the 'Controller.Right' property\n" << " -bc Same as using both -lc and -rc\n" << " -cp Sets the 'Controller.SwapPaddles' property\n" << " -format Sets the 'Display.Format' property\n" << " -ystart Sets the 'Display.YStart' property\n" << " -height Sets the 'Display.Height' property\n" << " -pp Sets the 'Display.Phosphor' property\n" << " -ppblend Sets the 'Display.PPBlend' property\n" << endl #endif << " Various development related parameters for player settings mode\n" << endl << " -dev.settings <1|0> Select developer (1) or player (0) settings mode\n" << endl << " -plr.stats <1|0> Overlay console info during emulation\n" << " -plr.console <2600|7800> Select console for B/W and Pause key handling and RAM initialization\n" << " -plr.bankrandom <1|0> Randomize the startup bank on reset\n" << " -plr.ramrandom <1|0> Randomize the contents of RAM on reset\n" << " -plr.cpurandom <1|0> Randomize the contents of CPU registers on reset\n" << " -plr.debugcolors <1|0> Enable debug colors\n" << " -plr.colorloss <1|0> Enable PAL color-loss effect\n" << " -plr.tv.jitter <1|0> Enable TV jitter effect\n" << " -plr.tv.jitter_recovery <1-20> Set recovery time for TV jitter effect\n" << " -plr.tiadriven <1|0> Drive unused TIA pins randomly on a read/peek\n" << " -plr.thumb.trapfatal <1|0> Determines whether errors in ARM emulation throw an exception\n" << " -plr.eepromaccess <1|0> Enable messages for AtariVox/SaveKey access messages\n" << endl << " The same parameters but for developer settings mode\n" << " -dev.stats <1|0> Overlay console info during emulation\n" << " -dev.console <2600|7800> Select console for B/W and Pause key handling and RAM initialization\n" << " -dev.bankrandom <1|0> Randomize the startup bank on reset\n" << " -dev.ramrandom <1|0> Randomize the contents of RAM on reset\n" << " -dev.cpurandom <1|0> Randomize the contents of CPU registers on reset\n" << " -dev.debugcolors <1|0> Enable debug colors\n" << " -dev.colorloss <1|0> Enable PAL color-loss effect\n" << " -dev.tv.jitter <1|0> Enable TV jitter effect\n" << " -dev.tv.jitter_recovery <1-20> Set recovery time for TV jitter effect\n" << " -dev.tiadriven <1|0> Drive unused TIA pins randomly on a read/peek\n" << " -dev.thumb.trapfatal <1|0> Determines whether errors in ARM emulation throw an exception\n" << " -dev.eepromaccess <1|0> Enable messages for AtariVox/SaveKey access messages\n" << endl << std::flush; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Variant& Settings::value(const string& key) const { // Try to find the named setting and answer its value int idx = -1; if((idx = getInternalPos(key)) != -1) return myInternalSettings[idx].value; else if((idx = getExternalPos(key)) != -1) return myExternalSettings[idx].value; else return EmptyVariant; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Settings::setValue(const string& key, const Variant& value) { if(int idx = getInternalPos(key) != -1) setInternal(key, value, idx); else setExternal(key, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Settings::saveConfig() { // Do a quick scan of the internal settings to see if any have // changed. If not, we don't need to save them at all. bool settingsChanged = false; for(const auto& s: myInternalSettings) { if(s.value != s.initialValue) { settingsChanged = true; break; } } if(!settingsChanged) return; ofstream out(myOSystem.configFile()); if(!out || !out.is_open()) { myOSystem.logMessage("ERROR: Couldn't save settings file", 0); return; } out << "; Stella configuration file" << endl << ";" << endl << "; Lines starting with ';' are comments and are ignored." << endl << "; Spaces and tabs are ignored." << endl << ";" << endl << "; Format MUST be as follows:" << endl << "; command = value" << endl << ";" << endl << "; Commands are the same as those specified on the commandline," << endl << "; without the '-' character." << endl << ";" << endl << "; Values are the same as those allowed on the commandline." << endl << "; Boolean values are specified as 1 (or true) and 0 (or false)" << endl << ";" << endl; // Write out each of the key and value pairs for(const auto& s: myInternalSettings) out << s.key << " = " << s.value << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Settings::getInternalPos(const string& key) const { for(uInt32 i = 0; i < myInternalSettings.size(); ++i) if(myInternalSettings[i].key == key) return i; return -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Settings::getExternalPos(const string& key) const { for(uInt32 i = 0; i < myExternalSettings.size(); ++i) if(myExternalSettings[i].key == key) return i; return -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Settings::setInternal(const string& key, const Variant& value, int pos, bool useAsInitial) { int idx = -1; if(pos >= 0 && pos < int(myInternalSettings.size()) && myInternalSettings[pos].key == key) { idx = pos; } else { for(uInt32 i = 0; i < myInternalSettings.size(); ++i) { if(myInternalSettings[i].key == key) { idx = i; break; } } } if(idx != -1) { myInternalSettings[idx].key = key; myInternalSettings[idx].value = value; if(useAsInitial) myInternalSettings[idx].initialValue = value; /*cerr << "modify internal: key = " << key << ", value = " << value << ", ivalue = " << myInternalSettings[idx].initialValue << " @ index = " << idx << endl;*/ } else { Setting setting(key, value); if(useAsInitial) setting.initialValue = value; myInternalSettings.push_back(setting); idx = int(myInternalSettings.size()) - 1; /*cerr << "insert internal: key = " << key << ", value = " << value << ", ivalue = " << setting.initialValue << " @ index = " << idx << endl;*/ } return idx; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Settings::setExternal(const string& key, const Variant& value, int pos, bool useAsInitial) { int idx = -1; if(pos >= 0 && pos < int(myExternalSettings.size()) && myExternalSettings[pos].key == key) { idx = pos; } else { for(uInt32 i = 0; i < myExternalSettings.size(); ++i) { if(myExternalSettings[i].key == key) { idx = i; break; } } } if(idx != -1) { myExternalSettings[idx].key = key; myExternalSettings[idx].value = value; if(useAsInitial) myExternalSettings[idx].initialValue = value; /*cerr << "modify external: key = " << key << ", value = " << value << " @ index = " << idx << endl;*/ } else { Setting setting(key, value); if(useAsInitial) setting.initialValue = value; myExternalSettings.push_back(setting); idx = int(myExternalSettings.size()) - 1; /*cerr << "insert external: key = " << key << ", value = " << value << " @ index = " << idx << endl;*/ } return idx; } stella-5.1.1/src/emucore/Settings.hxx000066400000000000000000000112701324334165500175700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SETTINGS_HXX #define SETTINGS_HXX class OSystem; #include "Variant.hxx" #include "bspf.hxx" /** This class provides an interface for accessing frontend specific settings. @author Stephen Anthony */ class Settings { friend class OSystem; public: /** Create a new settings abstract class */ Settings(OSystem& osystem); virtual ~Settings() = default; public: /** This method should be called to load the arguments from the commandline. @return Name of the ROM to load, otherwise empty string */ string loadCommandLine(int argc, char** argv); /** This method should be called *after* settings have been read, to validate (and change, if necessary) any improper settings. */ void validate(); /** This method should be called to display usage information. */ void usage() const; /** Get the value assigned to the specified key. @param key The key of the setting to lookup @return The (variant) value of the setting */ const Variant& value(const string& key) const; /** Set the value associated with the specified key. @param key The key of the setting @param value The (variant) value to assign to the setting */ void setValue(const string& key, const Variant& value); /** Convenience methods to return specific types. @param key The key of the setting to lookup @return The specific type value of the setting */ int getInt(const string& key) const { return value(key).toInt(); } float getFloat(const string& key) const { return value(key).toFloat(); } bool getBool(const string& key) const { return value(key).toBool(); } const string& getString(const string& key) const { return value(key).toString(); } const GUI::Size getSize(const string& key) const { return value(key).toSize(); } protected: /** This method will be called to load the current settings from an rc file. */ virtual void loadConfig(); /** This method will be called to save the current settings to an rc file. */ virtual void saveConfig(); // Trim leading and following whitespace from a string static string trim(string& str) { string::size_type first = str.find_first_not_of(' '); return (first == string::npos) ? EmptyString : str.substr(first, str.find_last_not_of(' ')-first+1); } protected: // The parent OSystem object OSystem& myOSystem; // Structure used for storing settings struct Setting { string key; Variant value; Variant initialValue; Setting(const string& k, const Variant& v, const Variant& i = EmptyVariant) : key(k), value(v), initialValue(i) { } }; using SettingsArray = vector; const SettingsArray& getInternalSettings() const { return myInternalSettings; } const SettingsArray& getExternalSettings() const { return myExternalSettings; } /** Get position in specified array of 'key' */ int getInternalPos(const string& key) const; int getExternalPos(const string& key) const; /** Add key,value pair to specified array at specified position */ int setInternal(const string& key, const Variant& value, int pos = -1, bool useAsInitial = false); int setExternal(const string& key, const Variant& value, int pos = -1, bool useAsInitial = false); private: // Holds key,value pairs that are necessary for Stella to // function and must be saved on each program exit. SettingsArray myInternalSettings; // Holds auxiliary key,value pairs that shouldn't be saved on // program exit. SettingsArray myExternalSettings; private: // Following constructors and assignment operators not supported Settings() = delete; Settings(const Settings&) = delete; Settings(Settings&&) = delete; Settings& operator=(const Settings&) = delete; Settings& operator=(Settings&&) = delete; }; #endif stella-5.1.1/src/emucore/Sound.hxx000066400000000000000000000072441324334165500170660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SOUND_HXX #define SOUND_HXX class OSystem; #include "Serializable.hxx" #include "bspf.hxx" /** This class is an abstract base class for the various sound objects. It has no functionality whatsoever. @author Stephen Anthony */ class Sound : public Serializable { public: /** Create a new sound object. The init method must be invoked before using the object. */ Sound(OSystem& osystem) : myOSystem(osystem) { } virtual ~Sound() = default; public: /** Enables/disables the sound subsystem. @param enable Either true or false, to enable or disable the sound system */ virtual void setEnabled(bool enable) = 0; /** Sets the number of channels (mono or stereo sound). @param channels The number of channels */ virtual void setChannels(uInt32 channels) = 0; /** Sets the display framerate. Sound generation for NTSC and PAL games depends on the framerate, so we need to set it here. @param framerate The base framerate depending on NTSC or PAL ROM */ virtual void setFrameRate(float framerate) = 0; /** Start the sound system, initializing it if necessary. This must be called before any calls are made to derived methods. */ virtual void open() = 0; /** Should be called to stop the sound system. Once called the sound device can be started again using the ::open() method. */ virtual void close() = 0; /** Set the mute state of the sound object. While muted no sound is played. @param state Mutes sound if true, unmute if false */ virtual void mute(bool state) = 0; /** Reset the sound device. */ virtual void reset() = 0; /** Sets the sound register to a given value. @param addr The register address @param value The value to save into the register @param cycle The system cycle at which the register is being updated */ virtual void set(uInt16 addr, uInt8 value, uInt64 cycle) = 0; /** Sets the volume of the sound device to the specified level. The volume is given as a percentage from 0 to 100. Values outside this range indicate that the volume shouldn't be changed at all. @param percent The new volume percentage level for the sound device */ virtual void setVolume(Int32 percent) = 0; /** Adjusts the volume of the sound device based on the given direction. @param direction Increase or decrease the current volume by a predefined amount based on the direction (1 = increase, -1 =decrease) */ virtual void adjustVolume(Int8 direction) = 0; protected: // The OSystem for this sound object OSystem& myOSystem; private: // Following constructors and assignment operators not supported Sound() = delete; Sound(const Sound&) = delete; Sound(Sound&&) = delete; Sound& operator=(const Sound&) = delete; Sound& operator=(Sound&&) = delete; }; #endif stella-5.1.1/src/emucore/Switches.cxx000066400000000000000000000063721324334165500175630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Event.hxx" #include "Props.hxx" #include "Settings.hxx" #include "Switches.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Switches::Switches(const Event& event, const Properties& properties, const Settings& settings) : myEvent(event), mySwitches(0xFF), myIs7800(false) { if(properties.get(Console_RightDifficulty) == "B") { mySwitches &= ~0x80; } else { mySwitches |= 0x80; } if(properties.get(Console_LeftDifficulty) == "B") { mySwitches &= ~0x40; } else { mySwitches |= 0x40; } if(properties.get(Console_TelevisionType) == "COLOR") { mySwitches |= 0x08; } else { mySwitches &= ~0x08; } toggle7800Mode(settings); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Switches::update() { if(myIs7800) { if(myEvent.get(Event::Console7800Pause) != 0) { mySwitches &= ~0x08; } else { mySwitches |= 0x08; } } else { if(myEvent.get(Event::ConsoleColor) != 0) { mySwitches |= 0x08; } else if(myEvent.get(Event::ConsoleBlackWhite) != 0) { mySwitches &= ~0x08; } } if(myEvent.get(Event::ConsoleRightDiffA) != 0) { mySwitches |= 0x80; } else if(myEvent.get(Event::ConsoleRightDiffB) != 0) { mySwitches &= ~0x80; } if(myEvent.get(Event::ConsoleLeftDiffA) != 0) { mySwitches |= 0x40; } else if(myEvent.get(Event::ConsoleLeftDiffB) != 0) { mySwitches &= ~0x40; } if(myEvent.get(Event::ConsoleSelect) != 0) { mySwitches &= ~0x02; } else { mySwitches |= 0x02; } if(myEvent.get(Event::ConsoleReset) != 0) { mySwitches &= ~0x01; } else { mySwitches |= 0x01; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Switches::save(Serializer& out) const { try { out.putByte(mySwitches); } catch(...) { cerr << "ERROR: Switches::save() exception\n"; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Switches::load(Serializer& in) { try { mySwitches = in.getByte(); } catch(...) { cerr << "ERROR: Switches::load() exception\n"; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Switches::toggle7800Mode(const Settings& settings) { bool devSettings = settings.getBool("dev.settings"); myIs7800 = devSettings && (settings.getString("dev.console") == "7800"); return myIs7800; } stella-5.1.1/src/emucore/Switches.hxx000066400000000000000000000070231324334165500175620ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SWITCHES_HXX #define SWITCHES_HXX class Event; class Properties; class Settings; #include "Serializable.hxx" #include "bspf.hxx" /** This class represents the console switches of the game console. @author Bradford W. Mott */ class Switches : public Serializable { /** Riot debug class needs special access to the underlying controller state */ friend class RiotDebug; public: /** Create a new set of switches using the specified events and properties. @param event The event object to use for events @param props The ROM properties to use for the currently enabled ROM @param settings The settings used by the system */ Switches(const Event& event, const Properties& props, const Settings& settings); virtual ~Switches() = default; public: /** Get the value of the console switches. @return The 8 bits which represent the state of the console switches */ uInt8 read() const { return mySwitches; } /** Update the switches variable. */ void update(); /** Save the current state of the switches to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of the switches from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "Switches"; } /** Query the 'Console_TelevisionType' switches bit. @return True if 'Color', false if 'BlackWhite' */ bool tvColor() const { return mySwitches & 0x08; } /** Query the 'Console_LeftDifficulty' switches bit. @return True if 'A', false if 'B' */ bool leftDifficultyA() const { return mySwitches & 0x40; } /** Query the 'Console_RightDifficulty' switches bit. @return True if 'A', false if 'B' */ bool rightDifficultyA() const { return mySwitches & 0x80; } /** Toggle between 2600 and 7800 mode depending on settings. @return True if 7800 mode enabled, else false */ bool toggle7800Mode(const Settings& settings); private: // Reference to the event object to use const Event& myEvent; // State of the console switches uInt8 mySwitches; // Are we in 7800 or 2600 mode? bool myIs7800; private: // Following constructors and assignment operators not supported Switches() = delete; Switches(const Switches&) = delete; Switches(Switches&&) = delete; Switches& operator=(const Switches&) = delete; Switches& operator=(Switches&&) = delete; }; #endif stella-5.1.1/src/emucore/System.cxx000066400000000000000000000152311324334165500172500ustar00rootroot00000000000000//============================================================================ // // MM MM 6666 555555 0000 2222 // MMMM MMMM 66 66 55 00 00 22 22 // MM MMM MM 66 55 00 00 22 // MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator" // MM MM 66 66 55 00 00 22 // MM MM 66 66 55 55 00 00 22 // MM MM 6666 5555 0000 222222 // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #include "Device.hxx" #include "M6502.hxx" #include "M6532.hxx" #include "TIA.hxx" #include "Cart.hxx" #include "System.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - System::System(const OSystem& osystem, M6502& m6502, M6532& m6532, TIA& mTIA, Cartridge& mCart) : myOSystem(osystem), myM6502(m6502), myM6532(m6532), myTIA(mTIA), myCart(mCart), myCycles(0), myDataBusState(0), myDataBusLocked(false), mySystemInAutodetect(false) { // Re-initialize random generator randGenerator().initSeed(); // Initialize page access table PageAccess access(&myNullDevice, System::PA_READ); for(int page = 0; page < NUM_PAGES; ++page) { myPageAccessTable[page] = access; myPageIsDirtyTable[page] = false; } // Bus starts out unlocked (in other words, peek() changes myDataBusState) myDataBusLocked = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::initialize() { // Install all devices myM6532.install(*this); myTIA.install(*this); myCart.install(*this); myM6502.install(*this); // Must always be installed last } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::reset(bool autodetect) { // Provide hint to devices that autodetection is active (or not) mySystemInAutodetect = autodetect; // Reset all devices myCycles = 0; // Must be done first (the reset() methods may use its value) myM6532.reset(); myTIA.reset(); myCart.reset(); myM6502.reset(); // Must always be reset last // There are no dirty pages upon startup clearDirtyPages(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::consoleChanged(ConsoleTiming timing) { myM6532.consoleChanged(timing); myTIA.consoleChanged(timing); myCart.consoleChanged(timing); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool System::isPageDirty(uInt16 start_addr, uInt16 end_addr) const { uInt16 start_page = (start_addr & ADDRESS_MASK) >> PAGE_SHIFT; uInt16 end_page = (end_addr & ADDRESS_MASK) >> PAGE_SHIFT; for(uInt16 page = start_page; page <= end_page; ++page) if(myPageIsDirtyTable[page]) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::clearDirtyPages() { for(uInt32 i = 0; i < NUM_PAGES; ++i) myPageIsDirtyTable[i] = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 System::peek(uInt16 addr, uInt8 flags) { const PageAccess& access = getPageAccess(addr); #ifdef DEBUGGER_SUPPORT // Set access type if(access.codeAccessBase) *(access.codeAccessBase + (addr & PAGE_MASK)) |= flags; else access.device->setAccessFlags(addr, flags); #endif // See if this page uses direct accessing or not uInt8 result; if(access.directPeekBase) result = *(access.directPeekBase + (addr & PAGE_MASK)); else result = access.device->peek(addr); #ifdef DEBUGGER_SUPPORT if(!myDataBusLocked) #endif myDataBusState = result; return result; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::poke(uInt16 addr, uInt8 value, uInt8 flags) { uInt16 page = (addr & ADDRESS_MASK) >> PAGE_SHIFT; const PageAccess& access = myPageAccessTable[page]; #ifdef DEBUGGER_SUPPORT // Set access type if (access.codeAccessBase) *(access.codeAccessBase + (addr & PAGE_MASK)) |= flags; else access.device->setAccessFlags(addr, flags); #endif // See if this page uses direct accessing or not if(access.directPokeBase) { // Since we have direct access to this poke, we can dirty its page *(access.directPokeBase + (addr & PAGE_MASK)) = value; myPageIsDirtyTable[page] = true; } else { // The specific device informs us if the poke succeeded myPageIsDirtyTable[page] = access.device->poke(addr, value); } #ifdef DEBUGGER_SUPPORT if(!myDataBusLocked) #endif myDataBusState = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 System::getAccessFlags(uInt16 addr) const { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); if(access.codeAccessBase) return *(access.codeAccessBase + (addr & PAGE_MASK)); else return access.device->getAccessFlags(addr); #else return 0; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void System::setAccessFlags(uInt16 addr, uInt8 flags) { #ifdef DEBUGGER_SUPPORT const PageAccess& access = getPageAccess(addr); if(access.codeAccessBase) *(access.codeAccessBase + (addr & PAGE_MASK)) |= flags; else access.device->setAccessFlags(addr, flags); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool System::save(Serializer& out) const { try { out.putString(name()); out.putLong(myCycles); out.putByte(myDataBusState); // Save the state of each device if(!myM6502.save(out)) return false; if(!myM6532.save(out)) return false; if(!myTIA.save(out)) return false; if(!myCart.save(out)) return false; if(!randGenerator().save(out)) return false; } catch(...) { cerr << "ERROR: System::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool System::load(Serializer& in) { try { if(in.getString() != name()) return false; myCycles = in.getLong(); myDataBusState = in.getByte(); // Load the state of each device if(!myM6502.load(in)) return false; if(!myM6532.load(in)) return false; if(!myTIA.load(in)) return false; if(!myCart.load(in)) return false; if(!randGenerator().load(in)) return false; } catch(...) { cerr << "ERROR: System::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/System.hxx000066400000000000000000000331161324334165500172570ustar00rootroot00000000000000//============================================================================ // // MM MM 6666 555555 0000 2222 // MMMM MMMM 66 66 55 00 00 22 22 // MM MMM MM 66 55 00 00 22 // MM M MM 66666 55555 00 00 22222 -- "A 6502 Microprocessor Emulator" // MM MM 66 66 55 00 00 22 // MM MM 66 66 55 55 00 00 22 // MM MM 6666 5555 0000 222222 // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SYSTEM_HXX #define SYSTEM_HXX class Device; class M6502; class M6532; class TIA; class NullDevice; #include "bspf.hxx" #include "Device.hxx" #include "NullDev.hxx" #include "Random.hxx" #include "Serializable.hxx" /** This class represents a system consisting of a 6502 microprocessor and a set of devices. The devices are mapped into an addressing space of 2^n bytes (1 <= n <= 16). The addressing space is broken into 2^m byte pages (1 <= m <= n), where a page is the smallest unit a device can use when installing itself in the system. In general the addressing space will be 8192 (2^13) bytes for a 6507 based system and 65536 (2^16) bytes for a 6502 based system. @author Bradford W. Mott */ class System : public Serializable { public: /** Create a new system with an addressing space of 2^13 bytes and pages of 2^6 bytes. */ System(const OSystem& osystem, M6502& m6502, M6532& m6532, TIA& mTIA, Cartridge& mCart); virtual ~System() = default; // Mask to apply to an address before accessing memory static constexpr uInt16 ADDRESS_MASK = (1 << 13) - 1; // Amount to shift an address by to determine what page it's on static constexpr uInt16 PAGE_SHIFT = 6; // Size of a page static constexpr uInt16 PAGE_SIZE = (1 << PAGE_SHIFT); // Mask to apply to an address to obtain its page offset static constexpr uInt16 PAGE_MASK = PAGE_SIZE - 1; // Number of pages in the system static constexpr uInt16 NUM_PAGES = 1 << (13 - PAGE_SHIFT); public: /** Initialize system and all attached devices to known state. */ void initialize(); /** Reset the system cycle counter, the attached devices, and the attached processor of the system. @param autodetect A hint to devices that the system is currently in autodetect mode. That is, the system is being run to autodetect certain device settings before actual emulation will begin. Certain devices may use this hint to act differently under those circumstances. */ void reset(bool autodetect = false); public: /** Answer the OSystem attached to the system. @return The attached OSystem */ const OSystem& oSystem() const { return myOSystem; } /** Answer the 6502 microprocessor attached to the system. If a processor has not been attached calling this function will fail. @return The attached 6502 microprocessor */ M6502& m6502() const { return myM6502; } /** Answer the 6532 processor attached to the system. If a processor has not been attached calling this function will fail. @return The attached 6532 microprocessor */ M6532& m6532() const { return myM6532; } /** Answer the TIA device attached to the system. @return The attached TIA device */ TIA& tia() const { return myTIA; } /** Answer the random generator attached to the system. @return The random generator */ Random& randGenerator() const { return myOSystem.random(); } /** Get the null device associated with the system. Every system has a null device associated with it that's used by pages which aren't mapped to "real" devices. @return The null device associated with the system */ const NullDevice& nullDevice() const { return myNullDevice; } public: /** Get the number of system cycles which have passed since the system was created. @return The number of system cycles which have passed */ uInt64 cycles() const { return myCycles; } /** Increment the system cycles by the specified number of cycles. @param amount The amount to add to the system cycles counter */ void incrementCycles(uInt32 amount) { myCycles += amount; } /** Informs all attached devices that the console type has changed. */ void consoleChanged(ConsoleTiming timing); /** Answers whether the system is currently in device autodetect mode. */ bool autodetectMode() const { return mySystemInAutodetect; } public: /** Get the current state of the data bus in the system. The current state is the last data that was accessed by the system. @return The data bus state */ uInt8 getDataBusState() const { return myDataBusState; } /** Get the current state of the data bus in the system, taking into account that certain bits are in Z-state (undriven). In those cases, the bits are floating, but will usually be the same as the last data bus value (the 'usually' is emulated by randomly driving certain bits high). However, some CMOS EPROM chips always drive Z-state bits high. This is emulated by hmask, which specifies to push a specific Z-state bit high. @param zmask The bits which are in Z-state @param hmask The bits which should always be driven high @return The data bus state */ uInt8 getDataBusState(uInt8 zmask, uInt8 hmask = 0x00) const { // For the pins that are floating, randomly decide which are high or low // Otherwise, they're specifically driven high return (myDataBusState | (randGenerator().next() | hmask)) & zmask; } /** Get the byte at the specified address. No masking of the address occurs before it's sent to the device mapped at the address. @param address The address from which the value should be loaded @param flags Indicates that this address has the given flags for type of access (CODE, DATA, GFX, etc) @return The byte at the specified address */ uInt8 peek(uInt16 address, uInt8 flags = 0); /** Change the byte at the specified address to the given value. No masking of the address occurs before it's sent to the device mapped at the address. This method sets the 'page dirty' if the write succeeds. In the case of direct-access pokes, the write always succeeds. Otherwise, if the device is handling the poke, we depend on its return value for this information. @param address The address where the value should be stored @param value The value to be stored at the address */ void poke(uInt16 address, uInt8 value, uInt8 flags = 0); /** Lock/unlock the data bus. When the bus is locked, peek() and poke() don't update the bus state. The bus should be unlocked while the CPU is running (normal emulation, or when the debugger is stepping/advancing). It should be locked while the debugger is active but not running the CPU. This is so the debugger can use System.peek() to examine memory/registers without changing the state of the system. */ void lockDataBus() { myDataBusLocked = true; } void unlockDataBus() { myDataBusLocked = false; } /** Access and modify the disassembly type flags for the given address. Note that while any flag can be used, the disassembly only really acts on CODE/GFX/PGFX/DATA/ROW. */ uInt8 getAccessFlags(uInt16 address) const; void setAccessFlags(uInt16 address, uInt8 flags); public: /** Describes how a page can be accessed */ enum PageAccessType { PA_READ = 1 << 0, PA_WRITE = 1 << 1, PA_READWRITE = PA_READ | PA_WRITE }; /** Structure used to specify access methods for a page */ struct PageAccess { /** Pointer to a block of memory or the null pointer. The null pointer indicates that the device's peek method should be invoked for reads to this page, while other values are the base address of an array to directly access for reads to this page. */ uInt8* directPeekBase; /** Pointer to a block of memory or the null pointer. The null pointer indicates that the device's poke method should be invoked for writes to this page, while other values are the base address of an array to directly access for pokes to this page. */ uInt8* directPokeBase; /** Pointer to a lookup table for marking an address as CODE. A CODE section is defined as any address that appears in the program counter. Currently, this is used by the debugger/disassembler to conclusively determine if a section of address space is CODE, even if the disassembler failed to mark it as such. */ uInt8* codeAccessBase; /** Pointer to the device associated with this page or to the system's null device if the page hasn't been mapped to a device. */ Device* device; /** The manner in which the pages are accessed by the system (READ, WRITE, READWRITE) */ PageAccessType type; // Constructors PageAccess() : directPeekBase(nullptr), directPokeBase(nullptr), codeAccessBase(nullptr), device(nullptr), type(System::PA_READ) { } PageAccess(Device* dev, PageAccessType access) : directPeekBase(nullptr), directPokeBase(nullptr), codeAccessBase(nullptr), device(dev), type(access) { } }; /** Set the page accessing method for the specified address. @param addr The address/page accessing methods should be set for @param access The accessing methods to be used by the page */ void setPageAccess(uInt16 addr, const PageAccess& access) { myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT] = access; } /** Get the page accessing method for the specified address. @param addr The address/page to get accessing methods for @return The accessing methods used by the page */ const PageAccess& getPageAccess(uInt16 addr) const { return myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT]; } /** Get the page type for the given address. @param addr The address contained in the page in questions @return The type of page that contains the given address */ System::PageAccessType getPageAccessType(uInt16 addr) const { return myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT].type; } /** Mark the page containing this address as being dirty. @param addr Determines the page that is dirty */ void setDirtyPage(uInt16 addr) { myPageIsDirtyTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT] = true; } /** Answer whether any pages in given range of addresses have been marked as dirty. @param start_addr The start address; determines the start page @param end_addr The end address; determines the end page */ bool isPageDirty(uInt16 start_addr, uInt16 end_addr) const; /** Mark all pages as clean (ie, turn off the dirty flag). */ void clearDirtyPages(); /** Save the current state of this system to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this system from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "System"; } private: const OSystem& myOSystem; // 6502 processor attached to the system M6502& myM6502; // 6532 processor attached to the system M6532& myM6532; // TIA device attached to the system TIA& myTIA; // Cartridge device attached to the system Cartridge& myCart; // Number of system cycles executed since last reset uInt64 myCycles; // Null device to use for page which are not installed NullDevice myNullDevice; // The list of PageAccess structures PageAccess myPageAccessTable[NUM_PAGES]; // The list of dirty pages bool myPageIsDirtyTable[NUM_PAGES]; // The current state of the Data Bus uInt8 myDataBusState; // Whether or not peek() updates the data bus state. This // is true during normal emulation, and false when the // debugger is active. bool myDataBusLocked; // Whether autodetection is currently running (ie, the emulation // core is attempting to autodetect display settings, cart modes, etc) // Some parts of the codebase need to act differently in such a case bool mySystemInAutodetect; private: // Following constructors and assignment operators not supported System() = delete; System(const System&) = delete; System(System&&) = delete; System& operator=(const System&) = delete; System& operator=(System&&) = delete; }; #endif stella-5.1.1/src/emucore/TIASnd.cxx000066400000000000000000000245151324334165500170530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "System.hxx" #include "TIAConstants.hxx" #include "TIASnd.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIASound::TIASound(Int32 outputFrequency) : myChannelMode(Hardware2Stereo), myOutputFrequency(outputFrequency), myOutputCounter(0), myVolumePercentage(100) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASound::reset() { // Fill the polynomials polyInit(Bit4, 4, 4, 3); polyInit(Bit5, 5, 5, 3); polyInit(Bit9, 9, 9, 5); // Initialize instance variables for(int chan = 0; chan <= 1; ++chan) { myVolume[chan] = 0; myDivNCnt[chan] = 0; myDivNMax[chan] = 0; myDiv3Cnt[chan] = 3; myAUDC[chan] = 0; myAUDF[chan] = 0; myAUDV[chan] = 0; myP4[chan] = 0; myP5[chan] = 0; myP9[chan] = 0; } myOutputCounter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASound::outputFrequency(Int32 freq) { myOutputFrequency = freq; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIASound::channels(uInt32 hardware, bool stereo) { if(hardware == 1) myChannelMode = Hardware1; else myChannelMode = stereo ? Hardware2Stereo : Hardware2Mono; switch(myChannelMode) { case Hardware1: return "Hardware1"; case Hardware2Mono: return "Hardware2Mono"; case Hardware2Stereo: return "Hardware2Stereo"; } return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASound::set(uInt16 address, uInt8 value) { int chan = ~address & 0x1; switch(address) { case TIARegister::AUDC0: case TIARegister::AUDC1: myAUDC[chan] = value & 0x0f; break; case TIARegister::AUDF0: case TIARegister::AUDF1: myAUDF[chan] = value & 0x1f; break; case TIARegister::AUDV0: case TIARegister::AUDV1: myAUDV[chan] = (value & 0x0f) << AUDV_SHIFT; break; default: return; } uInt16 newVal = 0; // An AUDC value of 0 is a special case if (myAUDC[chan] == SET_TO_1 || myAUDC[chan] == POLY5_POLY5) { // Indicate the clock is zero so no processing will occur, // and set the output to the selected volume newVal = 0; myVolume[chan] = (myAUDV[chan] * myVolumePercentage) / 100; } else { // Otherwise calculate the 'divide by N' value newVal = myAUDF[chan] + 1; // If bits 2 & 3 are set, then multiply the 'div by n' count by 3 if((myAUDC[chan] & DIV3_MASK) == DIV3_MASK && myAUDC[chan] != POLY5_DIV3) newVal *= 3; } // Only reset those channels that have changed if(newVal != myDivNMax[chan]) { // Reset the divide by n counters myDivNMax[chan] = newVal; // If the channel is now volume only or was volume only, // reset the counter (otherwise let it complete the previous) if ((myDivNCnt[chan] == 0) || (newVal == 0)) myDivNCnt[chan] = newVal; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIASound::get(uInt16 address) const { switch(address) { case TIARegister::AUDC0: return myAUDC[0]; case TIARegister::AUDC1: return myAUDC[1]; case TIARegister::AUDF0: return myAUDF[0]; case TIARegister::AUDF1: return myAUDF[1]; case TIARegister::AUDV0: return myAUDV[0] >> AUDV_SHIFT; case TIARegister::AUDV1: return myAUDV[1] >> AUDV_SHIFT; default: return 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASound::volume(uInt32 percent) { if(percent <= 100) myVolumePercentage = percent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASound::process(Int16* buffer, uInt32 samples) { // Make temporary local copy uInt8 audc0 = myAUDC[0], audc1 = myAUDC[1]; uInt8 p5_0 = myP5[0], p5_1 = myP5[1]; uInt8 div_n_cnt0 = myDivNCnt[0], div_n_cnt1 = myDivNCnt[1]; Int16 v0 = myVolume[0], v1 = myVolume[1]; // Take external volume into account Int16 audv0 = (myAUDV[0] * myVolumePercentage) / 100, audv1 = (myAUDV[1] * myVolumePercentage) / 100; // Loop until the sample buffer is full while(samples > 0) { // Process channel 0 if (div_n_cnt0 > 1) { div_n_cnt0--; } else if (div_n_cnt0 == 1) { int prev_bit5 = Bit5[p5_0]; div_n_cnt0 = myDivNMax[0]; // The P5 counter has multiple uses, so we increment it here p5_0++; if (p5_0 == POLY5_SIZE) p5_0 = 0; // Check clock modifier for clock tick if ((audc0 & 0x02) == 0 || ((audc0 & 0x01) == 0 && Div31[p5_0]) || ((audc0 & 0x01) == 1 && Bit5[p5_0]) || ((audc0 & 0x0f) == POLY5_DIV3 && Bit5[p5_0] != prev_bit5)) { if (audc0 & 0x04) // Pure modified clock selected { if ((audc0 & 0x0f) == POLY5_DIV3) // POLY5 -> DIV3 mode { if ( Bit5[p5_0] != prev_bit5 ) { myDiv3Cnt[0]--; if ( !myDiv3Cnt[0] ) { myDiv3Cnt[0] = 3; v0 = v0 ? 0 : audv0; } } } else { // If the output was set turn it off, else turn it on v0 = v0 ? 0 : audv0; } } else if (audc0 & 0x08) // Check for p5/p9 { if (audc0 == POLY9) // Check for poly9 { // Increase the poly9 counter myP9[0]++; if (myP9[0] == POLY9_SIZE) myP9[0] = 0; v0 = Bit9[myP9[0]] ? audv0 : 0; } else if ( audc0 & 0x02 ) { v0 = (v0 || audc0 & 0x01) ? 0 : audv0; } else // Must be poly5 { v0 = Bit5[p5_0] ? audv0 : 0; } } else // Poly4 is the only remaining option { // Increase the poly4 counter myP4[0]++; if (myP4[0] == POLY4_SIZE) myP4[0] = 0; v0 = Bit4[myP4[0]] ? audv0 : 0; } } } // Process channel 1 if (div_n_cnt1 > 1) { div_n_cnt1--; } else if (div_n_cnt1 == 1) { int prev_bit5 = Bit5[p5_1]; div_n_cnt1 = myDivNMax[1]; // The P5 counter has multiple uses, so we increment it here p5_1++; if (p5_1 == POLY5_SIZE) p5_1 = 0; // Check clock modifier for clock tick if ((audc1 & 0x02) == 0 || ((audc1 & 0x01) == 0 && Div31[p5_1]) || ((audc1 & 0x01) == 1 && Bit5[p5_1]) || ((audc1 & 0x0f) == POLY5_DIV3 && Bit5[p5_1] != prev_bit5)) { if (audc1 & 0x04) // Pure modified clock selected { if ((audc1 & 0x0f) == POLY5_DIV3) // POLY5 -> DIV3 mode { if ( Bit5[p5_1] != prev_bit5 ) { myDiv3Cnt[1]--; if ( ! myDiv3Cnt[1] ) { myDiv3Cnt[1] = 3; v1 = v1 ? 0 : audv1; } } } else { // If the output was set turn it off, else turn it on v1 = v1 ? 0 : audv1; } } else if (audc1 & 0x08) // Check for p5/p9 { if (audc1 == POLY9) // Check for poly9 { // Increase the poly9 counter myP9[1]++; if (myP9[1] == POLY9_SIZE) myP9[1] = 0; v1 = Bit9[myP9[1]] ? audv1 : 0; } else if ( audc1 & 0x02 ) { v1 = (v1 || audc1 & 0x01) ? 0 : audv1; } else // Must be poly5 { v1 = Bit5[p5_1] ? audv1 : 0; } } else // Poly4 is the only remaining option { // Increase the poly4 counter myP4[1]++; if (myP4[1] == POLY4_SIZE) myP4[1] = 0; v1 = Bit4[myP4[1]] ? audv1 : 0; } } } myOutputCounter += myOutputFrequency; switch(myChannelMode) { case Hardware2Mono: // mono sampling with 2 hardware channels while((samples > 0) && (myOutputCounter >= 31400)) { Int16 byte = v0 + v1; *(buffer++) = byte; *(buffer++) = byte; myOutputCounter -= 31400; samples--; } break; case Hardware2Stereo: // stereo sampling with 2 hardware channels while((samples > 0) && (myOutputCounter >= 31400)) { *(buffer++) = v0; *(buffer++) = v1; myOutputCounter -= 31400; samples--; } break; case Hardware1: // mono/stereo sampling with only 1 hardware channel while((samples > 0) && (myOutputCounter >= 31400)) { *(buffer++) = v0 + v1; myOutputCounter -= 31400; samples--; } break; } } // Save for next round myP5[0] = p5_0; myP5[1] = p5_1; myVolume[0] = v0; myVolume[1] = v1; myDivNCnt[0] = div_n_cnt0; myDivNCnt[1] = div_n_cnt1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASound::polyInit(uInt8* poly, int size, int f0, int f1) { int mask = (1 << size) - 1, x = mask; for(int i = 0; i < mask; i++) { int bit0 = ( ( size - f0 ) ? ( x >> ( size - f0 ) ) : x ) & 0x01; int bit1 = ( ( size - f1 ) ? ( x >> ( size - f1 ) ) : x ) & 0x01; poly[i] = x & 1; // calculate next bit x = ( x >> 1 ) | ( ( bit0 ^ bit1 ) << ( size - 1) ); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8 TIASound::Div31[POLY5_SIZE] = { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; stella-5.1.1/src/emucore/TIASnd.hxx000066400000000000000000000132111324334165500170470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIASOUND_HXX #define TIASOUND_HXX #include "bspf.hxx" /** This class implements a fairly accurate emulation of the TIA sound hardware. This class uses code/ideas from z26 and MESS. Currently, the sound generation routines work at 31400Hz only. Resampling can be done by passing in a different output frequency. @author Bradford W. Mott, Stephen Anthony, z26 and MESS teams */ class TIASound { public: /** Create a new TIA Sound object using the specified output frequency */ TIASound(Int32 outputFrequency = 31400); public: /** Reset the sound emulation to its power-on state */ void reset(); /** Set the frequency output samples should be generated at */ void outputFrequency(Int32 freq); /** Selects the number of audio channels per sample. There are two factors to consider: hardware capability and desired mixing. @param hardware The number of channels supported by the sound system @param stereo Whether to output the internal sound signals into 1 or 2 channels @return Status of the channel configuration used */ string channels(uInt32 hardware, bool stereo); public: /** Sets the specified sound register to the given value @param address Register address @param value Value to store in the register */ void set(uInt16 address, uInt8 value); /** Gets the specified sound register's value @param address Register address */ uInt8 get(uInt16 address) const; /** Create sound samples based on the current sound register settings in the specified buffer. NOTE: If channels is set to stereo then the buffer will need to be twice as long as the number of samples. @param buffer The location to store generated samples @param samples The number of samples to generate */ void process(Int16* buffer, uInt32 samples); /** Set the volume of the samples created (0-100) */ void volume(uInt32 percent); private: void polyInit(uInt8* poly, int size, int f0, int f1); private: // Definitions for AUDCx (15, 16) enum AUDCxRegister { SET_TO_1 = 0x00, // 0000 POLY4 = 0x01, // 0001 DIV31_POLY4 = 0x02, // 0010 POLY5_POLY4 = 0x03, // 0011 PURE1 = 0x04, // 0100 PURE2 = 0x05, // 0101 DIV31_PURE = 0x06, // 0110 POLY5_2 = 0x07, // 0111 POLY9 = 0x08, // 1000 POLY5 = 0x09, // 1001 DIV31_POLY5 = 0x0a, // 1010 POLY5_POLY5 = 0x0b, // 1011 DIV3_PURE = 0x0c, // 1100 DIV3_PURE2 = 0x0d, // 1101 DIV93_PURE = 0x0e, // 1110 POLY5_DIV3 = 0x0f // 1111 }; enum { POLY4_SIZE = 0x000f, POLY5_SIZE = 0x001f, POLY9_SIZE = 0x01ff, DIV3_MASK = 0x0c, AUDV_SHIFT = 10 // shift 2 positions for AUDV, // then another 8 for 16-bit sound }; enum ChannelMode { Hardware2Mono, // mono sampling with 2 hardware channels Hardware2Stereo, // stereo sampling with 2 hardware channels Hardware1 // mono/stereo sampling with only 1 hardware channel }; private: // Structures to hold the 6 tia sound control bytes uInt8 myAUDC[2]; // AUDCx (15, 16) uInt8 myAUDF[2]; // AUDFx (17, 18) Int16 myAUDV[2]; // AUDVx (19, 1A) Int16 myVolume[2]; // Last output volume for each channel uInt8 myP4[2]; // Position pointer for the 4-bit POLY array uInt8 myP5[2]; // Position pointer for the 5-bit POLY array uInt16 myP9[2]; // Position pointer for the 9-bit POLY array uInt8 myDivNCnt[2]; // Divide by n counter. one for each channel uInt8 myDivNMax[2]; // Divide by n maximum, one for each channel uInt8 myDiv3Cnt[2]; // Div 3 counter, used for POLY5_DIV3 mode ChannelMode myChannelMode; Int32 myOutputFrequency; Int32 myOutputCounter; uInt32 myVolumePercentage; /* Initialize the bit patterns for the polynomials (at runtime). The 4bit and 5bit patterns are the identical ones used in the tia chip. Though the patterns could be packed with 8 bits per byte, using only a single bit per byte keeps the math simple, which is important for efficient processing. */ uInt8 Bit4[POLY4_SIZE]; uInt8 Bit5[POLY5_SIZE]; uInt8 Bit9[POLY9_SIZE]; /* The 'Div by 31' counter is treated as another polynomial because of the way it operates. It does not have a 50% duty cycle, but instead has a 13:18 ratio (of course, 13+18 = 31). This could also be implemented by using counters. */ static const uInt8 Div31[POLY5_SIZE]; private: // Following constructors and assignment operators not supported TIASound(const TIASound&) = delete; TIASound(TIASound&&) = delete; TIASound& operator=(const TIASound&) = delete; TIASound& operator=(TIASound&&) = delete; }; #endif stella-5.1.1/src/emucore/TIASurface.cxx000066400000000000000000000315761324334165500177240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Settings.hxx" #include "OSystem.hxx" #include "Console.hxx" #include "TIA.hxx" #include "TIASurface.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIASurface::TIASurface(OSystem& system) : myOSystem(system), myFB(system.frameBuffer()), myTIA(nullptr), myFilter(Filter::Normal), myUsePhosphor(false), myPhosphorPercent(0.60f), myScanlinesEnabled(false), myPalette(nullptr) { // Load NTSC filter settings myNTSCFilter.loadConfig(myOSystem.settings()); // Create a surface for the TIA image and scanlines; we'll need them eventually myTiaSurface = myFB.allocateSurface(AtariNTSC::outWidth(kTIAW), kTIAH); // Generate scanline data, and a pre-defined scanline surface uInt32 scanData[kScanH]; for(int i = 0; i < kScanH; i+=2) { scanData[i] = 0x00000000; scanData[i+1] = 0xff000000; } mySLineSurface = myFB.allocateSurface(1, kScanH, scanData); // Base TIA surface for use in taking snapshots in 1x mode myBaseTiaSurface = myFB.allocateSurface(kTIAW*2, kTIAH); memset(myRGBFramebuffer, 0, sizeof(myRGBFramebuffer)); // Enable/disable threading in the NTSC TV effects renderer myNTSCFilter.enableThreading(myOSystem.settings().getBool("threads")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::initialize(const Console& console, const VideoMode& mode) { myTIA = &(console.tia()); myTiaSurface->setDstPos(mode.image.x(), mode.image.y()); myTiaSurface->setDstSize(mode.image.width(), mode.image.height()); mySLineSurface->setDstPos(mode.image.x(), mode.image.y()); mySLineSurface->setDstSize(mode.image.width(), mode.image.height()); // Phosphor mode can be enabled either globally or per-ROM bool p_enable = myOSystem.settings().getString("tv.phosphor") == "always" || console.properties().get(Display_Phosphor) == "YES"; int p_blend = atoi(console.properties().get(Display_PPBlend).c_str()); enablePhosphor(p_enable, p_blend); setNTSC(NTSCFilter::Preset(myOSystem.settings().getInt("tv.filter")), false); // Scanline repeating is sensitive to non-integral vertical resolution, // so rounding is performed to eliminate it // This won't be 100% accurate, but non-integral scaling isn't 100% // accurate anyway mySLineSurface->setSrcSize(1, int(2 * float(mode.image.height()) / floor((float(mode.image.height()) / myTIA->height()) + 0.5))); #if 0 cerr << "INITIALIZE:\n" << "TIA:\n" << "src: " << myTiaSurface->srcRect() << endl << "dst: " << myTiaSurface->dstRect() << endl << endl; cerr << "SLine:\n" << "src: " << mySLineSurface->srcRect() << endl << "dst: " << mySLineSurface->dstRect() << endl << endl; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::setPalette(const uInt32* tia_palette, const uInt32* rgb_palette) { myPalette = tia_palette; // The NTSC filtering needs access to the raw RGB data, since it calculates // its own internal palette myNTSCFilter.setTIAPalette(rgb_palette); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const FBSurface& TIASurface::baseSurface(GUI::Rect& rect) const { uInt32 tiaw = myTIA->width(), width = tiaw * 2, height = myTIA->height(); rect.setBounds(0, 0, width, height); // Get Blargg buffer and width uInt32 *blarggBuf, blarggPitch; myTiaSurface->basePtr(blarggBuf, blarggPitch); double blarggXFactor = double(blarggPitch) / width; bool useBlargg = ntscEnabled(); // Fill the surface with pixels from the TIA, scaled 2x horizontally uInt32 *buf_ptr, pitch; myBaseTiaSurface->basePtr(buf_ptr, pitch); for(uInt32 y = 0; y < height; ++y) { for(uInt32 x = 0; x < width; ++x) { if (useBlargg) *buf_ptr++ = blarggBuf[y * blarggPitch + uInt32(nearbyint(x * blarggXFactor))]; else *buf_ptr++ = myPalette[*(myTIA->frameBuffer() + y * tiaw + x / 2)]; } } return *myBaseTiaSurface; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 TIASurface::pixel(uInt32 idx, uInt8 shift) { return myPalette[*(myTIA->frameBuffer() + idx) | shift]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::setNTSC(NTSCFilter::Preset preset, bool show) { ostringstream buf; if(preset == NTSCFilter::PRESET_OFF) { enableNTSC(false); buf << "TV filtering disabled"; } else { enableNTSC(true); const string& mode = myNTSCFilter.setPreset(preset); buf << "TV filtering (" << mode << " mode)"; } myOSystem.settings().setValue("tv.filter", int(preset)); if(show) myFB.showMessage(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::setScanlineIntensity(int amount) { ostringstream buf; if(ntscEnabled()) { uInt32 intensity = enableScanlines(amount); buf << "Scanline intensity at " << intensity << "%"; myOSystem.settings().setValue("tv.scanlines", intensity); } else buf << "Scanlines only available in TV filtering mode"; myFB.showMessage(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::toggleScanlineInterpolation() { ostringstream buf; if(ntscEnabled()) { bool enable = !myOSystem.settings().getBool("tv.scaninter"); enableScanlineInterpolation(enable); buf << "Scanline interpolation " << (enable ? "enabled" : "disabled"); myOSystem.settings().setValue("tv.scaninter", enable); } else buf << "Scanlines only available in TV filtering mode"; myFB.showMessage(buf.str()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 TIASurface::enableScanlines(int relative, int absolute) { FBSurface::Attributes& attr = mySLineSurface->attributes(); if(relative == 0) attr.blendalpha = absolute; else attr.blendalpha += relative; attr.blendalpha = std::min(100u, attr.blendalpha); mySLineSurface->applyAttributes(); mySLineSurface->setDirty(); return attr.blendalpha; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::enableScanlineInterpolation(bool enable) { FBSurface::Attributes& attr = mySLineSurface->attributes(); attr.smoothing = enable; mySLineSurface->applyAttributes(); mySLineSurface->setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::enablePhosphor(bool enable, int blend) { myUsePhosphor = enable; if(blend >= 0) myPhosphorPercent = blend / 100.0; myFilter = Filter(enable ? uInt8(myFilter) | 0x01 : uInt8(myFilter) & 0x10); myTiaSurface->setDirty(); mySLineSurface->setDirty(); memset(myRGBFramebuffer, 0, sizeof(myRGBFramebuffer)); // Precalculate the average colors for the 'phosphor' effect if(myUsePhosphor) { for(Int16 c = 255; c >= 0; c--) for(Int16 p = 255; p >= 0; p--) myPhosphorPalette[c][p] = getPhosphor(c, p); myNTSCFilter.setPhosphorPalette(myPhosphorPalette); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline uInt32 TIASurface::getRGBPhosphor(const uInt32 c, const uInt32 p) const { #define TO_RGB(color, red, green, blue) \ const uInt8 red = color >> 16; const uInt8 green = color >> 8; const uInt8 blue = color; TO_RGB(c, rc, gc, bc); TO_RGB(p, rp, gp, bp); // Mix current calculated frame with previous displayed frame const uInt8 rn = myPhosphorPalette[rc][rp]; const uInt8 gn = myPhosphorPalette[gc][gp]; const uInt8 bn = myPhosphorPalette[bc][bp]; return (rn << 16) | (gn << 8) | bn; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::enableNTSC(bool enable) { myFilter = Filter(enable ? uInt8(myFilter) | 0x10 : uInt8(myFilter) & 0x01); // Normal vs NTSC mode uses different source widths myTiaSurface->setSrcSize(enable ? AtariNTSC::outWidth(kTIAW) : uInt32(kTIAW), myTIA->height()); FBSurface::Attributes& tia_attr = myTiaSurface->attributes(); tia_attr.smoothing = myOSystem.settings().getBool("tia.inter"); myTiaSurface->applyAttributes(); myScanlinesEnabled = enable; FBSurface::Attributes& sl_attr = mySLineSurface->attributes(); sl_attr.smoothing = myOSystem.settings().getBool("tv.scaninter"); sl_attr.blending = myScanlinesEnabled; sl_attr.blendalpha = myOSystem.settings().getInt("tv.scanlines"); mySLineSurface->applyAttributes(); myTiaSurface->setDirty(); mySLineSurface->setDirty(); memset(myRGBFramebuffer, 0, sizeof(myRGBFramebuffer)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TIASurface::effectsInfo() const { const FBSurface::Attributes& attr = mySLineSurface->attributes(); ostringstream buf; switch(myFilter) { case Filter::Normal: buf << "Disabled, normal mode"; break; case Filter::Phosphor: buf << "Disabled, phosphor mode"; break; case Filter::BlarggNormal: buf << myNTSCFilter.getPreset() << ", scanlines=" << attr.blendalpha << "/" << (attr.smoothing ? "inter" : "nointer"); break; case Filter::BlarggPhosphor: buf << myNTSCFilter.getPreset() << ", phosphor, scanlines=" << attr.blendalpha << "/" << (attr.smoothing ? "inter" : "nointer"); break; } return buf.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::render() { uInt32 width = myTIA->width(); uInt32 height = myTIA->height(); uInt32 *out, outPitch; myTiaSurface->basePtr(out, outPitch); switch(myFilter) { case Filter::Normal: { uInt8* tiaIn = myTIA->frameBuffer(); uInt32 bufofs = 0, screenofsY = 0, pos; for(uInt32 y = 0; y < height; ++y) { pos = screenofsY; for (uInt32 x = width / 2; x; --x) { out[pos++] = myPalette[tiaIn[bufofs++]]; out[pos++] = myPalette[tiaIn[bufofs++]]; } screenofsY += outPitch; } break; } case Filter::Phosphor: { uInt8* tiaIn = myTIA->frameBuffer(); uInt32* rgbIn = myRGBFramebuffer; uInt32 bufofs = 0, screenofsY = 0, pos; for(uInt32 y = height; y ; --y) { pos = screenofsY; for(uInt32 x = width / 2; x ; --x) { // Store back into displayed frame buffer (for next frame) rgbIn[bufofs] = out[pos++] = getRGBPhosphor(myPalette[tiaIn[bufofs]], rgbIn[bufofs]); bufofs++; rgbIn[bufofs] = out[pos++] = getRGBPhosphor(myPalette[tiaIn[bufofs]], rgbIn[bufofs]); bufofs++; } screenofsY += outPitch; } break; } case Filter::BlarggNormal: { myNTSCFilter.render(myTIA->frameBuffer(), width, height, out, outPitch << 2); break; } case Filter::BlarggPhosphor: { myNTSCFilter.render(myTIA->frameBuffer(), width, height, out, outPitch << 2, myRGBFramebuffer); break; } } // Draw TIA image myTiaSurface->setDirty(); myTiaSurface->render(); // Draw overlaying scanlines if(myScanlinesEnabled) { mySLineSurface->setDirty(); mySLineSurface->render(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIASurface::reRender() { uInt32 width = myTIA->width(); uInt32 height = myTIA->height(); uInt32 pos = 0; uInt32 *outPtr, outPitch; myTiaSurface->basePtr(outPtr, outPitch); switch (myFilter) { // for non-phosphor modes, render the frame again case Filter::Normal: case Filter::BlarggNormal: render(); break; // for phosphor modes, copy the phosphor framebuffer case Filter::Phosphor: for (uInt32 y = height; y; --y) { memcpy(outPtr, myRGBFramebuffer + pos, width); outPtr += outPitch; pos += width; } break; case Filter::BlarggPhosphor: memcpy(outPtr, myRGBFramebuffer, height * outPitch << 2); break; } if (myUsePhosphor) { // Draw TIA image myTiaSurface->setDirty(); myTiaSurface->render(); // Draw overlaying scanlines if (myScanlinesEnabled) { mySLineSurface->setDirty(); mySLineSurface->render(); } } } stella-5.1.1/src/emucore/TIASurface.hxx000066400000000000000000000142231324334165500177170ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIASURFACE_HXX #define TIASURFACE_HXX class TIA; class Console; class OSystem; class FrameBuffer; class FBSurface; class VideoMode; #include #include "Rect.hxx" #include "NTSCFilter.hxx" #include "bspf.hxx" #include "TIAConstants.hxx" /** This class is basically a wrapper around all things related to rendering the TIA image to FBSurface's, and presenting the results to the screen. This is placed in a separate class since currently, rendering a TIA image can consist of TV filters, a separate scanline surface, phosphor modes, etc. @author Stephen Anthony */ class TIASurface { public: /** Creates a new TIASurface object */ TIASurface(OSystem& system); /** Set the TIA object, which is needed for actually rendering the TIA image. */ void initialize(const Console& console, const VideoMode& mode); /** Set the palette for TIA rendering. This currently consists of two components: the actual TIA palette, and a mixed TIA palette used in phosphor mode. The latter may eventually disappear once a better phosphor emulation is developed. @param tia_palette An actual TIA palette, converted to data values that are actually usable by the framebuffer @param rgb_palette The RGB components of the palette, needed for calculating a phosphor palette */ void setPalette(const uInt32* tia_palette, const uInt32* rgb_palette); /** Get the TIA base surface for use in saving to a PNG image. */ const FBSurface& baseSurface(GUI::Rect& rect) const; /** Get the TIA pixel associated with the given TIA buffer index, shifting by the given offset (for greyscale values). */ uInt32 pixel(uInt32 idx, uInt8 shift = 0); /** Get the NTSCFilter object associated with the framebuffer */ NTSCFilter& ntsc() { return myNTSCFilter; } /** Use NTSC filtering effects specified by the given preset. */ void setNTSC(NTSCFilter::Preset preset, bool show = true); /** Increase/decrease current scanline intensity by given relative amount. */ void setScanlineIntensity(int relative); /** Toggles interpolation/smoothing of scanlines in TV modes. */ void toggleScanlineInterpolation(); /** Change scanline intensity and interpolation. @param relative If non-zero, change current intensity by 'relative' amount, otherwise set to 'absolute' @return New current intensity */ uInt32 enableScanlines(int relative, int absolute = 50); void enableScanlineInterpolation(bool enable); /** Enable/disable/query phosphor effect. */ void enablePhosphor(bool enable, int blend = -1); bool phosphorEnabled() const { return myUsePhosphor; } /** Used to calculate an averaged color for the 'phosphor' effect. @param c1 Color 1 @param c2 Color 2 @return Averaged value of the two colors */ inline uInt8 getPhosphor(const uInt8 c1, uInt8 c2) const { // Use maximum of current and decayed previous values c2 = uInt8(c2 * myPhosphorPercent); if(c1 > c2) return c1; // raise (assumed immediate) else return c2; // decay } /** Used to calculate an averaged color for the 'phosphor' effect. @param c RGB Color 1 (current frame) @param cp RGB Color 2 (previous frame) @return Averaged value of the two RGB colors */ uInt32 getRGBPhosphor(const uInt32 c, const uInt32 cp) const; /** Enable/disable/query NTSC filtering effects. */ void enableNTSC(bool enable); bool ntscEnabled() const { return uInt8(myFilter) & 0x10; } string effectsInfo() const; /** This method should be called to draw the TIA image(s) to the screen. */ void render(); /** This method renders the current frame again. */ void reRender(); private: OSystem& myOSystem; FrameBuffer& myFB; TIA* myTIA; shared_ptr myTiaSurface, mySLineSurface, myBaseTiaSurface; // Enumeration created such that phosphor off/on is in LSB, // and Blargg off/on is in MSB enum class Filter: uInt8 { Normal = 0x00, Phosphor = 0x01, BlarggNormal = 0x10, BlarggPhosphor = 0x11 }; Filter myFilter; enum { kTIAW = 160, kTIAH = TIAConstants::frameBufferHeight, kScanH = kTIAH*2 }; // NTSC object to use in TIA rendering mode NTSCFilter myNTSCFilter; ///////////////////////////////////////////////////////////// // Phosphor mode items (aka reduced flicker on 30Hz screens) // RGB frame buffer uInt32 myRGBFramebuffer[AtariNTSC::outWidth(kTIAW) * kTIAH]; // Use phosphor effect bool myUsePhosphor; // Amount to blend when using phosphor effect float myPhosphorPercent; // Precalculated averaged phosphor colors uInt8 myPhosphorPalette[256][256]; ///////////////////////////////////////////////////////////// // Use scanlines in TIA rendering mode bool myScanlinesEnabled; // Palette for normal TIA rendering mode const uInt32* myPalette; private: // Following constructors and assignment operators not supported TIASurface() = delete; TIASurface(const TIASurface&) = delete; TIASurface(TIASurface&&) = delete; TIASurface& operator=(const TIASurface&) = delete; TIASurface& operator=(TIASurface&&) = delete; }; #endif stella-5.1.1/src/emucore/Thumbulator.cxx000066400000000000000000001651661324334165500203070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ //============================================================================ // This class provides Thumb emulation code ("Thumbulator") // by David Welch (dwelch@dwelch.com) // Modified by Fred Quimby // Code is public domain and used with the author's consent //============================================================================ #include "bspf.hxx" #include "Base.hxx" #include "Cart.hxx" #include "Thumbulator.hxx" using Common::Base; // Uncomment the following to enable specific functionality // WARNING!!! This slows the runtime to a crawl //#define THUMB_DISS //#define THUMB_DBUG #if defined(THUMB_DISS) #define DO_DISS(statement) statement #else #define DO_DISS(statement) #endif #if defined(THUMB_DBUG) #define DO_DBUG(statement) statement #else #define DO_DBUG(statement) #endif #ifdef __BIG_ENDIAN__ #define CONV_DATA(d) (((d & 0xFFFF)>>8) | ((d & 0xffff)<<8)) & 0xffff; #define CONV_RAMROM(d) ((d>>8) | (d<<8)) & 0xffff; #else #define CONV_DATA(d) (d & 0xFFFF); #define CONV_RAMROM(d) (d); #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Thumbulator::Thumbulator(const uInt16* rom_ptr, uInt16* ram_ptr, bool traponfatal, Thumbulator::ConfigureFor configurefor, Cartridge* cartridge) : rom(rom_ptr), ram(ram_ptr), T1TCR(0), T1TC(0), configuration(configurefor), myCartridge(cartridge) { setConsoleTiming(ConsoleTiming::ntsc); trapFatalErrors(traponfatal); reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Thumbulator::run() { reset(); for(;;) { if(execute()) break; if(instructions > 500000) // way more than would otherwise be possible throw runtime_error("instructions > 500000"); } #if defined(THUMB_DISS) || defined(THUMB_DBUG) dump_counters(); cout << statusMsg.str() << endl; #endif return statusMsg.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::setConsoleTiming(ConsoleTiming timing) { // this sets how many ticks of the Harmony/Melody clock // will occur per tick of the 6507 clock constexpr double NTSC = 70.0 / 1.193182; // NTSC 6507 clock rate constexpr double PAL = 70.0 / 1.182298; // PAL 6507 clock rate constexpr double SECAM = 70.0 / 1.187500; // SECAM 6507 clock rate switch(timing) { case ConsoleTiming::ntsc: timing_factor = NTSC; break; case ConsoleTiming::secam: timing_factor = SECAM; break; case ConsoleTiming::pal: timing_factor = PAL; break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::updateTimer(uInt32 cycles) { if (T1TCR & 1) // bit 0 controls timer on/off T1TC += uInt32(cycles * timing_factor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string Thumbulator::run(uInt32 cycles) { updateTimer(cycles); return run(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, const char* msg) { statusMsg << "Thumb ARM emulation fatal error: " << endl << opcode << "(" << Base::HEX8 << v1 << "), " << msg << endl; dump_regs(); if(trapOnFatal) throw runtime_error(statusMsg.str()); return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline int Thumbulator::fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg) { statusMsg << "Thumb ARM emulation fatal error: " << endl << opcode << "(" << Base::HEX8 << v1 << "," << v2 << "), " << msg << endl; dump_regs(); if(trapOnFatal) throw runtime_error(statusMsg.str()); return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::dump_counters() { cout << endl << endl << "instructions " << instructions << endl << "fetches " << fetches << endl << "reads " << reads << endl << "writes " << writes << endl << "memcycles " << (fetches+reads+writes) << endl << "systick_ints " << systick_ints << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::dump_regs() { for (int cnt = 1; cnt < 14; cnt++) { statusMsg << "R" << cnt << " = " << Base::HEX8 << reg_norm[cnt-1] << " "; if(cnt % 4 == 0) statusMsg << endl; } statusMsg << endl << "SP = " << Base::HEX8 << reg_norm[13] << " " << "LR = " << Base::HEX8 << reg_norm[14] << " " << "PC = " << Base::HEX8 << reg_norm[15] << " " << endl; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Thumbulator::fetch16(uInt32 addr) { fetches++; uInt32 data; switch(addr & 0xF0000000) { case 0x00000000: //ROM addr &= ROMADDMASK; if(addr < 0x50) fatalError("fetch16", addr, "abort"); addr >>= 1; data = CONV_RAMROM(rom[addr]); DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl); return data; case 0x40000000: //RAM addr &= RAMADDMASK; addr >>= 1; data=CONV_RAMROM(ram[addr]); DO_DBUG(statusMsg << "fetch16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl); return data; } return fatalError("fetch16", addr, "abort"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Thumbulator::fetch32(uInt32 addr) { uInt32 data; switch(addr & 0xF0000000) { case 0x00000000: //ROM if(addr < 0x50) { data = read32(addr); DO_DBUG(statusMsg << "fetch32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl); if(addr == 0x00000000) return data; if(addr == 0x00000004) return data; if(addr == 0x0000003C) return data; fatalError("fetch32", addr, "abort"); } [[fallthrough]]; case 0x40000000: //RAM data = read32(addr); DO_DBUG(statusMsg << "fetch32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl); return data; } return fatalError("fetch32", addr, "abort"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::write16(uInt32 addr, uInt32 data) { if((addr > 0x40001fff) && (addr < 0x50000000)) fatalError("write16", addr, "abort - out of range"); if (isProtected(addr)) fatalError("write16", addr, "to driver area"); if(addr & 1) fatalError("write16", addr, "abort - misaligned"); writes++; DO_DBUG(statusMsg << "write16(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl); switch(addr & 0xF0000000) { case 0x40000000: //RAM addr &= RAMADDMASK; addr >>= 1; ram[addr] = CONV_DATA(data); return; case 0xE0000000: //MAMCR if(addr == 0xE01FC000) { DO_DBUG(statusMsg << "write16(" << Base::HEX8 << "MAMCR" << "," << Base::HEX8 << data << ") *" << endl); mamcr = data; return; } } fatalError("write16", addr, data, "abort"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::write32(uInt32 addr, uInt32 data) { if(addr & 3) fatalError("write32", addr, "abort - misaligned"); if (isProtected(addr)) fatalError("write32", addr, "to driver area"); DO_DBUG(statusMsg << "write32(" << Base::HEX8 << addr << "," << Base::HEX8 << data << ")" << endl); switch(addr & 0xF0000000) { case 0xF0000000: //halt dump_counters(); throw runtime_error("HALT"); case 0xE0000000: //periph switch(addr) { case 0xE0000000: DO_DISS(statusMsg << "uart: [" << char(data&0xFF) << "]" << endl); break; case 0xE0008004: // T1TCR - Timer 1 Control Register T1TCR = data; break; case 0xE0008008: // T1TC - Timer 1 Counter T1TC = data; break; case 0xE000E010: { uInt32 old = systick_ctrl; systick_ctrl = data & 0x00010007; if(((old & 1) == 0) && (systick_ctrl & 1)) { // timer started, load count systick_count = systick_reload; } break; } case 0xE000E014: systick_reload = data & 0x00FFFFFF; break; case 0xE000E018: systick_count = data & 0x00FFFFFF; break; case 0xE000E01C: systick_calibrate = data & 0x00FFFFFF; break; } return; case 0xD0000000: //debug switch(addr & 0xFF) { case 0x00: statusMsg << "[" << Base::HEX8 << read_register(14) << "][" << addr << "] " << data << endl; return; case 0x10: statusMsg << Base::HEX8 << data << endl; return; case 0x20: statusMsg << Base::HEX8 << data << endl; return; } return; case 0x40000000: //RAM write16(addr+0, (data >> 0) & 0xFFFF); write16(addr+2, (data >> 16) & 0xFFFF); return; } fatalError("write32", addr, data, "abort"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Thumbulator::isProtected(uInt32 addr) { if (addr < 0x40000000) return false; addr -= 0x40000000; switch (configuration) { case ConfigureFor::DPCplus: return (addr < 0x0c00) && (addr > 0x0028); case ConfigureFor::CDF: return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x06e0) && (addr < (0x0e60 + 284))); case ConfigureFor::CDF1: return (addr < 0x0800) && (addr > 0x0028) && !((addr >= 0x00a0) && (addr < (0x00a0 + 284))); case ConfigureFor::BUS: return (addr < 0x06d8) && (addr > 0x0028); } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Thumbulator::read16(uInt32 addr) { uInt32 data; if((addr > 0x40001fff) && (addr < 0x50000000)) fatalError("read16", addr, "abort - out of range"); else if((addr > 0x7fff) && (addr < 0x10000000)) fatalError("read16", addr, "abort - out of range"); if(addr & 1) fatalError("read16", addr, "abort - misaligned"); reads++; switch(addr & 0xF0000000) { case 0x00000000: //ROM addr &= ROMADDMASK; addr >>= 1; data = CONV_RAMROM(rom[addr]); DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl); return data; case 0x40000000: //RAM addr &= RAMADDMASK; addr >>= 1; data = CONV_RAMROM(ram[addr]); DO_DBUG(statusMsg << "read16(" << Base::HEX8 << addr << ")=" << Base::HEX4 << data << endl); return data; case 0xE0000000: //MAMCR if(addr == 0xE01FC000) { DO_DBUG(statusMsg << "read16(" << "MAMCR" << addr << ")=" << mamcr << " *"); return mamcr; } } return fatalError("read16", addr, "abort"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Thumbulator::read32(uInt32 addr) { if(addr & 3) fatalError("read32", addr, "abort - misaligned"); uInt32 data; switch(addr & 0xF0000000) { case 0x00000000: //ROM case 0x40000000: //RAM data = read16(addr+0); data |= (uInt32(read16(addr+2))) << 16; DO_DBUG(statusMsg << "read32(" << Base::HEX8 << addr << ")=" << Base::HEX8 << data << endl); return data; case 0xE0000000: { switch(addr) { case 0xE0008004: // T1TCR - Timer 1 Control Register data = T1TCR; return data; case 0xE0008008: // T1TC - Timer 1 Counter data = T1TC; return data; case 0xE000E010: data = systick_ctrl; systick_ctrl &= (~0x00010000); return data; case 0xE000E014: data = systick_reload; return data; case 0xE000E018: data = systick_count; return data; case 0xE000E01C: data = systick_calibrate; return data; } } } return fatalError("read32", addr, "abort"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 Thumbulator::read_register(uInt32 reg) { reg &= 0xF; uInt32 data = reg_norm[reg]; DO_DBUG(statusMsg << "read_register(" << dec << reg << ")=" << Base::HEX8 << data << endl); if(reg == 15) { if(data & 1) { DO_DBUG(statusMsg << "pc has lsbit set 0x" << Base::HEX8 << data << endl); } data &= ~1; } return data; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::write_register(uInt32 reg, uInt32 data) { reg &= 0xF; DO_DBUG(statusMsg << "write_register(" << dec << reg << "," << Base::HEX8 << data << ")" << endl); if(reg == 15) data &= ~1; reg_norm[reg] = data; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::do_zflag(uInt32 x) { if(x == 0) cpsr |= CPSR_Z; else cpsr &= ~CPSR_Z; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::do_nflag(uInt32 x) { if(x & 0x80000000) cpsr|=CPSR_N; else cpsr&=~CPSR_N; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::do_cflag(uInt32 a, uInt32 b, uInt32 c) { uInt32 rc; cpsr &= ~CPSR_C; rc = (a & 0x7FFFFFFF) + (b & 0x7FFFFFFF) + c; //carry in rc = (rc >> 31) + (a >> 31) + (b >> 31); //carry out if(rc & 2) cpsr |= CPSR_C; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::do_vflag(uInt32 a, uInt32 b, uInt32 c) { uInt32 rc, rd; cpsr &= ~CPSR_V; rc = (a & 0x7FFFFFFF) + (b & 0x7FFFFFFF) + c; //carry in rc >>= 31; //carry in in lsbit rd = (rc & 1) + ((a >> 31) & 1) + ((b >> 31) & 1); //carry out rd >>= 1; //carry out in lsbit rc = (rc^rd) & 1; //if carry in != carry out then signed overflow if(rc) cpsr |= CPSR_V; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::do_cflag_bit(uInt32 x) { if(x) cpsr |= CPSR_C; else cpsr &= ~CPSR_C; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Thumbulator::do_vflag_bit(uInt32 x) { if(x) cpsr |= CPSR_V; else cpsr &= ~CPSR_V; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Thumbulator::execute() { uInt32 pc, sp, inst, ra, rb, rc, rm, rd, rn, rs, op; pc = read_register(15); #if 0 if(handler_mode) { if((pc & 0xF0000000) == 0xF0000000) { uInt32 sp = read_register(13); handler_mode = false; write_register(0, read32(sp)); sp += 4; write_register(1, read32(sp)); sp += 4; write_register(2, read32(sp)); sp += 4; write_register(3, read32(sp)); sp += 4; write_register(12, read32(sp)); sp += 4; write_register(14, read32(sp)); sp += 4; pc = read32(sp); sp += 4; cpsr = read32(sp); sp += 4; write_register(13, sp); } } if(systick_ctrl & 1) { if(systick_count) { systick_count--; } else { systick_count = systick_reload; systick_ctrl |= 0x00010000; } } if((systick_ctrl & 3) == 3) { if(systick_ctrl & 0x00010000) { if(!handler_mode) { systick_ints++; uInt32 sp = read_register(13); sp -= 4; write32(sp, cpsr); sp -= 4; write32(sp, pc); sp -= 4; write32(sp, read_register(14)); sp -= 4; write32(sp, read_register(12)); sp -= 4; write32(sp, read_register(3)); sp -= 4; write32(sp, read_register(2)); sp -= 4; write32(sp, read_register(1)); sp -= 4; write32(sp, read_register(0)); write_register(13, sp); pc = fetch32(0x0000003C); //systick vector pc += 2; //write_register(14, 0xFFFFFF00); write_register(14, 0xFFFFFFF9); handler_mode = true; } } } #endif inst = fetch16(pc-2); pc += 2; write_register(15, pc); DO_DISS(statusMsg << Base::HEX8 << (pc-5) << ": " << Base::HEX4 << inst << " "); instructions++; //ADC if((inst & 0xFFC0) == 0x4140) { rd = (inst >> 0) & 0x07; rm = (inst >> 3) & 0x07; DO_DISS(statusMsg << "adc r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rd); rb = read_register(rm); rc = ra + rb; if(cpsr & CPSR_C) rc++; write_register(rd, rc); do_nflag(rc); do_zflag(rc); if(cpsr & CPSR_C) { do_cflag(ra, rb, 1); do_vflag(ra, rb, 1); } else { do_cflag(ra, rb, 0); do_vflag(ra, rb, 0); } return 0; } //ADD(1) small immediate two registers if((inst & 0xFE00) == 0x1C00) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rb = (inst >> 6) & 0x7; if(rb) { DO_DISS(statusMsg << "adds r" << dec << rd << ",r" << dec << rn << "," << "#0x" << Base::HEX2 << rb << endl); ra = read_register(rn); rc = ra + rb; //fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb); write_register(rd, rc); do_nflag(rc); do_zflag(rc); do_cflag(ra, rb, 0); do_vflag(ra, rb, 0); return 0; } else { //this is a mov } } //ADD(2) big immediate one register if((inst & 0xF800) == 0x3000) { rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x7; DO_DISS(statusMsg << "adds r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl); ra = read_register(rd); rc = ra + rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); do_cflag(ra, rb, 0); do_vflag(ra, rb, 0); return 0; } //ADD(3) three registers if((inst & 0xFE00) == 0x1800) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "adds r" << dec << rd << ",r" << dec << rn << ",r" << rm << endl); ra = read_register(rn); rb = read_register(rm); rc = ra + rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); do_cflag(ra, rb, 0); do_vflag(ra, rb, 0); return 0; } //ADD(4) two registers one or both high no flags if((inst & 0xFF00) == 0x4400) { if((inst >> 6) & 3) { //UNPREDICTABLE } rd = (inst >> 0) & 0x7; rd |= (inst >> 4) & 0x8; rm = (inst >> 3) & 0xF; DO_DISS(statusMsg << "add r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rd); rb = read_register(rm); rc = ra + rb; if(rd == 15) { if((rc & 1) == 0) fatalError("add pc", pc, rc, " produced an arm address"); rc &= ~1; //write_register may do this as well rc += 2; //The program counter is special } //fprintf(stderr,"0x%08X = 0x%08X + 0x%08X\n",rc,ra,rb); write_register(rd, rc); return 0; } //ADD(5) rd = pc plus immediate if((inst & 0xF800) == 0xA000) { rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x7; rb <<= 2; DO_DISS(statusMsg << "add r" << dec << rd << ",PC,#0x" << Base::HEX2 << rb << endl); ra = read_register(15); rc = (ra & (~3u)) + rb; write_register(rd, rc); return 0; } //ADD(6) rd = sp plus immediate if((inst & 0xF800) == 0xA800) { rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x7; rb <<= 2; DO_DISS(statusMsg << "add r" << dec << rd << ",SP,#0x" << Base::HEX2 << rb << endl); ra = read_register(13); rc = ra + rb; write_register(rd, rc); return 0; } //ADD(7) sp plus immediate if((inst & 0xFF80) == 0xB000) { rb = (inst >> 0) & 0x7F; rb <<= 2; DO_DISS(statusMsg << "add SP,#0x" << Base::HEX2 << rb << endl); ra = read_register(13); rc = ra + rb; write_register(13, rc); return 0; } //AND if((inst & 0xFFC0) == 0x4000) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "ands r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rd); rb = read_register(rm); rc = ra & rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //ASR(1) two register immediate if((inst & 0xF800) == 0x1000) { rd = (inst >> 0) & 0x07; rm = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl); rc = read_register(rm); if(rb == 0) { if(rc & 0x80000000) { do_cflag_bit(1); rc = ~0; } else { do_cflag_bit(0); rc = 0; } } else { do_cflag_bit(rc & (1 << (rb-1))); ra = rc & 0x80000000; rc >>= rb; if(ra) //asr, sign is shifted in rc |= (~0u) << (32-rb); } write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //ASR(2) two register if((inst & 0xFFC0) == 0x4100) { rd = (inst >> 0) & 0x07; rs = (inst >> 3) & 0x07; DO_DISS(statusMsg << "asrs r" << dec << rd << ",r" << dec << rs << endl); rc = read_register(rd); rb = read_register(rs); rb &= 0xFF; if(rb == 0) { } else if(rb < 32) { do_cflag_bit(rc & (1 << (rb-1))); ra = rc & 0x80000000; rc >>= rb; if(ra) //asr, sign is shifted in { rc |= (~0u) << (32-rb); } } else { if(rc & 0x80000000) { do_cflag_bit(1); rc = (~0u); } else { do_cflag_bit(0); rc = 0; } } write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //B(1) conditional branch if((inst & 0xF000) == 0xD000) { rb = (inst >> 0) & 0xFF; if(rb & 0x80) rb |= (~0u) << 8; op=(inst >> 8) & 0xF; rb <<= 1; rb += pc; rb += 2; switch(op) { case 0x0: //b eq z set DO_DISS(statusMsg << "beq 0x" << Base::HEX8 << (rb-3) << endl); if(cpsr & CPSR_Z) write_register(15, rb); return 0; case 0x1: //b ne z clear DO_DISS(statusMsg << "bne 0x" << Base::HEX8 << (rb-3) << endl); if(!(cpsr & CPSR_Z)) write_register(15, rb); return 0; case 0x2: //b cs c set DO_DISS(statusMsg << "bcs 0x" << Base::HEX8 << (rb-3) << endl); if(cpsr & CPSR_C) write_register(15, rb); return 0; case 0x3: //b cc c clear DO_DISS(statusMsg << "bcc 0x" << Base::HEX8 << (rb-3) << endl); if(!(cpsr & CPSR_C)) write_register(15, rb); return 0; case 0x4: //b mi n set DO_DISS(statusMsg << "bmi 0x" << Base::HEX8 << (rb-3) << endl); if(cpsr & CPSR_N) write_register(15, rb); return 0; case 0x5: //b pl n clear DO_DISS(statusMsg << "bpl 0x" << Base::HEX8 << (rb-3) << endl); if(!(cpsr & CPSR_N)) write_register(15, rb); return 0; case 0x6: //b vs v set DO_DISS(statusMsg << "bvs 0x" << Base::HEX8 << (rb-3) << endl); if(cpsr & CPSR_V) write_register(15,rb); return 0; case 0x7: //b vc v clear DO_DISS(statusMsg << "bvc 0x" << Base::HEX8 << (rb-3) << endl); if(!(cpsr & CPSR_V)) write_register(15, rb); return 0; case 0x8: //b hi c set z clear DO_DISS(statusMsg << "bhi 0x" << Base::HEX8 << (rb-3) << endl); if((cpsr & CPSR_C) && (!(cpsr & CPSR_Z))) write_register(15, rb); return 0; case 0x9: //b ls c clear or z set DO_DISS(statusMsg << "bls 0x" << Base::HEX8 << (rb-3) << endl); if((cpsr & CPSR_Z) || (!(cpsr & CPSR_C))) write_register(15, rb); return 0; case 0xA: //b ge N == V DO_DISS(statusMsg << "bge 0x" << Base::HEX8 << (rb-3) << endl); ra = 0; if( (cpsr & CPSR_N) && (cpsr & CPSR_V) ) ra++; if((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))) ra++; if(ra) write_register(15, rb); return 0; case 0xB: //b lt N != V DO_DISS(statusMsg << "blt 0x" << Base::HEX8 << (rb-3) << endl); ra = 0; if((!(cpsr & CPSR_N)) && (cpsr & CPSR_V)) ra++; if((!(cpsr & CPSR_V)) && (cpsr & CPSR_N)) ra++; if(ra) write_register(15, rb); return 0; case 0xC: //b gt Z==0 and N == V DO_DISS(statusMsg << "bgt 0x" << Base::HEX8 << (rb-3) << endl); ra = 0; if( (cpsr & CPSR_N) && (cpsr & CPSR_V) ) ra++; if((!(cpsr & CPSR_N)) && (!(cpsr & CPSR_V))) ra++; if(cpsr & CPSR_Z) ra = 0; if(ra) write_register(15, rb); return 0; case 0xD: //b le Z==1 or N != V DO_DISS(statusMsg << "ble 0x" << Base::HEX8 << (rb-3) << endl); ra = 0; if((!(cpsr & CPSR_N)) && (cpsr & CPSR_V)) ra++; if((!(cpsr & CPSR_V)) && (cpsr & CPSR_N)) ra++; if(cpsr & CPSR_Z) ra++; if(ra) write_register(15, rb); return 0; case 0xE: //undefined instruction break; case 0xF: //swi break; } } //B(2) unconditional branch if((inst & 0xF800) == 0xE000) { rb = (inst >> 0) & 0x7FF; if(rb & (1 << 10)) rb |= (~0u) << 11; rb <<= 1; rb += pc; rb += 2; DO_DISS(statusMsg << "B 0x" << Base::HEX8 << (rb-3) << endl); write_register(15, rb); return 0; } //BIC if((inst & 0xFFC0) == 0x4380) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "bics r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rd); rb = read_register(rm); rc = ra & (~rb); write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //BKPT if((inst & 0xFF00) == 0xBE00) { rb = (inst >> 0) & 0xFF; statusMsg << "bkpt 0x" << Base::HEX2 << rb << endl; return 1; } //BL/BLX(1) if((inst & 0xE000) == 0xE000) //BL,BLX { if((inst & 0x1800) == 0x1000) //H=b10 { DO_DISS(statusMsg << endl); rb = inst & ((1 << 11) - 1); if(rb & 1<<10) rb |= (~((1 << 11) - 1)); //sign extend rb <<= 12; rb += pc; write_register(14, rb); return 0; } else if((inst & 0x1800) == 0x1800) //H=b11 { //branch to thumb rb = read_register(14); rb += (inst & ((1 << 11) - 1)) << 1;; rb += 2; DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl); write_register(14, (pc-2) | 1); write_register(15, rb); return 0; } else if((inst & 0x1800) == 0x0800) //H=b01 { //fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst); // fxq: this should exit the code without having to detect it rb = read_register(14); rb += (inst & ((1 << 11) - 1)) << 1;; rb &= 0xFFFFFFFC; rb += 2; DO_DISS(statusMsg << "bl 0x" << Base::HEX8 << (rb-3) << endl); write_register(14, (pc-2) | 1); write_register(15, rb); return 0; } } //BLX(2) if((inst & 0xFF87) == 0x4780) { rm = (inst >> 3) & 0xF; DO_DISS(statusMsg << "blx r" << dec << rm << endl); rc = read_register(rm); //fprintf(stderr,"blx r%u 0x%X 0x%X\n",rm,rc,pc); rc += 2; if(rc & 1) { write_register(14, (pc-2) | 1); rc &= ~1; write_register(15, rc); return 0; } else { //fprintf(stderr,"cannot branch to arm 0x%08X 0x%04X\n",pc,inst); // fxq: this could serve as exit code return 1; } } //BX if((inst & 0xFF87) == 0x4700) { rm = (inst >> 3) & 0xF; DO_DISS(statusMsg << "bx r" << dec << rm << endl); rc = read_register(rm); rc += 2; //fprintf(stderr,"bx r%u 0x%X 0x%X\n",rm,rc,pc); if(rc & 1) { // branch to odd address denotes 16 bit ARM code rc &= ~1; write_register(15, rc); return 0; } else { // branch to even address denotes 32 bit ARM code, which the Thumbulator // class does not support. So capture relavent information and hand it // off to the Cartridge class for it to handle. bool handled = false; switch(configuration) { case ConfigureFor::BUS: // this subroutine interface is used in the BUS driver, // it starts at address 0x000006d8 // _SetNote: // ldr r4, =NoteStore // bx r4 // bx instruction at 0x000006da // _ResetWave: // ldr r4, =ResetWaveStore // bx r4 // bx instruction at 0x000006de // _GetWavePtr: // ldr r4, =WavePtrFetch // bx r4 // bx instruction at 0x000006e2 // _SetWaveSize: // ldr r4, =WaveSizeStore // bx r4 // bx instruction at 0x000006e6 // address to test for is + 4 due to pipelining #define BUS_SetNote (0x000006da + 4) #define BUS_ResetWave (0x000006de + 4) #define BUS_GetWavePtr (0x000006e2 + 4) #define BUS_SetWaveSize (0x000006e6 + 4) if (pc == BUS_SetNote) { myCartridge->thumbCallback(0, read_register(2), read_register(3)); handled = true; } else if (pc == BUS_ResetWave) { myCartridge->thumbCallback(1, read_register(2), 0); handled = true; } else if (pc == BUS_GetWavePtr) { write_register(2, myCartridge->thumbCallback(2, read_register(2), 0)); handled = true; } else if (pc == BUS_SetWaveSize) { myCartridge->thumbCallback(3, read_register(2), read_register(3)); handled = true; } else if (pc == 0x0000083a) { // exiting Custom ARM code, returning to BUS Driver control } else { #if 0 // uncomment this for testing uInt32 r0 = read_register(0); uInt32 r1 = read_register(1); uInt32 r2 = read_register(2); uInt32 r3 = read_register(3); uInt32 r4 = read_register(4); #endif myCartridge->thumbCallback(255, 0, 0); } break; case ConfigureFor::CDF: // this subroutine interface is used in the CDF driver, // it starts at address 0x000006e0 // _SetNote: // ldr r4, =NoteStore // bx r4 // bx instruction at 0x000006e2 // _ResetWave: // ldr r4, =ResetWaveStore // bx r4 // bx instruction at 0x000006e6 // _GetWavePtr: // ldr r4, =WavePtrFetch // bx r4 // bx instruction at 0x000006ea // _SetWaveSize: // ldr r4, =WaveSizeStore // bx r4 // bx instruction at 0x000006ee // address to test for is + 4 due to pipelining #define CDF_SetNote (0x000006e2 + 4) #define CDF_ResetWave (0x000006e6 + 4) #define CDF_GetWavePtr (0x000006ea + 4) #define CDF_SetWaveSize (0x000006ee + 4) if (pc == CDF_SetNote) { myCartridge->thumbCallback(0, read_register(2), read_register(3)); handled = true; } else if (pc == CDF_ResetWave) { myCartridge->thumbCallback(1, read_register(2), 0); handled = true; } else if (pc == CDF_GetWavePtr) { write_register(2, myCartridge->thumbCallback(2, read_register(2), 0)); handled = true; } else if (pc == CDF_SetWaveSize) { myCartridge->thumbCallback(3, read_register(2), read_register(3)); handled = true; } else if (pc == 0x0000083a) { // exiting Custom ARM code, returning to BUS Driver control } else { #if 0 // uncomment this for testing uInt32 r0 = read_register(0); uInt32 r1 = read_register(1); uInt32 r2 = read_register(2); uInt32 r3 = read_register(3); uInt32 r4 = read_register(4); #endif myCartridge->thumbCallback(255, 0, 0); } break; case ConfigureFor::CDF1: // this subroutine interface is used in the CDF driver, // it starts at address 0x00000750 // _SetNote: // ldr r4, =NoteStore // bx r4 // bx instruction at 0x000006e2 // _ResetWave: // ldr r4, =ResetWaveStore // bx r4 // bx instruction at 0x000006e6 // _GetWavePtr: // ldr r4, =WavePtrFetch // bx r4 // bx instruction at 0x000006ea // _SetWaveSize: // ldr r4, =WaveSizeStore // bx r4 // bx instruction at 0x000006ee // address to test for is + 4 due to pipelining #define CDF1_SetNote (0x00000752 + 4) #define CDF1_ResetWave (0x00000756 + 4) #define CDF1_GetWavePtr (0x0000075a + 4) #define CDF1_SetWaveSize (0x0000075e + 4) if (pc == CDF1_SetNote) { myCartridge->thumbCallback(0, read_register(2), read_register(3)); handled = true; } else if (pc == CDF1_ResetWave) { myCartridge->thumbCallback(1, read_register(2), 0); handled = true; } else if (pc == CDF1_GetWavePtr) { write_register(2, myCartridge->thumbCallback(2, read_register(2), 0)); handled = true; } else if (pc == CDF1_SetWaveSize) { myCartridge->thumbCallback(3, read_register(2), read_register(3)); handled = true; } else if (pc == 0x0000083a) { // exiting Custom ARM code, returning to BUS Driver control } else { #if 0 // uncomment this for testing uInt32 r0 = read_register(0); uInt32 r1 = read_register(1); uInt32 r2 = read_register(2); uInt32 r3 = read_register(3); uInt32 r4 = read_register(4); #endif myCartridge->thumbCallback(255, 0, 0); } break; case ConfigureFor::DPCplus: // no 32-bit subroutines in DPC+ break; } if (handled) { rc = read_register(14); // lr rc += 2; rc &= ~1; write_register(15, rc); return 0; } return 1; } } //CMN if((inst & 0xFFC0) == 0x42C0) { rn = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "cmns r" << dec << rn << ",r" << dec << rm << endl); ra = read_register(rn); rb = read_register(rm); rc = ra + rb; do_nflag(rc); do_zflag(rc); do_cflag(ra, rb, 0); do_vflag(ra, rb, 0); return 0; } //CMP(1) compare immediate if((inst & 0xF800) == 0x2800) { rb = (inst >> 0) & 0xFF; rn = (inst >> 8) & 0x07; DO_DISS(statusMsg << "cmp r" << dec << rn << ",#0x" << Base::HEX2 << rb << endl); ra = read_register(rn); rc = ra - rb; //fprintf(stderr,"0x%08X 0x%08X\n",ra,rb); do_nflag(rc); do_zflag(rc); do_cflag(ra, ~rb, 1); do_vflag(ra, ~rb, 1); return 0; } //CMP(2) compare register if((inst & 0xFFC0) == 0x4280) { rn = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "cmps r" << dec << rn << ",r" << dec << rm << endl); ra = read_register(rn); rb = read_register(rm); rc = ra - rb; //fprintf(stderr,"0x%08X 0x%08X\n",ra,rb); do_nflag(rc); do_zflag(rc); do_cflag(ra, ~rb, 1); do_vflag(ra, ~rb, 1); return 0; } //CMP(3) compare high register if((inst & 0xFF00) == 0x4500) { if(((inst >> 6) & 3) == 0x0) { //UNPREDICTABLE } rn = (inst >> 0) & 0x7; rn |= (inst >> 4) & 0x8; if(rn == 0xF) { //UNPREDICTABLE } rm = (inst >> 3) & 0xF; DO_DISS(statusMsg << "cmps r" << dec << rn << ",r" << dec << rm << endl); ra = read_register(rn); rb = read_register(rm); rc = ra - rb; do_nflag(rc); do_zflag(rc); do_cflag(ra, ~rb, 1); do_vflag(ra, ~rb, 1); return 0; } //CPS if((inst & 0xFFE8) == 0xB660) { DO_DISS(statusMsg << "cps TODO" << endl); return 1; } //CPY copy high register if((inst & 0xFFC0) == 0x4600) { //same as mov except you can use both low registers //going to let mov handle high registers rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "cpy r" << dec << rd << ",r" << dec << rm << endl); rc = read_register(rm); write_register(rd, rc); return 0; } //EOR if((inst & 0xFFC0) == 0x4040) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "eors r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rd); rb = read_register(rm); rc = ra ^ rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //LDMIA if((inst & 0xF800) == 0xC800) { rn = (inst >> 8) & 0x7; #if defined(THUMB_DISS) statusMsg << "ldmia r" << dec << rn << "!,{"; for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++) { if(inst&rb) { if(rc) statusMsg << ","; statusMsg << "r" << dec << ra; rc++; } } statusMsg << "}" << endl; #endif sp = read_register(rn); for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ra++) { if(inst & rb) { write_register(ra, read32(sp)); sp += 4; } } //there is a write back exception. if((inst & (1 << rn)) == 0) write_register(rn, sp); return 0; } //LDR(1) two register immediate if((inst & 0xF800) == 0x6800) { rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; rb <<= 2; DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl); rb = read_register(rn) + rb; rc = read32(rb); write_register(rd, rc); return 0; } //LDR(2) three register if((inst & 0xFE00) == 0x5800) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "ldr r" << dec << rd << ",[r" << dec << rn << ",r" << dec << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read32(rb); write_register(rd, rc); return 0; } //LDR(3) if((inst & 0xF800) == 0x4800) { rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x07; rb <<= 2; DO_DISS(statusMsg << "ldr r" << dec << rd << ",[PC+#0x" << Base::HEX2 << rb << "] "); ra = read_register(15); ra &= ~3; rb += ra; DO_DISS(statusMsg << ";@ 0x" << Base::HEX2 << rb << endl); rc = read32(rb); write_register(rd, rc); return 0; } //LDR(4) if((inst & 0xF800) == 0x9800) { rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x07; rb <<= 2; DO_DISS(statusMsg << "ldr r" << dec << rd << ",[SP+#0x" << Base::HEX2 << rb << "]" << endl); ra = read_register(13); //ra&=~3; rb += ra; rc = read32(rb); write_register(rd, rc); return 0; } //LDRB(1) if((inst & 0xF800) == 0x7800) { rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; DO_DISS(statusMsg << "ldrb r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl); rb = read_register(rn) + rb; rc = read16(rb & (~1u)); if(rb & 1) { rc >>= 8; } else { } write_register(rd, rc & 0xFF); return 0; } //LDRB(2) if((inst & 0xFE00) == 0x5C00) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "ldrb r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read16(rb & (~1u)); if(rb & 1) { rc >>= 8; } else { } write_register(rd, rc & 0xFF); return 0; } //LDRH(1) if((inst & 0xF800) == 0x8800) { rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; rb <<= 1; DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl); rb=read_register(rn) + rb; rc = read16(rb); write_register(rd, rc & 0xFFFF); return 0; } //LDRH(2) if((inst & 0xFE00) == 0x5A00) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "ldrh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read16(rb); write_register(rd, rc & 0xFFFF); return 0; } //LDRSB if((inst & 0xFE00) == 0x5600) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "ldrsb r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read16(rb & (~1u)); if(rb & 1) { rc >>= 8; } else { } rc &= 0xFF; if(rc & 0x80) rc |= ((~0u) << 8); write_register(rd, rc); return 0; } //LDRSH if((inst & 0xFE00) == 0x5E00) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "ldrsh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read16(rb); rc &= 0xFFFF; if(rc & 0x8000) rc |= ((~0u) << 16); write_register(rd, rc); return 0; } //LSL(1) if((inst & 0xF800) == 0x0000) { rd = (inst >> 0) & 0x07; rm = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl); rc = read_register(rm); if(rb == 0) { //if immed_5 == 0 //C unaffected //result not shifted } else { //else immed_5 > 0 do_cflag_bit(rc & (1 << (32-rb))); rc <<= rb; } write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //LSL(2) two register if((inst & 0xFFC0) == 0x4080) { rd = (inst >> 0) & 0x07; rs = (inst >> 3) & 0x07; DO_DISS(statusMsg << "lsls r" << dec << rd << ",r" << dec << rs << endl); rc = read_register(rd); rb = read_register(rs); rb &= 0xFF; if(rb == 0) { } else if(rb < 32) { do_cflag_bit(rc & (1 << (32-rb))); rc <<= rb; } else if(rb == 32) { do_cflag_bit(rc & 1); rc = 0; } else { do_cflag_bit(0); rc = 0; } write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //LSR(1) two register immediate if((inst & 0xF800) == 0x0800) { rd = (inst >> 0) & 0x07; rm = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rm << ",#0x" << Base::HEX2 << rb << endl); rc = read_register(rm); if(rb == 0) { do_cflag_bit(rc & 0x80000000); rc = 0; } else { do_cflag_bit(rc & (1 << (rb-1))); rc >>= rb; } write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //LSR(2) two register if((inst & 0xFFC0) == 0x40C0) { rd = (inst >> 0) & 0x07; rs = (inst >> 3) & 0x07; DO_DISS(statusMsg << "lsrs r" << dec << rd << ",r" << dec << rs << endl); rc = read_register(rd); rb = read_register(rs); rb &= 0xFF; if(rb == 0) { } else if(rb < 32) { do_cflag_bit(rc & (1 << (rb-1))); rc >>= rb; } else if(rb == 32) { do_cflag_bit(rc & 0x80000000); rc = 0; } else { do_cflag_bit(0); rc = 0; } write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //MOV(1) immediate if((inst & 0xF800) == 0x2000) { rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x07; DO_DISS(statusMsg << "movs r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl); write_register(rd, rb); do_nflag(rb); do_zflag(rb); return 0; } //MOV(2) two low registers if((inst & 0xFFC0) == 0x1C00) { rd = (inst >> 0) & 7; rn = (inst >> 3) & 7; DO_DISS(statusMsg << "movs r" << dec << rd << ",r" << dec << rn << endl); rc = read_register(rn); //fprintf(stderr,"0x%08X\n",rc); write_register(rd, rc); do_nflag(rc); do_zflag(rc); do_cflag_bit(0); do_vflag_bit(0); return 0; } //MOV(3) if((inst & 0xFF00) == 0x4600) { rd = (inst >> 0) & 0x7; rd |= (inst >> 4) & 0x8; rm = (inst >> 3) & 0xF; DO_DISS(statusMsg << "mov r" << dec << rd << ",r" << dec << rm << endl); rc = read_register(rm); if((rd == 14) && (rm == 15)) { //printf("mov lr,pc warning 0x%08X\n",pc-2); //rc|=1; } if(rd == 15) { rc &= ~1; //write_register may do this as well rc += 2; //The program counter is special } write_register(rd, rc); return 0; } //MUL if((inst & 0xFFC0) == 0x4340) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "muls r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rd); rb = read_register(rm); rc = ra * rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //MVN if((inst & 0xFFC0) == 0x43C0) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "mvns r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rm); rc = (~ra); write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //NEG if((inst & 0xFFC0) == 0x4240) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "negs r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rm); rc = 0 - ra; write_register(rd, rc); do_nflag(rc); do_zflag(rc); do_cflag(0, ~ra, 1); do_vflag(0, ~ra, 1); return 0; } //ORR if((inst & 0xFFC0) == 0x4300) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "orrs r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rd); rb = read_register(rm); rc = ra | rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //POP if((inst & 0xFE00) == 0xBC00) { #if defined(THUMB_DISS) statusMsg << "pop {"; for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++) { if(inst&rb) { if(rc) statusMsg << ","; statusMsg << "r" << dec << ra; rc++; } } if(inst&0x100) { if(rc) statusMsg << ","; statusMsg << "pc"; } statusMsg << "}" << endl; #endif sp = read_register(13); for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ra++) { if(inst & rb) { write_register(ra, read32(sp)); sp += 4; } } if(inst & 0x100) { rc = read32(sp); rc += 2; write_register(15, rc); sp += 4; } write_register(13, sp); return 0; } //PUSH if((inst & 0xFE00) == 0xB400) { #if defined(THUMB_DISS) statusMsg << "push {"; for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++) { if(inst&rb) { if(rc) statusMsg << ","; statusMsg << "r" << dec << ra; rc++; } } if(inst&0x100) { if(rc) statusMsg << ","; statusMsg << "lr"; } statusMsg << "}" << endl; #endif sp = read_register(13); //fprintf(stderr,"sp 0x%08X\n",sp); for(ra = 0, rb = 0x01, rc = 0; rb; rb = (rb << 1) & 0xFF, ra++) { if(inst & rb) { rc++; } } if(inst & 0x100) rc++; rc <<= 2; sp -= rc; rd = sp; for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ra++) { if(inst & rb) { write32(rd, read_register(ra)); rd += 4; } } if(inst & 0x100) { rc = read_register(14); write32(rd, rc); if((rc & 1) == 0) { // FIXME fprintf(stderr,"push {lr} with an ARM address pc 0x%08X popped 0x%08X\n",pc,rc); } } write_register(13, sp); return 0; } //REV if((inst & 0xFFC0) == 0xBA00) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; DO_DISS(statusMsg << "rev r" << dec << rd << ",r" << dec << rn << endl); ra = read_register(rn); rc = ((ra >> 0) & 0xFF) << 24; rc |= ((ra >> 8) & 0xFF) << 16; rc |= ((ra >> 16) & 0xFF) << 8; rc |= ((ra >> 24) & 0xFF) << 0; write_register(rd, rc); return 0; } //REV16 if((inst & 0xFFC0) == 0xBA40) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; DO_DISS(statusMsg << "rev16 r" << dec << rd << ",r" << dec << rn << endl); ra = read_register(rn); rc = ((ra >> 0) & 0xFF) << 8; rc |= ((ra >> 8) & 0xFF) << 0; rc |= ((ra >> 16) & 0xFF) << 24; rc |= ((ra >> 24) & 0xFF) << 16; write_register(rd, rc); return 0; } //REVSH if((inst & 0xFFC0) == 0xBAC0) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; DO_DISS(statusMsg << "revsh r" << dec << rd << ",r" << dec << rn << endl); ra = read_register(rn); rc = ((ra >> 0) & 0xFF) << 8; rc |= ((ra >> 8) & 0xFF) << 0; if(rc & 0x8000) rc |= 0xFFFF0000; else rc &= 0x0000FFFF; write_register(rd, rc); return 0; } //ROR if((inst & 0xFFC0) == 0x41C0) { rd = (inst >> 0) & 0x7; rs = (inst >> 3) & 0x7; DO_DISS(statusMsg << "rors r" << dec << rd << ",r" << dec << rs << endl); rc = read_register(rd); ra = read_register(rs); ra &= 0xFF; if(ra == 0) { } else { ra &= 0x1F; if(ra == 0) { do_cflag_bit(rc & 0x80000000); } else { do_cflag_bit(rc & (1 << (ra-1))); rb = rc << (32-ra); rc >>= ra; rc |= rb; } } write_register(rd, rc); do_nflag(rc); do_zflag(rc); return 0; } //SBC if((inst & 0xFFC0) == 0x4180) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "sbc r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rd); rb = read_register(rm); rc = ra - rb; if(!(cpsr & CPSR_C)) rc--; write_register(rd, rc); do_nflag(rc); do_zflag(rc); if(cpsr & CPSR_C) { do_cflag(ra, ~rb, 1); do_vflag(ra, ~rb, 1); } else { do_cflag(ra, ~rb, 0); do_vflag(ra, ~rb, 0); } return 0; } //SETEND if((inst & 0xFFF7) == 0xB650) { statusMsg << "setend not implemented" << endl; return 1; } //STMIA if((inst & 0xF800) == 0xC000) { rn = (inst >> 8) & 0x7; #if defined(THUMB_DISS) statusMsg << "stmia r" << dec << rn << "!,{"; for(ra=0,rb=0x01,rc=0;rb;rb=(rb<<1)&0xFF,ra++) { if(inst & rb) { if(rc) statusMsg << ","; statusMsg << "r" << dec << ra; rc++; } } statusMsg << "}" << endl; #endif sp = read_register(rn); for(ra = 0, rb = 0x01; rb; rb = (rb << 1) & 0xFF, ra++) { if(inst & rb) { write32(sp, read_register(ra)); sp += 4; } } write_register(rn, sp); return 0; } //STR(1) if((inst & 0xF800) == 0x6000) { rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; rb <<= 2; DO_DISS(statusMsg << "str r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl); rb = read_register(rn) + rb; rc = read_register(rd); write32(rb, rc); return 0; } //STR(2) if((inst & 0xFE00) == 0x5000) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "str r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read_register(rd); write32(rb, rc); return 0; } //STR(3) if((inst & 0xF800) == 0x9000) { rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x07; rb <<= 2; DO_DISS(statusMsg << "str r" << dec << rd << ",[SP,#0x" << Base::HEX2 << rb << "]" << endl); rb = read_register(13) + rb; //fprintf(stderr,"0x%08X\n",rb); rc = read_register(rd); write32(rb, rc); return 0; } //STRB(1) if((inst & 0xF800) == 0x7000) { rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; DO_DISS(statusMsg << "strb r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX8 << rb << "]" << endl); rb = read_register(rn) + rb; rc = read_register(rd); ra = read16(rb & (~1u)); if(rb & 1) { ra &= 0x00FF; ra |= rc << 8; } else { ra &= 0xFF00; ra |= rc & 0x00FF; } write16(rb & (~1u), ra & 0xFFFF); return 0; } //STRB(2) if((inst & 0xFE00) == 0x5400) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "strb r" << dec << rd << ",[r" << dec << rn << ",r" << rm << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read_register(rd); ra = read16(rb & (~1u)); if(rb & 1) { ra &= 0x00FF; ra |= rc << 8; } else { ra &= 0xFF00; ra |= rc & 0x00FF; } write16(rb & (~1u), ra & 0xFFFF); return 0; } //STRH(1) if((inst & 0xF800) == 0x8000) { rd = (inst >> 0) & 0x07; rn = (inst >> 3) & 0x07; rb = (inst >> 6) & 0x1F; rb <<= 1; DO_DISS(statusMsg << "strh r" << dec << rd << ",[r" << dec << rn << ",#0x" << Base::HEX2 << rb << "]" << endl); rb = read_register(rn) + rb; rc= read_register(rd); write16(rb, rc & 0xFFFF); return 0; } //STRH(2) if((inst & 0xFE00) == 0x5200) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "strh r" << dec << rd << ",[r" << dec << rn << ",r" << dec << rm << "]" << endl); rb = read_register(rn) + read_register(rm); rc = read_register(rd); write16(rb, rc & 0xFFFF); return 0; } //SUB(1) if((inst & 0xFE00) == 0x1E00) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rb = (inst >> 6) & 0x7; DO_DISS(statusMsg << "subs r" << dec << rd << ",r" << dec << rn << ",#0x" << Base::HEX2 << rb << endl); ra = read_register(rn); rc = ra - rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); do_cflag(ra, ~rb, 1); do_vflag(ra, ~rb, 1); return 0; } //SUB(2) if((inst & 0xF800) == 0x3800) { rb = (inst >> 0) & 0xFF; rd = (inst >> 8) & 0x07; DO_DISS(statusMsg << "subs r" << dec << rd << ",#0x" << Base::HEX2 << rb << endl); ra = read_register(rd); rc = ra - rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); do_cflag(ra, ~rb, 1); do_vflag(ra, ~rb, 1); return 0; } //SUB(3) if((inst & 0xFE00) == 0x1A00) { rd = (inst >> 0) & 0x7; rn = (inst >> 3) & 0x7; rm = (inst >> 6) & 0x7; DO_DISS(statusMsg << "subs r" << dec << rd << ",r" << dec << rn << ",r" << dec << rm << endl); ra = read_register(rn); rb = read_register(rm); rc = ra - rb; write_register(rd, rc); do_nflag(rc); do_zflag(rc); do_cflag(ra, ~rb, 1); do_vflag(ra, ~rb, 1); return 0; } //SUB(4) if((inst & 0xFF80) == 0xB080) { rb = inst & 0x7F; rb <<= 2; DO_DISS(statusMsg << "sub SP,#0x" << Base::HEX2 << rb << endl); ra = read_register(13); ra -= rb; write_register(13, ra); return 0; } //SWI if((inst & 0xFF00) == 0xDF00) { rb = inst & 0xFF; DO_DISS(statusMsg << "swi 0x" << Base::HEX2 << rb << endl); if((inst & 0xFF) == 0xCC) { write_register(0, cpsr); return 0; } else { statusMsg << endl << endl << "swi 0x" << Base::HEX2 << rb << endl; return 1; } } //SXTB if((inst & 0xFFC0) == 0xB240) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "sxtb r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rm); rc = ra & 0xFF; if(rc & 0x80) rc |= (~0u) << 8; write_register(rd, rc); return 0; } //SXTH if((inst & 0xFFC0) == 0xB200) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "sxth r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rm); rc = ra & 0xFFFF; if(rc & 0x8000) rc |= (~0u) << 16; write_register(rd, rc); return 0; } //TST if((inst & 0xFFC0) == 0x4200) { rn = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "tst r" << dec << rn << ",r" << dec << rm << endl); ra = read_register(rn); rb = read_register(rm); rc = ra & rb; do_nflag(rc); do_zflag(rc); return 0; } //UXTB if((inst & 0xFFC0) == 0xB2C0) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "uxtb r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rm); rc = ra & 0xFF; write_register(rd, rc); return 0; } //UXTH if((inst & 0xFFC0) == 0xB280) { rd = (inst >> 0) & 0x7; rm = (inst >> 3) & 0x7; DO_DISS(statusMsg << "uxth r" << dec << rd << ",r" << dec << rm << endl); ra = read_register(rm); rc = ra & 0xFFFF; write_register(rd, rc); return 0; } statusMsg << "invalid instruction " << Base::HEX8 << pc << " " << Base::HEX4 << inst << endl; return 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Thumbulator::reset() { std::fill(reg_norm, reg_norm+12, 0); reg_norm[13] = 0x40001FB4; switch(configuration) { // future 2K Harmony/Melody drivers will most likely use these settings case ConfigureFor::BUS: case ConfigureFor::CDF: case ConfigureFor::CDF1: reg_norm[14] = 0x00000800; // Link Register reg_norm[15] = 0x0000080B; // Program Counter break; // future 3K Harmony/Melody drivers will most likely use these settings case ConfigureFor::DPCplus: reg_norm[14] = 0x00000C00; // Link Register reg_norm[15] = 0x00000C0B; // Program Counter break; } cpsr = mamcr = 0; handler_mode = false; systick_ctrl = 0x00000004; systick_reload = 0x00000000; systick_count = 0x00000000; systick_calibrate = 0x00ABCDEF; // fxq: don't care about below so much (maybe to guess timing???) instructions = fetches = reads = writes = systick_ints = 0; statusMsg.str(""); return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Thumbulator::trapOnFatal = true; stella-5.1.1/src/emucore/Thumbulator.hxx000066400000000000000000000126271324334165500203050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ //============================================================================ // This class provides Thumb emulation code ("Thumbulator") // by David Welch (dwelch@dwelch.com) // Modified by Fred Quimby // Code is public domain and used with the author's consent //============================================================================ #ifndef THUMBULATOR_HXX #define THUMBULATOR_HXX class Cartridge; // FIXME - This code has many instances of shifting into signed integers // Perhaps the int's should be changed to uInt32 #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wshift-sign-overflow" #endif #include "bspf.hxx" #include "Console.hxx" #define ROMADDMASK 0x7FFF #define RAMADDMASK 0x1FFF #define ROMSIZE (ROMADDMASK+1) #define RAMSIZE (RAMADDMASK+1) #define CPSR_N (1<<31) #define CPSR_Z (1<<30) #define CPSR_C (1<<29) #define CPSR_V (1<<28) class Thumbulator { public: // control cartridge specific features of the Thumbulator class, // such as the start location for calling custom code enum ConfigureFor { BUS, // cartridges of type BUS CDF, // cartridges of type CDF CDF1, // cartridges of type CDF version 1 DPCplus // cartridges of type DPC+ }; Thumbulator(const uInt16* rom, uInt16* ram, bool traponfatal, Thumbulator::ConfigureFor configurefor, Cartridge* cartridge); /** Run the ARM code, and return when finished. A runtime_error exception is thrown in case of any fatal errors/aborts (if enabled), containing the actual error, and the contents of the registers at that point in time. @return The results of any debugging output (if enabled), otherwise an empty string */ string run(); string run(uInt32 cycles); /** Normally when a fatal error is encountered, the ARM emulation immediately throws an exception and exits. This method allows execution to continue, and simply log the error. Note that this is meant for developers only, and should normally be always enabled. It can be used to temporarily ignore illegal reads and writes, but a ROM which consistently performs these operations should be fixed, as it can cause crashes on real hardware. @param enable Enable (the default) or disable exceptions on fatal errors */ static void trapFatalErrors(bool enable) { trapOnFatal = enable; } /** Inform the Thumbulator class about the console currently in use, which is used to accurately determine how many 6507 cycles have passed while ARM code is being executed. */ void setConsoleTiming(ConsoleTiming timing); private: uInt32 read_register(uInt32 reg); void write_register(uInt32 reg, uInt32 data); uInt32 fetch16(uInt32 addr); uInt32 fetch32(uInt32 addr); uInt32 read16(uInt32 addr); uInt32 read32(uInt32 addr); bool isProtected(uInt32 addr); void write16(uInt32 addr, uInt32 data); void write32(uInt32 addr, uInt32 data); void updateTimer(uInt32 cycles); void do_zflag(uInt32 x); void do_nflag(uInt32 x); void do_cflag(uInt32 a, uInt32 b, uInt32 c); void do_vflag(uInt32 a, uInt32 b, uInt32 c); void do_cflag_bit(uInt32 x); void do_vflag_bit(uInt32 x); // Throw a runtime_error exception containing an error referencing the // given message and variables // Note that the return value is never used in these methods int fatalError(const char* opcode, uInt32 v1, const char* msg); int fatalError(const char* opcode, uInt32 v1, uInt32 v2, const char* msg); void dump_counters(); void dump_regs(); int execute(); int reset(); private: const uInt16* rom; uInt16* ram; uInt32 reg_norm[16]; // normal execution mode, do not have a thread mode uInt32 cpsr, mamcr; bool handler_mode; uInt32 systick_ctrl, systick_reload, systick_count, systick_calibrate; uInt64 instructions, fetches, reads, writes, systick_ints; // For emulation of LPC2103's timer 1, used for NTSC/PAL/SECAM detection. // Register names from documentation: // http://www.nxp.com/documents/user_manual/UM10161.pdf uInt32 T1TCR; // Timer 1 Timer Control Register uInt32 T1TC; // Timer 1 Timer Counter double timing_factor; ostringstream statusMsg; static bool trapOnFatal; ConfigureFor configuration; Cartridge* myCartridge; private: // Following constructors and assignment operators not supported Thumbulator() = delete; Thumbulator(const Thumbulator&) = delete; Thumbulator(Thumbulator&&) = delete; Thumbulator& operator=(const Thumbulator&) = delete; Thumbulator& operator=(Thumbulator&&) = delete; }; #endif // THUMBULATOR_HXX stella-5.1.1/src/emucore/TrakBall.hxx000066400000000000000000000033301324334165500174620ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TRAKBALL_HXX #define TRAKBALL_HXX #include "PointingDevice.hxx" class TrakBall : public PointingDevice { public: /** Create a new trakball controller plugged into the specified jack @param jack The jack the controller is plugged into @param event The event object to use for events @param system The system using this controller */ TrakBall(Jack jack, const Event& event, const System& system) : PointingDevice(jack, event, system, Controller::TrakBall, trackballSensitivity) { } virtual ~TrakBall() = default; protected: uInt8 ioPortA(uInt8 countH, uInt8 countV, uInt8 left, uInt8 down) override { static constexpr uInt32 ourTableH[2][2] = {{ 0b00, 0b01 }, { 0b10, 0b11 }}; static constexpr uInt32 ourTableV[2][2] = {{ 0b0100, 0b0000 }, { 0b1100, 0b1000 }}; return ourTableH[countH & 0b1][left] | ourTableV[countV & 0b1][down]; } // 50% of Atari and Amiga mouse static constexpr float trackballSensitivity = 0.4f; }; #endif // TRAKBALL_HXX stella-5.1.1/src/emucore/module.mk000066400000000000000000000041021324334165500170510ustar00rootroot00000000000000MODULE := src/emucore MODULE_OBJS := \ src/emucore/AtariVox.o \ src/emucore/Booster.o \ src/emucore/Cart.o \ src/emucore/CartDetector.o \ src/emucore/Cart0840.o \ src/emucore/Cart2K.o \ src/emucore/Cart3E.o \ src/emucore/Cart3EPlus.o \ src/emucore/Cart3F.o \ src/emucore/Cart4A50.o \ src/emucore/Cart4K.o \ src/emucore/Cart4KSC.o \ src/emucore/CartAR.o \ src/emucore/CartBUS.o \ src/emucore/CartCDF.o \ src/emucore/CartCM.o \ src/emucore/CartCTY.o \ src/emucore/CartCV.o \ src/emucore/CartCVPlus.o \ src/emucore/CartDASH.o \ src/emucore/CartDPC.o \ src/emucore/CartDPCPlus.o \ src/emucore/CartE0.o \ src/emucore/CartMNetwork.o \ src/emucore/CartE7.o \ src/emucore/CartE78K.o \ src/emucore/CartEF.o \ src/emucore/CartEFSC.o \ src/emucore/CartBF.o \ src/emucore/CartBFSC.o \ src/emucore/CartDF.o \ src/emucore/CartDFSC.o \ src/emucore/CartF0.o \ src/emucore/CartF4.o \ src/emucore/CartF4SC.o \ src/emucore/CartF6.o \ src/emucore/CartF6SC.o \ src/emucore/CartF8.o \ src/emucore/CartF8SC.o \ src/emucore/CartFA.o \ src/emucore/CartFA2.o \ src/emucore/CartFE.o \ src/emucore/CartMDM.o \ src/emucore/CartSB.o \ src/emucore/CartUA.o \ src/emucore/CartWD.o \ src/emucore/CartX07.o \ src/emucore/CompuMate.o \ src/emucore/Console.o \ src/emucore/Control.o \ src/emucore/Driving.o \ src/emucore/EventHandler.o \ src/emucore/EventJoyHandler.o \ src/emucore/FrameBuffer.o \ src/emucore/FBSurface.o \ src/emucore/FSNode.o \ src/emucore/Genesis.o \ src/emucore/Joystick.o \ src/emucore/Keyboard.o \ src/emucore/KidVid.o \ src/emucore/MindLink.o \ src/emucore/M6502.o \ src/emucore/M6532.o \ src/emucore/MT24LC256.o \ src/emucore/MD5.o \ src/emucore/OSystem.o \ src/emucore/Paddles.o \ src/emucore/PointingDevice.o \ src/emucore/Props.o \ src/emucore/PropsSet.o \ src/emucore/SaveKey.o \ src/emucore/Serializer.o \ src/emucore/Settings.o \ src/emucore/Switches.o \ src/emucore/System.o \ src/emucore/TIASnd.o \ src/emucore/TIASurface.o \ src/emucore/Thumbulator.o MODULE_DIRS += \ src/emucore # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/emucore/stella.pro000066400000000000000000023607151324334165500172620ustar00rootroot00000000000000"Cartridge.MD5" "000509d1ed2b8d30a9d94be1b3b5febb" "Cartridge.Manufacturer" "Greg Zumwalt" "Cartridge.Name" "Jungle Jane (2003) (Greg Zumwalt) (Hack)" "Cartridge.Note" "Hack of Pitfall!" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "0060a89b4c956b9c703a59b181cb3018" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines - Ariola" "Cartridge.ModelNo" "CM-008 - 712 008-720" "Cartridge.Name" "Cakewalk (1983) (CommaVid) (PAL)" "Cartridge.Note" "AKA Alarm in der Backstube" "" "Cartridge.MD5" "007d18dedc1f0565f09c42aa61a6f585" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-843" "Cartridge.Name" "Worm War I (1983) (CCE)" "" "Cartridge.MD5" "008543ae43497af015e9428a5e3e874e" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.09) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "00b7b4cbec81570642283e7fc1ef17af" "Cartridge.Manufacturer" "Sega - Beck-Tech, Steve Beck, Phat Ho" "Cartridge.ModelNo" "006-01" "Cartridge.Name" "Congo Bongo (1983) (Sega)" "Display.YStart" "26" "Display.Height" "220" "" "Cartridge.MD5" "00ce0bdd43aed84a983bef38fe7f5ee3" "Cartridge.Manufacturer" "20th Century Fox, Bill Aspromonte" "Cartridge.ModelNo" "11012" "Cartridge.Name" "Bank Heist (1983) (20th Century Fox)" "Cartridge.Note" "AKA Bonnie and Clyde, Cops 'n' Robbers, Holdup, Rooring 20's" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "00ce76ad69cdc2fa36ada01ae092d5a6" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP214" "Cartridge.Name" "Cosmic Avenger (4 Game in One) (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA StarMaster" "" "Cartridge.MD5" "00dc28b881989c39a6cf87a892bd3c6b" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Krull (CCE)" "" "Cartridge.MD5" "00e19ebf9d0817ccfb057e262be1e5af" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw" "Cartridge.ModelNo" "CX2639, CX2639P" "Cartridge.Name" "Othello (1981) (Atari) (PAL) [no grid markers]" "" "Cartridge.MD5" "00e55b27fe2e96354cd21b8b698d1e31" "Cartridge.Name" "Phoenix (Unknown)" "" "Cartridge.MD5" "00eaee22034aff602f899b684c107d77" "Cartridge.Manufacturer" "Rainbow Vision - Suntek - Sunteck Corp" "Cartridge.ModelNo" "SS-001" "Cartridge.Name" "Time Race (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Space Jockey" "Display.Height" "240" "" "Cartridge.MD5" "00f7985c20b8bdf3c557fac4d3f26775" "Cartridge.Manufacturer" "Aaron Curtis" "Cartridge.Name" "AStar (NTSC)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "012020625a3227815e47b37fd025e480" "Cartridge.Manufacturer" "Rob Kudla" "Cartridge.Name" "Better Space Invaders (1999) (Rob Kudla) (Hack) [a]" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "01293bd90a4579abb7aed2f7d440681f" "Cartridge.Manufacturer" "Century" "Cartridge.Name" "Snoopy (1983) (Century) (PAL)" "Cartridge.Note" "AKA Snoopy and the Red Baron" "" "Cartridge.MD5" "01297d9b450455dd716db9658efb2fae" "Cartridge.Manufacturer" "TechnoVision - Video Technology" "Cartridge.ModelNo" "TVS1002" "Cartridge.Name" "Save Our Ship (1983) (TechnoVision) (PAL)" "Display.YStart" "45" "" "Cartridge.MD5" "012b8e6ef3b5fd5aabc94075c527709d" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix (1983) (Arcadia)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 56" "" "Cartridge.MD5" "0164f26f6b38a34208cd4a2d0212afc3" "Cartridge.Manufacturer" "Coleco, Ed English" "Cartridge.ModelNo" "2656" "Cartridge.Name" "Mr. Do! (1983) (Coleco)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0173675d40a8d975763ee493377ca87d" "Cartridge.Manufacturer" "CBS Electronics, Ed English" "Cartridge.ModelNo" "4L1751" "Cartridge.Name" "Roc 'n Rope (1984) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "01abcc1d2d3cba87a3aa0eb97a9d7b9c" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Topy (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "01b09872dcd9556427761f0ed64aa42a" "Cartridge.Manufacturer" "Galaga Games" "Cartridge.Name" "River Raid (1984) (Galaga Games)" "" "Cartridge.MD5" "01cb3e8dfab7203a9c62ba3b94b4e59f" "Cartridge.Manufacturer" "Atari, Mimi Nyden, Scott Smith, Robert Vieira" "Cartridge.ModelNo" "CX26127" "Cartridge.Name" "Gremlins (1984) (Atari)" "" "Cartridge.MD5" "01e5c81258860dd82f77339d58bc5f5c" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Corrida da Matematica (CCE)" "Cartridge.Note" "AKA Math Gran Prix" "" "Cartridge.MD5" "01e60a109a6a67c70d3c0528381d0187" "Cartridge.Manufacturer" "ITT Family Games, Perry Rhodan-Serie" "Cartridge.ModelNo" "554-33 383" "Cartridge.Name" "Fire Birds (1983) (ITT Family Games) (PAL)" "Cartridge.Note" "AKA Sky Alien" "" "Cartridge.MD5" "01f584bf67b0e464014a8c8b5ea470e3" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "5 AR-4200" "Cartridge.Name" "Labyrinth (Escape from the Mindmaster Beta) (1982) (Arcadia)" "" "Cartridge.MD5" "02066b17f29082412c6754c1a2d6302e" "Cartridge.Name" "Demo Image Series #3 - Baboon (19-02-2003) (AD)" "" "Cartridge.MD5" "024365007a87f213cbe8ef5f2e8e1333" "Cartridge.Manufacturer" "Atari, Frank Hausman, Mimi Nyden, Steve Woita" "Cartridge.ModelNo" "CX2686" "Cartridge.Name" "Quadrun (1983) (Atari)" "" "Cartridge.MD5" "025668e36a788e8af8ac4f1be7e72043" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX2659" "Cartridge.Name" "Raiders of the Lost Ark (06-14-82) (Atari) (Prototype)" "Cartridge.Note" "Console ports are swapped" "Cartridge.Rarity" "Prototype" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "026180bf641ff17d8577c33facf0edea" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-022" "Cartridge.Name" "Seaquest (1983) (Activision) (8K)" "" "Cartridge.MD5" "0277c449fae63f6f1c8f94dedfcf0058" "Cartridge.Name" "Laser Demo (B. Watson)" "" "Cartridge.MD5" "027a59a575b78860aed780b2ae7d001d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Pressure Cooker (CCE)" "" "Cartridge.MD5" "028024fb8e5e5f18ea586652f9799c96" "Cartridge.Manufacturer" "Coleco - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen" "Cartridge.ModelNo" "2468" "Cartridge.Name" "Carnival (1982) (Coleco)" "" "Cartridge.MD5" "02811151906e477d47c135db5b1699c6" "Cartridge.Name" "FlickerSort Demo (Updated) (20-04-2002) (MP)" "" "Cartridge.MD5" "02a5fc90a0d183f870e8eebac1f16591" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-422" "Cartridge.Name" "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL)" "" "Cartridge.MD5" "02ab2c47bc21e7feafa015f90d7df776" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "MA017600" "Cartridge.Name" "Diagnostic Test Cartridge 2.6 (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "02ced7ea2b7cb509748db6bfa227ebec" "Cartridge.Manufacturer" "Parker Brothers, Ed English, David Lamkins" "Cartridge.ModelNo" "931502" "Cartridge.Name" "Frogger (1982) (Parker Bros) (PAL)" "" "Cartridge.MD5" "02cee0b140d2f1a1efcfb1d482a5c392" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2639 - 49-75162" "Cartridge.Name" "Othello (1981) (Atari) (4K)" "" "Cartridge.MD5" "02dcba28c614fec7ca25955327128abb" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Laseresal 2002 (PAL) (PD) [a]" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "02e3f4ba156fb578bef7d7a0bf3400c1" "Cartridge.Name" "Booster (Junkosoft) (PD)" "" "Cartridge.MD5" "033e21521e0bf4e54e8816873943406d" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius Software, Dan Thompson" "Cartridge.ModelNo" "11020" "Cartridge.Name" "Earth Dies Screaming, The (1983) (20th Century Fox)" "Cartridge.Note" "The Day the Earth Stood Still" "" "Cartridge.MD5" "034c1434280b0f2c9f229777d790d1e1" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5665 A016" "Cartridge.Name" "Baseball (1988) (Telegames) (PAL)" "Cartridge.Note" "AKA Super Challenge Baseball" "" "Cartridge.MD5" "0375f589f7da06d2d2be532e0d4d4b94" "Cartridge.Name" "Push (V0.04) (2001) (AD)" "" "Cartridge.MD5" "0383dc02cb82302da3d155fd108bfe3a" "Cartridge.Manufacturer" "AtariAge, Chris Spry" "Cartridge.ModelNo" "CX26200" "Cartridge.Name" "Princess Rescue (2013) (Sprybug) (PAL60)" "Cartridge.Note" "Compatible with Genesis controller" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "038e1e79c3d4410defde4bfe0b99cc32" "Cartridge.Manufacturer" "Atari, Tod Frye, Gary Shannon" "Cartridge.Name" "Aquaventure (08-12-1983) (Atari) (Prototype)" "Cartridge.Note" "AKA Sea Sentinel" "Cartridge.Rarity" "Unbelievably Rare" "" "Cartridge.MD5" "039cf18b459d33b8a8fca31d06c4c244" "Cartridge.Name" "Demo Image Series #0 (12-02-2003) (AD)" "" "Cartridge.MD5" "03b1051c9374678363c899914412cfc5" "Cartridge.Name" "Incoming (30-10-2002) (Ben Larson) (PD)" "" "Cartridge.MD5" "03c3f7ba4585e349dd12bfa7b34b7729" "Cartridge.Manufacturer" "Sega, Jeff Lorenz" "Cartridge.ModelNo" "004-01" "Cartridge.Name" "Star Trek - Strategic Operations Simulator (1983) (Sega)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "03ff9e8a7af437f16447fe88cea3226c" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA285" "Cartridge.Name" "Wall-Defender (1983) (Bomb)" "Cartridge.Note" "AKA Wall Break" "" "Cartridge.MD5" "04014d563b094e79ac8974366f616308" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn" "Cartridge.ModelNo" "CX2690" "Cartridge.Name" "Pengo (1984) (Atari)" "" "Cartridge.MD5" "041b5e56bbc650db574bd8db3fae2696" "Cartridge.Name" "Thrust (V1.0) (2000) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "043f165f384fbea3ea89393597951512" "Cartridge.Manufacturer" "Spectravision - Spectravideo" "Cartridge.ModelNo" "SA-202" "Cartridge.Name" "Planet Patrol (1982) (Spectravision)" "" "Cartridge.MD5" "0443cfa9872cdb49069186413275fa21" "Cartridge.Manufacturer" "M Network, Patricia Lewis Du Long, Ron Surratt - INTV" "Cartridge.ModelNo" "MT4518" "Cartridge.Name" "BurgerTime (1983) (M Network)" "" "Cartridge.MD5" "045035f995272eb2deb8820111745a07" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (1983) (Arcadia)" "Cartridge.Note" "AKA Jungle Raid" "" "Cartridge.MD5" "047ac3b9faea64522b7a23c4465a7aa8" "Cartridge.Name" "Defender (Unknown) (PAL)" "" "Cartridge.MD5" "04856e3006a4f5f7b4638da71dad3d88" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26176" "Cartridge.Name" "Radar Lock (1989) (Atari) (PAL)" "Cartridge.Note" "AKA Dog Fight" "" "Cartridge.MD5" "049626cbfb1a5f7a5dc885a0c4bb758e" "Cartridge.Name" "MegaMania (Unknown) (PAL)" "" "Cartridge.MD5" "04b488d4eef622d022a0021375e7e339" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83107" "Cartridge.Name" "Tennis (1983) (Home Vision) (PAL) (4K)" "" "Cartridge.MD5" "04dfb4acac1d0909e4c360fd2ac04480" "Cartridge.Name" "Jammed (2001) (XYPE) (NTSC)" "" "Cartridge.MD5" "04e737c9d53cd84bfd5ee679954e4706" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Checkers (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "04fccc7735155a6c1373d453b110c640" "Cartridge.Manufacturer" "HES - Imagineering, David Lubar" "Cartridge.ModelNo" "535" "Cartridge.Name" "My Golf (1990) (HES) (PAL)" "" "Cartridge.MD5" "0519f395d5f7d76be813b834aa51c0be" "Cartridge.Manufacturer" "Atari, Ian Shepard" "Cartridge.ModelNo" "CX2604" "Cartridge.Name" "Space War (1978) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "0546f4e6b946f38956799dd00caab3b1" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "My Golf (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "056f5d886a4e7e6fdd83650554997d0d" "Cartridge.Manufacturer" "Parker Brothers, Ed Temple" "Cartridge.ModelNo" "931504" "Cartridge.Name" "Amidar (1982) (Parker Bros) (PAL)" "Cartridge.Rarity" "Uncommon" "Console.LeftDifficulty" "A" "Console.RightDifficulty" "A" "" "Cartridge.MD5" "056ff67dd9715fafa91fb8b0ddcc4a46" "Cartridge.Name" "Frisco (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "05824fcbe615dbca836d061a140a50e0" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 9 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "05aedf04803c43eb5e09dfd098d3fd01" "Cartridge.Name" "Keystone Kapers (Unknown) (PAL)" "" "Cartridge.MD5" "05aff8f626ef870432ae3b3d9d5aa301" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-019" "Cartridge.Name" "Sky Jinks (1982) (Activision) (16K)" "" "Cartridge.MD5" "05b45ba09c05befa75ac70476829eda0" "Cartridge.Manufacturer" "Parker Brothers, Rex Bradford" "Cartridge.ModelNo" "931507" "Cartridge.Name" "Star Wars - Jedi Arena (1983) (Parker Bros) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (swapped)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 50" "" "Cartridge.MD5" "05c60458ec69e7fe8b1be973852d84f1" "Cartridge.Name" "Test (1996) (J.V. Matthews) (PD)" "" "Cartridge.MD5" "05ccf96247af12eef59698f1a060a54f" "Cartridge.Manufacturer" "Otto Versand" "Cartridge.ModelNo" "600273" "Cartridge.Name" "King Arthur (1983) (Otto Versand) (PAL)" "Cartridge.Note" "AKA Dragonfire (Double-Game Package)" "" "Cartridge.MD5" "05d61b925d3d2474bab83f0a79bb5df1" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Cosmic Ark Stars (1997) (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "05eb4347f0ec8f4783983ca35ffd8d1b" "Cartridge.Name" "Qb (2.06) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "05ebd183ea854c0a1b56c218246fbbae" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2656" "Cartridge.Name" "SwordQuest - EarthWorld (1982) (Atari) [a]" "" "Cartridge.MD5" "05f11fb2e45c4e47424d3cb25414d278" "Cartridge.Name" "Boring (NTSC) (AD)" "" "Cartridge.MD5" "060c865c782debb047e6fd101c8923fc" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL) (4K)" "Cartridge.Note" "AKA Freeway" "" "Cartridge.MD5" "0614ed51acd027d531e7c85c4f435292" "Cartridge.Name" "Narnia (Glenn Saunders) (PD)" "" "Cartridge.MD5" "0651216c4a4a9c9ac5ada3013a317c72" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Fishing Derby (Jone Yuan) (4K) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "06742cf522f23797157f215a1dc8a1a9" "Cartridge.Name" "Healthbars (PD)" "" "Cartridge.MD5" "0685bd0bcb975ceef7041749a5454a48" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "11 Sprite Demo (Piero Cavina) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "06953ed762220dba63d63930d4ad0cc3" "Cartridge.Name" "Star Fire - Eckhard WIP (MP)" "" "Cartridge.MD5" "069c17beb1e8e0557adb8539fdcf6cba" "Cartridge.Name" "Phantom II & Pirate (PAL60)" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "Cartridge.MD5" "06b0194ce992584c365278e0d7323279" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game #2 (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "06b6c5031b8353f3a424a5b86b8fe409" "Cartridge.Manufacturer" "Activision, Mike Lorenzen - Ariola" "Cartridge.ModelNo" "EAX-023 - 711 023-720" "Cartridge.Name" "Oink! (1983) (Activision) (PAL)" "Cartridge.Note" "AKA Das Schweinchen und der Wolf" "" "Cartridge.MD5" "06cfd57f0559f38b9293adae9128ff88" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "4317 A009" "Cartridge.Name" "Adventures on GX-12 (1988) (Telegames) (PAL)" "Cartridge.Note" "AKA Adventures of Tron" "" "Cartridge.MD5" "06db908011065e5ebb37f4e253c2a0b0" "Cartridge.Name" "Gopher (Unknown) (PAL)" "" "Cartridge.MD5" "06e5dc181a8eda1c31cc7c581c68b6ef" "Cartridge.Name" "Tac-Scan (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "071f84d10b343c7c05ce3e32af631687" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP233" "Cartridge.Name" "Krieg der Sterne (Ariola) (PAL)" "Cartridge.Note" "AKA Atlantis" "" "Cartridge.MD5" "072a6ea2181ca0df88ac0dedc67b239d" "Cartridge.Name" "Multiple Missiles Demo (19-12-2002) (CT)" "" "Cartridge.MD5" "073cb76b006af034fd150be3f5e0e7e6" "Cartridge.Name" "Mobile 48 Sprite Kernel (Bug Fixed) (10-01-2003) (Eric Ball)" "" "Cartridge.MD5" "073d7aff37b7601431e4f742c36c0dc1" "Cartridge.Name" "Bermuda (Unknown) (PAL)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "074ec425ec20579e64a7ded592155d48" "Cartridge.Manufacturer" "Atari - Sculptured Software, Steve Aguirre" "Cartridge.ModelNo" "CX26162" "Cartridge.Name" "Fatal Run (Ultimate Driving) (1991) (Atari) (PAL)" "" "Cartridge.MD5" "075069ad80cde15eca69e3c98bd66714" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-803" "Cartridge.Name" "Bobby Is Going Home (1983) (CCE)" "Cartridge.Note" "AKA Bobby Vai Para Casa" "" "Cartridge.MD5" "0751f342ee4cf28f2c9a6e8467c901be" "Cartridge.Manufacturer" "Atari, Mimi Nyden, Joseph Tung" "Cartridge.ModelNo" "CX26152" "Cartridge.Name" "Super Baseball (1988) (Atari) (PAL)" "" "Cartridge.MD5" "07973be3ecfd55235bf59aa56bdef28c" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "732.052 6" "Cartridge.Name" "Eddy Langfinger, der Museumsdieb (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA A Mysterious Thief" "Display.Phosphor" "YES" "" "Cartridge.MD5" "079fe9103515d15bc108577e234a484d" "Cartridge.Name" "Multi-Color Demo 0 (Bob Colbert) (PD)" "" "Cartridge.MD5" "07a3af1e18b63765b6807876366f5e8a" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 2 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "07c76f2d88552d20ad2c0ed7aef406c6" "Cartridge.Manufacturer" "Cody Pittman" "Cartridge.Name" "Blob (Cody Pittman) (Hack)" "Cartridge.Note" "Hack of Halloween" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "07f42847a79e4f5ae55cc03304b18c25" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Sea Hawk (Zellers)" "Cartridge.Note" "AKA Seahawk" "" "Cartridge.MD5" "07f84db31e97ef8d08dc9fa8a5250755" "Cartridge.Manufacturer" "Supergame" "Cartridge.Name" "Enduro (1984) (Supergame)" "" "Cartridge.MD5" "07f91e33e76f53bb9d2731fd5d8a35a5" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX2632" "Cartridge.Name" "Space Invaders (1978) (Atari) [t1]" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "0805366f1b165a64b6d4df20d2c39d25" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2650" "Cartridge.Name" "Berzerk (1982) (Atari) (PAL)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "08188785e2b8300983529946dbeff4d2" "Cartridge.Manufacturer" "Atari, Carla Meninsky, Ed Riddle - Sears" "Cartridge.ModelNo" "CX2611 - 99821, 49-75149" "Cartridge.Name" "Indy 500 (1977) (Atari) (4K)" "Cartridge.Note" "Uses the Driving Controllers" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "Controller.MouseAxis" "45" "Display.YStart" "28" "" "Cartridge.MD5" "081e2c114c9c20b61acf25fc95c71bf4" "Cartridge.Manufacturer" "Parker Brothers, Ed English, David Lamkins" "Cartridge.ModelNo" "PB5300" "Cartridge.Name" "Frogger (1982) (Parker Bros)" "" "Cartridge.MD5" "082fdc8bd47fef01482ce5883c4ffdb8" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "Tanks DX (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Tanks But No Tanks" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "0832fb2ee654bf9382bc57d2b16d2ffc" "Cartridge.Manufacturer" "Apollo, Ed Salvo" "Cartridge.ModelNo" "AP-1001" "Cartridge.Name" "Skeet Shoot (1981) (Apollo) (PAL)" "" "Cartridge.MD5" "083e7cae41a874b2f9b61736c37d2ffe" "Cartridge.Manufacturer" "Imagic, Rob Fulop, Bob Smith" "Cartridge.ModelNo" "720106-2A, IA3600P, EIX-009-04I" "Cartridge.Name" "Riddle of the Sphinx (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "085322bae40d904f53bdcc56df0593fc" "Cartridge.Manufacturer" "Parker Brothers, Dave Engman, Dawn Stockbridge" "Cartridge.ModelNo" "PB5340" "Cartridge.Name" "Tutankham (1983) (Parker Bros)" "" "Cartridge.MD5" "0856f202b18cd46e44fd1dc3b42e9bfb" "Cartridge.Name" "Frame Counter 1 (2001) (Jake Patterson) (PD)" "" "Cartridge.MD5" "0866e22f6f56f92ea1a14c8d8d01d29c" "Cartridge.Manufacturer" "Androbot - Western Technologies, Michael Case, Lenny Carlson" "Cartridge.Name" "AndroMan on the Moon (1984) (Western Tech) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "0890a5b089191f45d0f08dd1e3235687" "Cartridge.Name" "Star Fire - 4K Version (25-10-2002) (MP)" "" "Cartridge.MD5" "0894aa7be77521f9df562be8d9555fe6" "Cartridge.Manufacturer" "CBS Electronics, Dan Kitchen, Garry Kitchen" "Cartridge.ModelNo" "4L1700, 4L1701, 4L1702, 4L1802, 4L2274" "Cartridge.Name" "Donkey Kong (1982) (CBS Electronics) (PAL) [a2]" "" "Cartridge.MD5" "08989fa4ff537f5dbd611aff4019521a" "Cartridge.Manufacturer" "Atari, Gary Palmer" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fun with Numbers (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "08bd4c1dcc843f6a0b563d9fd80b3b11" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "343.273 9" "Cartridge.Name" "Phantompanzer II (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Thunderground" "" "Cartridge.MD5" "08bf437d012db07b05ff57a0c745c49e" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen H. Landrum" "Cartridge.ModelNo" "4 AR-4102" "Cartridge.Name" "Meteoroids (1982) (Arcadia) (Prototype)" "Cartridge.Note" "Suicide Mission Beta" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "08d1b6d75206edb999252caf542a2c7f" "Cartridge.Manufacturer" "Larry Petit" "Cartridge.Name" "Super Home Run (2003) (Larry Petit) (Hack)" "Cartridge.Note" "Hack of Home Run" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "08d60a58a691c7f690162850302dc0e1" "Cartridge.Name" "Poker Squares (V0.27) (PAL) (2001) (B. Watson)" "" "Cartridge.MD5" "08e5960bb52d9a3e2c9954677b5e4472" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams" "Cartridge.ModelNo" "CX26101" "Cartridge.Name" "Oscar's Trash Race (10-20-1982) (Atari) (Prototype)" "Cartridge.Note" "Uses the Keypad Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.YStart" "34" "" "Cartridge.MD5" "08f4dc6f118f7c98e2406c180c08e78e" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix - Tug of War (2 of 3) (1983) (Arcadia) (PAL)" "Cartridge.Note" "Uses Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "02" "" "Cartridge.MD5" "08f853e8e01e711919e734d85349220d" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Michael Sierchio" "Cartridge.ModelNo" "CX2667" "Cartridge.Name" "RealSports Soccer (1983) (Atari)" "" "Cartridge.MD5" "0906c6e0e4bda9c10cfa4c5fc64d2f4b" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.12) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "090f0a7ef8a3f885048d213faa59b2f8" "Cartridge.Manufacturer" "Carrere Video - Western Technologies - Teldec - Prism" "Cartridge.ModelNo" "USC1012" "Cartridge.Name" "M.A.D. (1983) (Carrere Video) (PAL)" "" "Cartridge.MD5" "09274c3fc1c43bf1e362fda436651fd8" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Acid Drop (TJ)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.YStart" "6" "Display.Height" "240" "" "Cartridge.MD5" "09388bf390cd9a86dc0849697b96c7dc" "Cartridge.Manufacturer" "Absolute Entertainment, Alex DeMeo" "Cartridge.ModelNo" "AG-045-04, AK-045-04" "Cartridge.Name" "Pete Rose Baseball (1988) (Absolute)" "" "Cartridge.MD5" "0945081a6bd00345ff3d58eb7a07330a" "Cartridge.Name" "Stampede (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "0956285e24a18efa10c68a33846ca84d" "Cartridge.Manufacturer" "Dismac" "Cartridge.Name" "Viagem Espacial (Dismac)" "Cartridge.Note" "AKA Star Voyager" "" "Cartridge.MD5" "0963aa9f7f6cf5a36ff700001583624e" "Cartridge.Manufacturer" "Franklin Cruz" "Cartridge.Name" "Space Invaders 2 (Hack) [o1]" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "096649575e451508006b17e0353259a5" "Cartridge.Manufacturer" "Justin J. Scott" "Cartridge.Name" "Yar Vs. Yar (2002) (Justin J. Scott) (Hack)" "Cartridge.Note" "Hack of Yars' Revenge" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "097074f24cde141fe6a0f26a10333265" "Cartridge.Name" "Marble Craze (V0.90) (Paul Slocum)" "Display.YStart" "30" "" "Cartridge.MD5" "097936b07e0e0117b9026ae6835eb168" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "720100-2B, IA3000P" "Cartridge.Name" "Trick Shot (1982) (Imagic) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "09abfe9a312ce7c9f661582fdf12eab6" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26154" "Cartridge.Name" "Super Football (1988) (Atari)" "" "Cartridge.MD5" "09d19274c20768f842e8fae84b766abe" "Cartridge.Name" "Star Fire - Animated Patricles (06-10-2002) (MP)" "" "Cartridge.MD5" "09e1ecf9bd2a3030d5670dba7a65e78d" "Cartridge.Manufacturer" "Atari, James Andreasen" "Cartridge.ModelNo" "CX2654" "Cartridge.Name" "Haunted House (1982) (Atari) (PAL)" "" "Cartridge.MD5" "09f89bbfa2ab00f1964d200e12d7ced0" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "MA017600" "Cartridge.Name" "Diagnostic Test Cartridge 2.6 (1982) (Atari) (Prototype) (4K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "0a1b98937911d621b004b1617446d124" "Cartridge.Name" "Hangman Pac-Man Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "0a981c03204ac2b278ba392674682560" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2651 - 99805, 49-75602" "Cartridge.Name" "Blackjack (1977) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "" "Cartridge.MD5" "0aa208060d7c140f20571e3341f5a3f8" "Cartridge.Manufacturer" "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper" "Cartridge.ModelNo" "VC1009" "Cartridge.Name" "Towering Inferno (1982) (U.S. Games)" "Cartridge.Note" "Uses the Joystick Controllers (swapped)" "Console.SwapPorts" "YES" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0abf64ca504a116adca80f77f85e00fb" "Cartridge.Name" "Cube Conquest (Billy Eno) (PD)" "" "Cartridge.MD5" "0ac0d491763153fac75f5337ce32a9d6" "Cartridge.Name" "SPAM Image Demo (PD)" "" "Cartridge.MD5" "0acaf71e60b89f6b6eab63db6ab84510" "Cartridge.Name" "This Planet Sucks (Greg Troutman) [a2]" "Cartridge.Rarity" "New Release" "Display.YStart" "36" "" "Cartridge.MD5" "0aceb7c3bd13fe048b77a1928ed4267d" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "720102-2B, IA3201P, EIX-011-04I" "Cartridge.Name" "Star Voyager (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "0ad9a358e361256b94f3fb4f2fa5a3b1" "Cartridge.Manufacturer" "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner - Sears" "Cartridge.ModelNo" "CX2608 - 49-75165" "Cartridge.Name" "Super Breakout (1982 - 1981) (Atari) [a]" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 45" "" "Cartridge.MD5" "0adb21206de92e8aec5ef295805ebb90" "Cartridge.Name" "Solaris (Genesis)" "Cartridge.Note" "Genesis controller (C switches to map mode)" "Cartridge.Rarity" "Hack of Solaris" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "0ae3497e731ca0bf6a77b23441d9d9f9" "Cartridge.Name" "Analog Clock (V0.0) (20-01-2003) (AD)" "" "Cartridge.MD5" "0af51ceb4aecc7a8fc89781ac44a1973" "Cartridge.Manufacturer" "Barry Laws Jr." "Cartridge.Name" "Face Invaders Deluxe (Barry Laws Jr.) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "0afe6ae18966795b89314c3797dd2b1e" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692, CX2692P" "Cartridge.Name" "Moon Patrol (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "0b01909ba84512fdaf224d3c3fd0cf8d" "Cartridge.Name" "Revenge of the Apes (Hack)" "Cartridge.Note" "Hack of Planet of the Apes" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "0b1056f1091cfdc5eb0e2301f47ac6c3" "Cartridge.Manufacturer" "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec" "Cartridge.ModelNo" "7-001 - 3.60001 VE" "Cartridge.Name" "King Kong (1982) (Tigervision) (PAL) [a]" "" "Cartridge.MD5" "0b17ed42984000da8b727ca46143f87a" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu" "Cartridge.ModelNo" "CX26104" "Cartridge.Name" "Big Bird's Egg Catch (05-17-1983) (Atari) (Prototype)" "Cartridge.Note" "Uses the Keypad Controller" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "" "Cartridge.MD5" "0b24658714f8dff110a693a2052cc207" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-815" "Cartridge.Name" "Seaquest (1983) (CCE)" "" "Cartridge.MD5" "0b33252b680b65001e91a411e56e72e9" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-832" "Cartridge.Name" "Atlantis (1983) (CCE) [a]" "" "Cartridge.MD5" "0b4e793c9425175498f5a65a3e960086" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Kung Fu Master (CCE)" "" "Cartridge.MD5" "0b55399cf640a2a00ba72dd155a0c140" "Cartridge.Manufacturer" "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop" "Cartridge.ModelNo" "720111-1A, 03205" "Cartridge.Name" "Fathom (1983) (Imagic)" "Cartridge.Note" "AKA Scuba" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0b577e63b0c64f9779f315dca8967587" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP236" "Cartridge.Name" "Raketen-Angriff (Ariola) (PAL)" "Cartridge.Note" "AKA Missile Control" "" "Cartridge.MD5" "0b8d3002d8f744a753ba434a4d39249a" "Cartridge.Manufacturer" "Sears Tele-Games, Robert Zdybel" "Cartridge.ModelNo" "CX2619 - 49-75159" "Cartridge.Name" "Stellar Track (1981) (Sears)" "Cartridge.Note" "AKA Stella Trak" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0bf19e40d5cd8aa5afb33b16569313e6" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira" "Cartridge.ModelNo" "CX26118" "Cartridge.Name" "Millipede (01-04-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "0bf1e354304f46c0caf8fc0f6f5e9525" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4105" "Cartridge.Name" "Official Frogger (1983) (Arcadia) [a]" "Display.YStart" "32" "" "Cartridge.MD5" "0bfabf1e98bdb180643f35f2165995d0" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2623 - 6-99819, 49-75108, 49-75125" "Cartridge.Name" "Home Run (1978) (Atari)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "0c0392db94a20e4d006d885abbe60d8e" "Cartridge.Name" "Dodge Demo 3 (PD)" "" "Cartridge.MD5" "0c35806ff0019a270a7acae68de89d28" "Cartridge.Manufacturer" "Froggo" "Cartridge.ModelNo" "FG1003" "Cartridge.Name" "Task Force (1987) (Froggo)" "Cartridge.Note" "AKA Gangster Alley" "" "Cartridge.MD5" "0c48e820301251fbb6bcdc89bd3555d9" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Andrew Fuchs" "Cartridge.ModelNo" "CX26120" "Cartridge.Name" "Stargate (1984) (Atari)" "" "Cartridge.MD5" "0c54811cf3b1f1573c9164d5f19eca65" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715" "Cartridge.Name" "Dragster (1980) (Activision) (PAL)" "Cartridge.Note" "AKA Dragster Rennen, Drag Strip" "" "Cartridge.MD5" "0c7926d660f903a2d6910c254660c32c" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2602, CX2602P" "Cartridge.Name" "Air-Sea Battle (1977) (Atari) (PAL)" "Cartridge.Note" "AKA Anti-Aircraft" "Cartridge.Rarity" "Uncommon" "Display.Height" "256" "" "Cartridge.MD5" "0c7bd935d9a7f2522155e48315f44fa0" "Cartridge.Manufacturer" "Carrere Video - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Tom Sloper - Teldec - Prism" "Cartridge.ModelNo" "USC1009" "Cartridge.Name" "Infernal Tower (1983) (Carrere Video) (PAL)" "Cartridge.Note" "AKA Towering Inferno" "Console.SwapPorts" "YES" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0c80751f6f7a3b370cc9e9f39ad533a7" "Cartridge.Manufacturer" "Atari, Carla Meninsky" "Cartridge.ModelNo" "CX2610" "Cartridge.Name" "Warlords (1981) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "0cb7af80fd0ddef84844481d85e5d29b" "Cartridge.Name" "Mr. Pac-Man (El Destructo)" "" "Cartridge.MD5" "0cc8224ff1edfe458e8629e9e5fe3f5b" "Cartridge.Name" "Trick 12 (2001) (TJ)" "" "Cartridge.MD5" "0cdd9cc692e8b04ba8eb31fc31d72e5e" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Wing War (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "0cebb0bb45a856b23f56d21ce7d1bc34" "Cartridge.Manufacturer" "20th Century Fox Video Games, Bill Aspromonte" "Cartridge.ModelNo" "11131" "Cartridge.Name" "Crash Dive (1983) (20th Century Fox) (PAL)" "" "Cartridge.MD5" "0cfdd2f3b243cac21f38a0f09f54bead" "Cartridge.Name" "Overhead Adventure Demo 4 (PD)" "" "Cartridge.MD5" "0d07d2c1be1a5eaaea235a533bcda781" "Cartridge.Name" "Scrolling Playfield 1 (Junkosoft) (PD)" "" "Cartridge.MD5" "0d09cff0d28033c02c3290edfc3a5cea" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "0d1b3abf681a2fc9a6aa31a9b0e8b445" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Laser Blast (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "0d27c7f5db349b592f70f68daf5e8f3b" "Cartridge.Name" "Space Instigators (21-10-2002) (CT)" "" "Cartridge.MD5" "0d35618b6d76ddd46d2626e9e3e40db5" "Cartridge.Name" "X-Doom V.26 (PD)" "" "Cartridge.MD5" "0d5af65ad3f19558e6f8e29bf2a9d0f8" "Cartridge.Manufacturer" "Atari - Sculptured Software, Adam Clayton" "Cartridge.ModelNo" "CX26151, CX26151P" "Cartridge.Name" "Dark Chambers (1989) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0d6b974fe58a1bdd453600401c407856" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "128-in-1 Junior Console (Chip 3 or 4) (1991) (Atari) (PAL)" "Cartridge.Note" "Actually contains only 16 games, not 32" "Cartridge.Type" "16IN1" "" "Cartridge.MD5" "0d786a41695e5fc8cffd05a6dbb3f659" "Cartridge.Name" "Scrolling Playfield With Score (10-02-2003) (Aaron Bergstrom)" "" "Cartridge.MD5" "0d7e630a14856f4d52c9666040961d4d" "Cartridge.Name" "Wavy Line Test (PD)" "" "Cartridge.MD5" "0d90a0ee73d55539b7def24c88caa651" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-005, CAG-005, AG-005-04" "Cartridge.Name" "Skiing (1980) (Activision) (16K)" "" "Cartridge.MD5" "0db4f4150fecf77e4ce72ca4d04c052f" "Cartridge.Manufacturer" "Atari, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2618 - 49-75123" "Cartridge.Name" "3-D Tic-Tac-Toe (1980) (Atari)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "0dd4c69b5f9a7ae96a7a08329496779a" "Cartridge.Manufacturer" "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec" "Cartridge.ModelNo" "7-001 - 3.60001 VE" "Cartridge.Name" "King Kong (1982) (Tigervision) (PAL)" "" "Cartridge.MD5" "0de53160a8b54c3aa5aed8d68c970b62" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "806.174 9" "Cartridge.Name" "Fuchs & Schweinchen Schlau (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Oink!" "" "Cartridge.MD5" "0dfbdadf8f1bc718e7e1bb3ccd5fef3d" "Cartridge.Name" "Mr. Pac-Man (New start tune) (El Destructo)" "" "Cartridge.MD5" "0e0808227ef41f6825c06f25082c2e56" "Cartridge.Name" "Candi (Hack) [a]" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "0e08cd2c5bcf11c6a7e5a009a7715b6a" "Cartridge.Name" "Boing! (PD) [a1]" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "0e224ea74310da4e7e2103400eb1b4bf" "Cartridge.Manufacturer" "Atari, Gary Shannon, Howard Scott Warshaw" "Cartridge.Name" "Mind Maze (10-10-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Controller.Right" "MINDLINK" "" "Cartridge.MD5" "0e4b2b6e014a93ef8be896823da0d4ec" "Cartridge.Name" "Skiing (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "0e713d4e272ea7322c5b27d645f56dd0" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83105" "Cartridge.Name" "Panda Chase (1983) (Home Vision) (PAL)" "Display.Height" "256" "" "Cartridge.MD5" "0e7e73421606873b544e858c59dc283e" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Super Soccer (Digivision)" "Cartridge.Note" "AKA RealSports Soccer" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0e86470791b26292abe1c64545c47985" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix - Down on the Line (3 of 3) (1983) (Arcadia) (PAL)" "Cartridge.Note" "Uses Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "Controller.MouseAxis" "01 70" "" "Cartridge.MD5" "0ec93f519bb769e0d9f80e61f6cc8023" "Cartridge.Manufacturer" "Atari - GCC, John Allred, Mike Feinstein" "Cartridge.ModelNo" "CX2688" "Cartridge.Name" "Jungle Hunt (02-25-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "0eebfb60d437796d536039701ec43845" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Cakewalk (Fabrizio Zavagli)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "0eecb5f58f55de9db4eedb3a0f6b74a8" "Cartridge.Manufacturer" "Xonox - Beck-Tech" "Cartridge.ModelNo" "6210, 06002, 06004, 99002" "Cartridge.Name" "Ghost Manor (1983) (Xonox) (4K)" "Display.YStart" "30" "" "Cartridge.MD5" "0ef64cdbecccb7049752a3de0b7ade14" "Cartridge.Manufacturer" "Atari, Joe Decuir, Larry Caplan, Steve Mayer, Larry Wagner" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Combat (32 in 1) (1988) (Atari) (PAL)" "Display.Height" "256" "" "Cartridge.MD5" "0f14c03050b35d6b1d8850b07578722d" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 10 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "0f24ca5668b4ab5dfaf217933c505926" "Cartridge.Name" "Fantastic Voyage (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "0f2e09c71cc216f79d22a804152ba24b" "Cartridge.Manufacturer" "Bob Colbert" "Cartridge.Name" "Scroller Demo (Bob Colbert) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0f341d1f4e144e3163d9a5fc5a662b79" "Cartridge.Name" "RUN Platform Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "0f39fc03d579d0d93a6b729a3746843e" "Cartridge.Manufacturer" "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX26111" "Cartridge.Name" "Snoopy and the Red Baron (05-27-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "0f643c34e40e3f1daafd9c524d3ffe64" "Cartridge.Manufacturer" "Atari, Robert C. Polaro, Alan J. Murphy - Sears" "Cartridge.ModelNo" "CX2609 - 49-75186" "Cartridge.Name" "Defender (1982) (Atari)" "" "Cartridge.MD5" "0f6676b05621f80c670966e2995b227a" "Cartridge.Name" "Globe Trotter Demo 1 (24-03-2003) (Weston)" "" "Cartridge.MD5" "0f738dc44437557624eb277ed7ad91c9" "Cartridge.Name" "Grand Prix (Unknown) (PAL)" "Cartridge.Note" "AKA Grand Prix" "" "Cartridge.MD5" "0f8043715d66a4bbed394ef801d99862" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "684.733 9" "Cartridge.Name" "Robin Hood (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Save Our Ship" "Display.YStart" "45" "" "Cartridge.MD5" "0f95264089c99fc2a839a19872552004" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009, AG-009-04" "Cartridge.Name" "Freeway (1981) (Activision) (8K)" "" "Cartridge.MD5" "0fba7d8c3520bdb681f75494e498ec36" "Cartridge.Name" "Gunfight 2600 - Final Run (MP)" "" "Cartridge.MD5" "0fbf618be43d4396856d4244126fe7dc" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "805.784 6" "Cartridge.Name" "Labyrinth (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Maze Craze" "Display.Format" "PAL" "" "Cartridge.MD5" "0fc161704c46e16f7483f92b06c1558d" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-853" "Cartridge.Name" "Spider Fighter (1983) (CCE)" "" "Cartridge.MD5" "0fcff6fe3b0769ad5d0cf82814d2a6d9" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-027" "Cartridge.Name" "Zoo Fun (Suntek) (PAL)" "Cartridge.Note" "AKA Panda Chase" "Display.Height" "256" "" "Cartridge.MD5" "0fd72a13b3b6103fc825a692c71963b4" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.ModelNo" "720104-2A, IA3204P, EIX-008-04I" "Cartridge.Name" "Cosmic Ark (1982) (Imagic) (PAL) [selectable starfield]" "" "Cartridge.MD5" "101ab60f4000a5d13792ef0abad5f74b" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26109" "Cartridge.Name" "Sorcerer's Apprentice (1983) (Atari) [a]" "" "Cartridge.MD5" "102672bbd7e25cd79f4384dd7214c32b" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2642 - 6-99814" "Cartridge.Name" "Hunt & Score - Memory Match (1978) (Atari)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "103d4c890c2108cb536372c98d093e5f" "Cartridge.Name" "Star Fire - Star Background (MP)" "" "Cartridge.MD5" "103e9d616328969f5d7b4e0a381b25d5" "Cartridge.Name" "Playfield Illustration and Logo Demo (2001) (Jake Patterson) (PD)" "" "Cartridge.MD5" "103f1756d9dc0dd2b16b53ad0f0f1859" "Cartridge.Manufacturer" "Home Vision, Gem International Corp." "Cartridge.Name" "Go Go Home Monster (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Go Go Home" "" "Cartridge.MD5" "104468e44898b8e9fa4a1500fde8d4cb" "Cartridge.Manufacturer" "AtariAge, Chris Spry" "Cartridge.ModelNo" "CX26200" "Cartridge.Name" "Princess Rescue (2013) (Sprybug)" "Cartridge.Note" "Compatible with Genesis controller" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "106326c262dfd3e8eaeabd961d2a0519" "Cartridge.Name" "PAL-NTSC Detector (15-11-2002) (CT)[a1]" "" "Cartridge.MD5" "106855474c69d08c8ffa308d47337269" "Cartridge.Manufacturer" "Atari - Sculptured Software, Adam Clayton" "Cartridge.ModelNo" "CX26151" "Cartridge.Name" "Dark Chambers (1989) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "107cc025334211e6d29da0b6be46aec7" "Cartridge.Manufacturer" "Atari, Bob Smith - Sears" "Cartridge.ModelNo" "CX2648 - 49-75161" "Cartridge.Name" "Video Pinball (1981) (Atari)" "" "Cartridge.MD5" "1086ff69f82b68d6776634f336fb4857" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009" "Cartridge.Name" "Bloody Human Freeway (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "10958cd0a1a81d599005f1797ab0e51d" "Cartridge.Name" "Centipede 2k (2000) (PD) (Hack)" "Cartridge.Note" "Hack of Centipede" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "10a3cd14e5dcfdde6ff216a14ce7b7dd" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX262, CX2627P" "Cartridge.Name" "Human Cannonball (1979) (Atari) (PAL)" "" "Cartridge.MD5" "10af8728f975aa35a99d0965de8f714c" "Cartridge.Manufacturer" "Dinatronic" "Cartridge.Name" "Seaquest (Dinatronic)" "" "Cartridge.MD5" "10c8cfd8c37522f11d47540ff024e5f9" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.ModelNo" "C 3016" "Cartridge.Name" "Demon Attack (Canal 3)" "" "Cartridge.MD5" "10eae73a07b3da044b72473d8d366267" "Cartridge.Manufacturer" "Funvision - Fund. Int'l Co." "Cartridge.Name" "Karate (1982) (Funvision) (PAL)" "" "Cartridge.MD5" "10f0ecaf962aef1fc28abed870b01b65" "Cartridge.Manufacturer" "Atari, Paul Donaldson" "Cartridge.Name" "Bionic Breakthrough (06-22-1984) (Atari) (Prototype)" "Cartridge.Note" "Uses the Mindlink Controller" "Cartridge.Rarity" "Prototype" "Controller.Left" "MINDLINK" "" "Cartridge.MD5" "10f62443f1ae087dc588a77f9e8f43e9" "Cartridge.Manufacturer" "Atari, Carla Meninsky" "Cartridge.ModelNo" "CX2637, CX2637P" "Cartridge.Name" "Dodge 'Em (1980) (Atari) (PAL) [fixed]" "" "Cartridge.MD5" "110ac8ecaf1b69f41bc94c59dfcb8b2d" "Cartridge.Name" "Demon Attack (Unknown)" "" "Cartridge.MD5" "111029770226b319524134193886a10e" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - One Limit Reached! (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "11330eaa5dd2629052fac37cfe1a0b7d" "Cartridge.Manufacturer" "128-in-1 Junior Console" "Cartridge.Name" "Human Cannonball (128-in-1 Junior Console) (PAL)" "" "Cartridge.MD5" "113cd09c9771ac278544b7e90efe7df2" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2639 - 49-75162" "Cartridge.Name" "Othello (1981) (Atari) [no grid markers]" "" "Cartridge.MD5" "114c599454d32f74c728a6e1f71012ba" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAX-015, EAX-015-04I - 711 015-725" "Cartridge.Name" "Chopper Command (1982) (Activision) (PAL)" "" "Cartridge.MD5" "11bcf5c752088b5aaf86d6c7a6a11e8d" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira" "Cartridge.ModelNo" "CX26118" "Cartridge.Name" "Millipede (1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "11cf751bc8173db105eabd119c5844ba" "Cartridge.Name" "Star Fire - Crosshair (12-02-2002) (MP)" "" "Cartridge.MD5" "11e7e0d9437ec98fa085284cf16d0eb4" "Cartridge.Name" "Bowling (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "11f9532557e4c9569f4b242164006161" "Cartridge.Manufacturer" "Chris Walton, Justin Hairgrove, Tony Morse" "Cartridge.Name" "Hunchy II (2005) (PAL)" "Cartridge.Note" "Homebrew" "" "Cartridge.MD5" "1201c18cf00d2c236f42e4d7d8c86aa1" "Cartridge.Name" "Nick Bensema Demo (Nick Bensema)" "" "Cartridge.MD5" "12123b534bdee79ed7563b9ad74f1cbd" "Cartridge.Manufacturer" "Absolute Entertainment, Alex DeMeo" "Cartridge.ModelNo" "AG-041-04" "Cartridge.Name" "Title Match Pro Wrestling (1987) (Absolute)" "" "Cartridge.MD5" "1228c01cd3c4b9c477540c5adb306d2a" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Basketball (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "Console ports are swapped" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "1266b3fd632c981f3ef9bdbf9f86ce9a" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "EAZ-034-04, EAZ-034-04I" "Cartridge.Name" "Private Eye (1984) (Activision) (PAL)" "" "Cartridge.MD5" "1267e3c6ca951ff1df6f222c8f813d97" "Cartridge.Name" "Dragonfire (Unknown) (PAL)" "" "Cartridge.MD5" "1278f74ca1dfaa9122df3eca3c5bcaad" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "719.013 5" "Cartridge.Name" "Ungeheuer der Tiefe (Quelle) (PAL)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "1287535256bf5dff404839ac9e25c3e7" "Cartridge.Manufacturer" "PacManPlus" "Cartridge.ModelNo" "Rev 2" "Cartridge.Name" "Alien Pac-Man (PacManPlus) (Hack)" "Cartridge.Note" "Hack of Alien" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "12937db3d4a80da5c4452b752891252d" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Megamania (1983) (Digitel)" "" "Cartridge.MD5" "12bca8305d5ab8ea51fe1cfd95d7ab0e" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite" "Cartridge.ModelNo" "80561-00250" "Cartridge.Name" "Summer Games (1987) (Epyx) (PAL)" "" "Cartridge.MD5" "12d7e0d6b187889f8d150bf7034d1db2" "Cartridge.Name" "Poker Squares (V0.0e) (2001) (B. Watson)" "" "Cartridge.MD5" "130c5742cd6cbe4877704d733d5b08ca" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83109" "Cartridge.Name" "World End (1983) (Home Vision) (PAL)" "" "Cartridge.MD5" "1323c45d660f5a5b6d5ea45c6c4cbe4a" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Enduro (Canal 3)" "" "Cartridge.MD5" "133456269a03e3fdae6cddd65754c50d" "Cartridge.Manufacturer" "Tigervision - Software Electronics Corporation - Teldec" "Cartridge.ModelNo" "7-006 - 3.60008 VG" "Cartridge.Name" "Springer (1983) (Tigervision) (PAL)" "" "Cartridge.MD5" "133a4234512e8c4e9e8c5651469d4a09" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee" "Cartridge.ModelNo" "CX26117" "Cartridge.Name" "Obelix (1984) (Atari)" "" "Cartridge.MD5" "133b56de011d562cbab665968bde352b" "Cartridge.Manufacturer" "Activision, John Van Ryzin" "Cartridge.ModelNo" "AG-038-04" "Cartridge.Name" "Cosmic Commuter (1984) (Activision)" "" "Cartridge.MD5" "1343de49c2a50d99176255f99f0d0234" "Cartridge.Manufacturer" "Gray Games & AtariAge" "Cartridge.Name" "E.T. Book Cart (PAL)" "Cartridge.Note" "Charles F. Gray & Michael Rideout" "Display.YStart" "24" "Display.Height" "280" "Display.Phosphor" "YES" "Display.PPBlend" "55" "" "Cartridge.MD5" "13448eb5ba575e8d7b8d5b280ea6788f" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Crackpots (Digivision)" "" "Cartridge.MD5" "1345e972dbe08ea3e70850902e20e1a5" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (rough beta) (Greg Troutman) (PD)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1351c67b42770c1bd758c3e42f553fea" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Keystone Kapers (Digivision)" "" "Cartridge.MD5" "135708b9a7dd20576c1b66ab2a41860d" "Cartridge.Name" "Hangman Man Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "13584411da0a8d431991035423fdc0dc" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Skiing (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "1367e41858be525710eb04d0dab53505" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "Zelda (2003) (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "136f75c4dd02c29283752b7e5799f978" "Cartridge.Manufacturer" "Atari, Dan Hitchens - Sears" "Cartridge.ModelNo" "CX2650 - 49-75168" "Cartridge.Name" "Berzerk (1982) (Atari)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "13895ef15610af0d0f89d588f376b3fe" "Cartridge.Manufacturer" "Tigervision, Rorke Weigandt" "Cartridge.ModelNo" "7-005" "Cartridge.Name" "Marauder (1982) (Tigervision)" "" "Cartridge.MD5" "13a37cf8170a3a34ce311b89bde82032" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker" "Cartridge.ModelNo" "CX2684, CX2684P" "Cartridge.Name" "Galaxian (1983) (Atari) (PAL)" "" "Cartridge.MD5" "13a991bc9c2ff03753aeb322d3e3e2e5" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Galactic (Funvision) (PAL)" "Cartridge.Note" "AKA Condor Attack" "" "Cartridge.MD5" "13aa1f9ac4249947e4af61319d9a08f2" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680, CX2680P" "Cartridge.Name" "RealSports Tennis (1983) (Atari) (PAL) [a1]" "" "Cartridge.MD5" "13abc32f803165c458bb086fa57195fb" "Cartridge.Manufacturer" "Christian Samuel" "Cartridge.Name" "E.T. The Extra-Testical (Christian Samuel) (Hack)" "Cartridge.Note" "Hack of E.T. The Extra-Terrestrial" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "13ccc692f111d52fec75d83df16192e2" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Fishing Derby (Canal 3)" "" "Cartridge.MD5" "13d8326bf5648db4dafce45d25e62ddd" "Cartridge.Name" "Atari Logo Demo 2 (PD)" "" "Cartridge.MD5" "13dfb095e519a555a5b60b7d9d7169f9" "Cartridge.Name" "Red Line Demo (PD)" "" "Cartridge.MD5" "140909d204abd6841c64cdad4d7765b4" "Cartridge.Name" "Moving Blue Ladder Demo (PD)" "" "Cartridge.MD5" "14163eb2a3ddd35576bd8527eae3b45e" "Cartridge.Name" "Multi-Color Demo 6 (Bob Colbert) (PD)" "" "Cartridge.MD5" "1423f560062c4f3c669d55891a2bcbe7" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-859" "Cartridge.Name" "MASH (1983) (CCE) [a]" "Cartridge.Note" "AKA M.A.S.H" "" "Cartridge.MD5" "1428029e762797069ad795ce7c6a1a93" "Cartridge.Name" "Thunderground (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "143918368f4f4dfff90999188c0197c9" "Cartridge.Name" "Unknown Title (bin00016 (200110)) (PD)" "" "Cartridge.MD5" "1442d1b35a6478fba22ae7dd1fcb5634" "Cartridge.Name" "Thrust (V0.2) (2000) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "148471144ccebd7f6aa9aa9215896533" "Cartridge.Manufacturer" "Parker Brothers - JWDA, Todd Marshall" "Cartridge.ModelNo" "PB5550" "Cartridge.Name" "Q-bert's Qubes (1984) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "149b543c917c180a1b02d33c12415206" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-857" "Cartridge.Name" "Superman (1983) (CCE)" "" "Cartridge.MD5" "14a56b493a8d9d10e94a3e100362e3a2" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Early Play-kernel (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "14b1e30982962c72f426e2e763eb4274" "Cartridge.Manufacturer" "Atari, Carol Shaw - Ralph Lauren" "Cartridge.Name" "Polo (1978) (Atari) (Prototype) (4K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "14c2548712099c220964d7f044c59fd9" "Cartridge.Manufacturer" "First Star Software, Alex Leavens, Shirley Ann Russell" "Cartridge.Name" "Boing! (1983) (First Star Software)" "Cartridge.Note" "AKA Bubbles, Soap Suds, The Emphysema Game" "Cartridge.Rarity" "Extremely Rare" "Display.Phosphor" "YES" "" "Cartridge.MD5" "14d365bbfaac3d20c6119591f57acca4" "Cartridge.Name" "Video Life (Unknown) (4K) (Hack)" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "14dbb3686dd31964332dc2ef0c55cad0" "Cartridge.Name" "Demo Image Series #15 - Three Marios (PAL) (Non-Interleave) (06-03-2003) (AD)" "" "Cartridge.MD5" "151c33a71b99e6bcffb34b43c6f0ec23" "Cartridge.Manufacturer" "Parker Brothers, Laura Nikolich" "Cartridge.Name" "Care Bears (1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "151fa3218d8d7600114eb5bcd79c85cb" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu" "Cartridge.ModelNo" "CX26104" "Cartridge.Name" "Big Bird's Egg Catch (05-02-1983) (Atari) (Prototype)" "Cartridge.Note" "Uses the Keypad Controller" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "" "Cartridge.MD5" "152c253478b009c275e18cd731b48561" "Cartridge.Name" "Quest (11-10-2002) (Chris Larkin)" "" "Cartridge.MD5" "153f40e335e5cb90f5ce02e54934ab62" "Cartridge.Manufacturer" "Absolute Entertainment, Alex DeMeo" "Cartridge.ModelNo" "EAZ-041-04I" "Cartridge.Name" "Title Match Pro Wrestling (1987) (Absolute) (PAL)" "" "Cartridge.MD5" "1542662f665d2ffaa77b4b897dd2e2af" "Cartridge.Name" "Starfield (V1.0) (2002) (MP)" "" "Cartridge.MD5" "155fa7f479dcba3b10b1494e236d6010" "Cartridge.Manufacturer" "Skyworks" "Cartridge.Name" "Tomcat (2002) (Skyworks) (PAL)" "Cartridge.Note" "AKA The F-14 Flight Simulator" "" "Cartridge.MD5" "157356f80c709ab675961d8b8b207e20" "Cartridge.Name" "Multi-Sprite Game V2.5 (Piero Cavina) (PD)" "" "Cartridge.MD5" "157bddb7192754a45372be196797f284" "Cartridge.Manufacturer" "Atari, Warren Robinett - Sears" "Cartridge.ModelNo" "CX2613, 49-75154" "Cartridge.Name" "Adventure (1980) (Atari)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "159e5cd6ccb968015f49aed5adbc91eb" "Cartridge.Manufacturer" "Justin J. Scott" "Cartridge.Name" "Yar's Defeat (2002) (Justin J. Scott) (Hack)" "Cartridge.Note" "Hack of Yars' Revenge" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "15b498199ed0ed28057bf0dbdce9b8d8" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Jammed (V0.2) (Demo) (2001) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "15bcd74f2f1f2a63e1aa93e90d2c0555" "Cartridge.Name" "Incoming (22-08-2002) (Ben Larson) (PD)" "" "Cartridge.MD5" "15bf2ef7583bfcbbba630847a1dc5539" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Jul 15) (2002) (Eric Eid) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "15c11ab6e4502b2010b18366133fc322" "Cartridge.Manufacturer" "Atari - Axlon, Tod Frye - Heuristica, Augustin Ortiz" "Cartridge.ModelNo" "CX26169" "Cartridge.Name" "Shooting Arcade (09-19-1989) (Atari) (Prototype)" "Cartridge.Note" "Uses the Light Gun Controller (left only)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "15dd21c2608e0d7d9f54c0d3f08cca1f" "Cartridge.Manufacturer" "Data Age, J. Ray Dettling" "Cartridge.ModelNo" "112-008" "Cartridge.Name" "Frankenstein's Monster (1983) (Data Age)" "" "Cartridge.MD5" "15fe28d0c8893be9223e8cb2d032e557" "Cartridge.Name" "Towering Inferno (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1619bc27632f9148d8480cd813aa74c3" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Steeple Chase (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "161ded4a85d3c78e44fffd40426f537f" "Cartridge.Name" "JtzBall (Alpha) (TJ)" "" "Cartridge.MD5" "163e7e757e2dc44469123ff0e5daec5e" "Cartridge.Name" "Many Blue Bars and Text Demo 2 (PD)" "" "Cartridge.MD5" "169d4c7bd3a4d09e184a3b993823d048" "Cartridge.Name" "Superman (Unknown) (PAL) [a]" "" "Cartridge.MD5" "16cb43492987d2f32b423817cdaaf7c4" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2602 - 99802, 6-99802, 49-75102" "Cartridge.Name" "Air-Sea Battle (1977) (Atari)" "Cartridge.Note" "AKA Target Fun (Anti-Aircraft)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "16cc6d1b4ddce51c767a1ba8e5ff196c" "Cartridge.Name" "Big - Move This Demo 2 (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "16e04823887c547dc24bc70dff693df4" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Tennis (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "16ee443c990215f61f7dd1e55a0d2256" "Cartridge.Manufacturer" "Spectravideo, David Lubar" "Cartridge.ModelNo" "SA-218, SA-218C" "Cartridge.Name" "Bumper Bash (1983) (Spectravideo) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Display.YStart" "54" "" "Cartridge.MD5" "16f494f20af5dc803bc35939ef924020" "Cartridge.Manufacturer" "Mark De Smet" "Cartridge.Name" "Video Simon (Mark De Smet)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "16fbb36a6124567405a235821e8f69ee" "Cartridge.Name" "Star Fire (28-11-2002) (MP)" "" "Cartridge.MD5" "170e7589a48739cfb9cc782cbb0fe25a" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Hal Finney - INTV" "Cartridge.ModelNo" "MT5666" "Cartridge.Name" "Astroblast (1982) (M Network) [fixed]" "Cartridge.Note" "Can also use left joystick" "Cartridge.Rarity" "Uncommon" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 55" "" "Cartridge.MD5" "171cd6b55267573e6a9c2921fb720794" "Cartridge.Manufacturer" "Kurt Howe" "Cartridge.Name" "Adventure 34 (Kurt Howe) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "1733772165d7b886a94e2b4ed0f74ccd" "Cartridge.Name" "Boring Journey Escape (Hack)" "Cartridge.Note" "Hack of Journey - Escape" "Cartridge.Rarity" "Hack" "Display.Height" "230" "" "Cartridge.MD5" "1738b2e3f25ab3eef3cecb95e1d0d957" "Cartridge.Name" "Hangman Monkey Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "17512d0c38f448712f49f36f9d185c4e" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (Release Candidate #1) (Retroactive)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "17515a4d0b7ea5029ffff7dfa8456671" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Multi-Sprite Demo V1.1 (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "176d3fba7d687f2b23158098e103c34a" "Cartridge.Manufacturer" "Zach Matley" "Cartridge.Name" "Combat AI (16-02-2003) (Zach Matley)" "Cartridge.Rarity" "Homebrew" "Display.YStart" "34" "" "Cartridge.MD5" "177504abd4260c4265e1338955e9fa47" "Cartridge.Manufacturer" "HCC Software" "Cartridge.Name" "Pitfall! (Steroids Hack)" "Cartridge.Note" "Hack of Pitfall! (Activision)" "" "Cartridge.MD5" "1782929e1c214b70fb6884f77c207a55" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-018, AX-018-04" "Cartridge.Name" "Pitfall! (1982) (Activision) (Prototype)" "Cartridge.Note" "Pitfall Harry's Jungle Adventure (Jungle Runner)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "17ba72433dd41383065d4aa6dedb3d91" "Cartridge.Name" "SCSIcide (09-06-2001) (Joe Grand)" "" "Cartridge.MD5" "17badbb3f54d1fc01ee68726882f26a6" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Hal Finney, Bruce Pedersen - INTV" "Cartridge.ModelNo" "MT5659" "Cartridge.Name" "Space Attack (1982) (M Network)" "" "Cartridge.MD5" "17bbe288c3855c235950fea91c9504e9" "Cartridge.Manufacturer" "Dismac" "Cartridge.Name" "Pega Ladrao (Dismac)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "17c0a63f9a680e7a61beba81692d9297" "Cartridge.Manufacturer" "U.S. Games Corporation - Western Technologies, Tom Sloper" "Cartridge.ModelNo" "VC2004" "Cartridge.Name" "Picnic (1983) (U.S. Games)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 45" "" "Cartridge.MD5" "17d000a2882f9fdaa8b4a391ad367f00" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2676" "Cartridge.Name" "Centipede (1983) (Atari) (PAL)" "" "Cartridge.MD5" "17ee158d15e4a34f57a837bc1ce2b0ce" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Kevin Osborn" "Cartridge.ModelNo" "CX2691, CX2691P" "Cartridge.Name" "Joust (1983) (Atari) (PAL) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "17ee23e5da931be82f733917adcb6386" "Cartridge.Manufacturer" "Salu, Dennis M. Kiss" "Cartridge.ModelNo" "460758" "Cartridge.Name" "Acid Drop (1992) (Salu) (PAL)" "Cartridge.Rarity" "Extremely Rare" "Display.YStart" "50" "Display.Height" "256" "" "Cartridge.MD5" "1802cc46b879b229272501998c5de04f" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu" "Cartridge.ModelNo" "CX26104" "Cartridge.Name" "Big Bird's Egg Catch (1983) (Atari)" "Cartridge.Note" "Uses Kids/Keypad Controllers" "Cartridge.Rarity" "Rare" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "183020a80848e06a1238a1ab74079d52" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (Amiga Mouse) (2002) (TJ) (PAL)" "Cartridge.Note" "Uses Amiga Mouse Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "AMIGAMOUSE" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1862fca4f98e66f363308b859b5863af" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "128-in-1 Junior Console (Chip 1 of 4) (1991) (Atari) (PAL)" "Cartridge.Note" "Actually contains only 16 games, not 32" "Cartridge.Type" "16IN1" "" "Cartridge.MD5" "18760f1f9ca5e18610115cf7b815b824" "Cartridge.Name" "Star Fire (23-10-2002) (MP)" "" "Cartridge.MD5" "18a970bea7ac4d29707c8d5cd559d03a" "Cartridge.Name" "Bridge (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "18b28b386abdadb3a700ac8fb68e639a" "Cartridge.Manufacturer" "Manuel Polik" "Cartridge.Name" "Gunfight 2600 (MP) (PAL)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "18bebbbd41c234f82b1717b1905e6027" "Cartridge.Name" "Space Instigators (Public Release) (02-01-2003) (CT)" "" "Cartridge.MD5" "18d26111cef66dff0c8af8cf0e117843" "Cartridge.Name" "Tunnel Demo (Cycling Colours 2) (29-03-2003) (AD)" "" "Cartridge.MD5" "18dc28bc22402f21e1c9b81344b3b8c5" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2684, CX2684P" "Cartridge.Name" "Galaxian (1983) (Atari) (PAL) [a1]" "" "Cartridge.MD5" "18ed63e3ce5bc3dd2d8bd188b807f1a2" "Cartridge.Name" "Stell-A-Sketch (Bob Colbert) (PD) [a1]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "18f299edb5ba709a64c80c8c9cec24f2" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83111" "Cartridge.Name" "Asteroid Fire (1983) (Home Vision) (PAL)" "Cartridge.Rarity" "Extremely Rare" "Display.YStart" "20" "" "Cartridge.MD5" "19098c46da0640f2b5763167dea6c716" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Laseresal 2002 (NTSC) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "191449e40b0c56411c70772706f79224" "Cartridge.Name" "Multi-Color Demo 2 (Bob Colbert) (PD)" "" "Cartridge.MD5" "19162393786098d50587827588198a86" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Flag Capture (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "191ac4eec767358ee3ec3756c120423a" "Cartridge.Name" "Checkers (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "192aa2e8c795c9e10a7913e5d41feb81" "Cartridge.Manufacturer" "Atari - GCC, Jaques Hugon, Seth Lipkin" "Cartridge.ModelNo" "CX26125" "Cartridge.Name" "Los Angeles 1984 Games (1984) (Atari) (Prototype) (PAL)" "Cartridge.Note" "AKA Track and Field (Uses Track & Field Controller)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "193f060553ba0a2a2676f91d9ec0c555" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX2636, CX2636P" "Cartridge.Name" "Video Checkers (1980) (Atari) (PAL)" "" "Cartridge.MD5" "199985cae1c0123ab1aef921daace8be" "Cartridge.Name" "Euchre (Release Candidate 2) (PAL) (01-10-2002) (Erik Eid)" "" "Cartridge.MD5" "199eb0b8dce1408f3f7d46411b715ca9" "Cartridge.Manufacturer" "Parker Brothers, David Lamkins, Laura Nikolich" "Cartridge.ModelNo" "PB5900" "Cartridge.Name" "Spider-Man (1982) (Parker Bros)" "" "Cartridge.MD5" "19a9d3f9fa1b1358fb53009444247aaf" "Cartridge.Name" "Blackjack (Unknown) (PAL) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "Display.YStart" "56" "" "Cartridge.MD5" "19abaf2144b6a7b281c4112cff154904" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.ModelNo" "CX2649, CX2649P" "Cartridge.Name" "Asteroids (1981) (Atari) (PAL) [a2]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "19d6956ff17a959c48fcd8f4706a848d" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "202" "Cartridge.Name" "Burning Desire (1982) (PlayAround)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "19d9b5f8428947eae6f8e97c7f33bf44" "Cartridge.Name" "Fortress (Dual Version) (20-04-2003) (CT)" "" "Cartridge.MD5" "19e739c2764a5ab9ed08f9095aa2af0b" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee" "Cartridge.ModelNo" "CX26117" "Cartridge.Name" "Obelix (1984) (Atari) (PAL)" "" "Cartridge.MD5" "19e761e53e5ec8e9f2fceea62715ca06" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "104" "Cartridge.Name" "Scuba Diver (1983) (Panda)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "1a23540d91f87584a04f184304a00648" "Cartridge.Name" "Race Demo (PD)" "" "Cartridge.MD5" "1a613ce60fc834d4970e1e674b9196b3" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83135" "Cartridge.Name" "Tanks War (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Tanks But No Tanks" "" "Cartridge.MD5" "1a624e236526c4c8f31175e9c89b2a22" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-007" "Cartridge.Name" "Space Raid (Rainbow Vision) (PAL) [a]" "Cartridge.Note" "AKA MegaMania" "" "Cartridge.MD5" "1a8204a2bcd793f539168773d9ad6230" "Cartridge.Manufacturer" "Atari, Rob Fulop - Sears" "Cartridge.ModelNo" "CX2638 - 49-75166" "Cartridge.Name" "Missile Command (1981) (Atari) [no initials]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1aa7344b563c597eecfbfcf8e7093c27" "Cartridge.Manufacturer" "David Marli" "Cartridge.Name" "Slot Invaders (David Marli) (Hack)" "Cartridge.Note" "Hack of Slot Machine" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "1b0f3d7af668eeea38ddd6182d8f48fb" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Cosmic Swarm (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "30" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1b1daaa9aa5cded3d633bfcbeb06479c" "Cartridge.Name" "Ship Demo (V 1502) (PD)" "" "Cartridge.MD5" "1b22a3d79ddd79335b69c94dd9b3e44e" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Moon Patrol (Tron)" "" "Cartridge.MD5" "1b4b06c2a14ed3ee73b7d0fd61b6aaf5" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype) [a]" "" "Cartridge.MD5" "1b8c3c0bfb815b2a1010bba95998b66e" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Frogs and Flies (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "1b8d35d93697450ea26ebf7ff17bd4d1" "Cartridge.Manufacturer" "Quelle - Otto Versand" "Cartridge.ModelNo" "176.764 9 - 781644" "Cartridge.Name" "Marineflieger (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Seahawk" "" "Cartridge.MD5" "1bb91bae919ddbd655fa25c54ea6f532" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-026" "Cartridge.Name" "Treasure Island (Suntek) (PAL)" "Cartridge.Note" "AKA Treasure Discovery" "" "Cartridge.MD5" "1bc2427ac9b032a52fe527c7b26ce22c" "Cartridge.Manufacturer" "Intellivision Productions - M Network - APh Technological Consulting, Bruce Pedersen, Larry Zwick" "Cartridge.ModelNo" "MT5860" "Cartridge.Name" "Sea Battle (1983) (M Network)" "Cartridge.Note" "High Seas" "" "Cartridge.MD5" "1bef389e3dd2d4ca4f2f60d42c932509" "Cartridge.Manufacturer" "Dimax - Sinmax" "Cartridge.ModelNo" "SM8001" "Cartridge.Name" "Space Robot (1983) (Dimax - Sinmax) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1bf503c724001b09be79c515ecfcbd03" "Cartridge.Name" "Bumper Bash (Unknown) (PAL)" "Display.YStart" "54" "" "Cartridge.MD5" "1c3f3133a3e5b023c77ecba94fd65995" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-830" "Cartridge.Name" "Planet Patrol (1983) (CCE) [a]" "" "Cartridge.MD5" "1c5796d277d9e4df3f6648f7012884c4" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "715.853 5" "Cartridge.Name" "Wachroboter jagt Jupy (Quelle) (PAL)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "1c6eb740d3c485766cade566abab8208" "Cartridge.Manufacturer" "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26110" "Cartridge.Name" "Crystal Castles (1984) (Atari)" "" "Cartridge.MD5" "1c85c0fc480bbd69dc301591b6ecb422" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Box (CCE)" "Cartridge.Note" "AKA RealSports Boxing" "" "Cartridge.MD5" "1c8c42d1aee5010b30e7f1992d69216e" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "205" "Cartridge.Name" "Gigolo (1982) (PlayAround)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1cad3b56cc0e6e858554e46d08952861" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Chopper Command (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "1cafa9f3f9a2fce4af6e4b85a2bbd254" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX2659" "Cartridge.Name" "Raiders of the Lost Ark (1982) (Atari) (PAL)" "Cartridge.Note" "Console ports are swapped" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "1cca2197d95c5a41f2add49a13738055" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2664 - 6-99818" "Cartridge.Name" "Brain Games (1978) (Atari)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "1cf59fc7b11cdbcefe931e41641772f6" "Cartridge.Manufacturer" "Sega" "Cartridge.ModelNo" "005-01" "Cartridge.Name" "Buck Rogers - Planet of Zoom (1983) (Sega)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1d1d2603ec139867c1d1f5ddf83093f1" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2602 - 99802, 6-99802, 49-75102" "Cartridge.Name" "Air-Sea Battle (1977) (Atari) (4K)" "Cartridge.Note" "AKA Target Fun (Anti-Aircraft)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "1d284d6a3f850bafb25635a12b316f3d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "H.E.R.O. (CCE)" "" "Cartridge.MD5" "1d2a28eb8c95da0d6d6b18294211839f" "Cartridge.Name" "Fishing Derby (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "1d4e0a034ad1275bc4d75165ae236105" "Cartridge.Manufacturer" "20th Century Fox Video Games, Mark Klein" "Cartridge.ModelNo" "11034" "Cartridge.Name" "Pick Up (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1d5eac85e67b8cff1377c8dba1136929" "Cartridge.Name" "Chronocolor Donkey Kong Sideways (PD)" "" "Cartridge.MD5" "1d6ed6fe9dfbde32708e8353548cbb80" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Super Challenge Baseball (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "1da2da7974d2ca73a823523f82f517b3" "Cartridge.Manufacturer" "Spectravision - Spectravideo - Sirius Software, David Lubar" "Cartridge.ModelNo" "SA-206" "Cartridge.Name" "Challenge of.... Nexar, The (1982) (Spectravision) (PAL)" "" "Cartridge.MD5" "1db3bc4601f22cf43be7ce015d74f59a" "Cartridge.Name" "Ship Demo (V 10) (PD)" "" "Cartridge.MD5" "1e060a8025512ad2127e3da11e212ccc" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "13" "Cartridge.Name" "Sweat! - The Decathlon Game (3 of 3) (1983) (Arcadia) (Prototype)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Cartridge.Rarity" "Prototype" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "1e0ef01e330e5b91387f75f700ccaf8f" "Cartridge.Manufacturer" "Quelle - Otto Versand" "Cartridge.ModelNo" "686.561 2 - 781627" "Cartridge.Name" "Mein Weg (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Challenge" "" "Cartridge.MD5" "1e1290ea102e12d7ac52820961457e2b" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart" "Cartridge.ModelNo" "PB5540" "Cartridge.Name" "Star Wars - The Arcade Game (12-15-1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1e1817d9cbcc3ba75043b7db4e6c228f" "Cartridge.Name" "Star Fire (07-10-2002) (MP)" "" "Cartridge.MD5" "1e272d09c0e55f5ef14fcb76a735f6d7" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Slot Machine (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "1e587ca91518a47753a28217cd4fd586" "Cartridge.Manufacturer" "Telesys, Jim Rupp, Jack Woodman" "Cartridge.ModelNo" "1001" "Cartridge.Name" "Coco Nuts (1982) (Telesys)" "" "Cartridge.MD5" "1e750000af77cc76232f4d040f4ab060" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Raft Rider (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "1e85f8bccb4b866d4daa9fcf89306474" "Cartridge.Manufacturer" "Atari, Lou Harp" "Cartridge.ModelNo" "CX26122" "Cartridge.Name" "Sinistar (02-13-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1e89f722494608d6ea15a00d99f81337" "Cartridge.Name" "River Raid (Unknown) (PAL)" "Display.Format" "NTSC50" "" "Cartridge.MD5" "1ea1abcd2d3d3d628f59a99a9d41b13b" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Stampede (Jone Yuan) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "1ea980574416bfd504f62575ba524005" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2675" "Cartridge.Name" "Ms. Pac-Man (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1ec57bbd27bdbd08b60c391c4895c1cf" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX26119" "Cartridge.Name" "Saboteur (09-02-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1ec5bef77b91e59313cba205f15b06d7" "Cartridge.Name" "Overhead Adventure Demo 1 (PD)" "Display.YStart" "60" "" "Cartridge.MD5" "1ede4f365ce1386d58f121b15a775e24" "Cartridge.Manufacturer" "Parker Brothers, Dave Hampton, Tom Sloper" "Cartridge.ModelNo" "931517" "Cartridge.Name" "Q-bert (1983) (Parker Bros) (PAL) [a]" "" "Cartridge.MD5" "1ee2cfc7d0333b96bd11f7f3ec8ce8bc" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (4 of 4) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "1ee9c1ba95cef2cf987d63f176c54ac3" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2675, CX2675P" "Cartridge.Name" "Ms. Pac-Man (1983) (Atari) (PAL)" "" "Cartridge.MD5" "1ef04e7e508296a8d9eb61cc7dae2e5d" "Cartridge.Manufacturer" "SOLID Corp. (D. Scott Williamson)" "Cartridge.ModelNo" "CX2655-069" "Cartridge.Name" "Star Castle 2600 (SolidCorp) [069]" "Cartridge.Note" "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1f21666b8f78b65051b7a609f1d48608" "Cartridge.Manufacturer" "K-Tel Vision" "Cartridge.Name" "Vulture Attack (1982) (K-Tel Vision)" "Cartridge.Note" "AKA Condor Attack" "" "Cartridge.MD5" "1f2ae0c70a04c980c838c2cdc412cf45" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2698" "Cartridge.Name" "Rubik's Cube (1984) (Atari)" "Cartridge.Note" "AKA Atari Video Cube" "" "Cartridge.MD5" "1f349dd41c3f93c4214e5e308dccb056" "Cartridge.Name" "Virtual Pet Demo 2 (CRACKERS) (PD)" "" "Cartridge.MD5" "1f40eefc7447336ae6cd8ffa5eb325be" "Cartridge.Manufacturer" "Atari, Chris Crawford" "Cartridge.Name" "Wizard (1980) (Atari) (Prototype) (4K) [a]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1f562b89d081e36d58e6fc943512ec05" "Cartridge.Name" "Hangman Man Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "1f5a2927a0b2faf87540b01d9d7d7fd1" "Cartridge.Manufacturer" "Pet Boat" "Cartridge.Name" "Tennis (Pet Boat) (PAL)" "" "Cartridge.MD5" "1f60e48ad98b659a05ce0c1a8e999ad9" "Cartridge.Name" "Mondo Pong V2 (Piero Cavina) (PD)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "1f773a94d919b2a3c647172bbb97f6b4" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday" "Cartridge.ModelNo" "CX26115" "Cartridge.Name" "Dumbo's Flying Circus (07-11-1983) (Atari) (Prototype) (PAL)" "Cartridge.Note" "AKA Dumbo Flies Home" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1fa58679d4a39052bd9db059e8cda4ad" "Cartridge.Manufacturer" "Imagic, Dan Oliver" "Cartridge.ModelNo" "720118-1A, 03208" "Cartridge.Name" "Laser Gates (1983) (Imagic)" "Cartridge.Note" "AKA Innerspace" "" "Cartridge.MD5" "1fa7a42c2c7d6b7a0c6a05d38c7508f4" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (09-04-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "1fa86282403fa35d103ab88a9d603c31" "Cartridge.Manufacturer" "SpiceWare - Darrell Spice Jr." "Cartridge.Name" "Stay Frosty (SpiceWare) (PAL60)" "Cartridge.Note" "Part of Stella's Stocking 2007 Xmas compilation" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "1fab68fd67fe5a86b2c0a9227a59bb95" "Cartridge.Manufacturer" "20th Century Fox Video Games - Videa, Lee Actor" "Cartridge.Name" "Lasercade (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "200309c8fba0f248c13751ed4fc69bab" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 1 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "2008c76deba5953201ef75a09b2ff7dc" "Cartridge.Name" "Fortress (21-04-2003) (CT)" "" "Cartridge.MD5" "200a9d2a7cb4441ce4f002df6aa47e38" "Cartridge.Name" "Doomzerk (PD) (Hack)" "Cartridge.Note" "Hack of Berzerk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2016726db38ad6a68b4c48ba6fe51557" "Cartridge.Manufacturer" "Piero Cavina, Erik Mooney" "Cartridge.Name" "INV 2 (Piero Cavina, Erik Mooney)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "203049f4d8290bb4521cc4402415e737" "Cartridge.Manufacturer" "Tigervision, Robert H. O'Neil - Teldec" "Cartridge.ModelNo" "7-007 - 3.60005 VG" "Cartridge.Name" "Polaris (1983) (Tigervision) (PAL)" "" "Cartridge.MD5" "203abb713c00b0884206dcc656caa48f" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "720114-1A, 03207, IZ-001-04" "Cartridge.Name" "Moonsweeper (1983) (Imagic)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "203b1efc6101d4b9d83bb6cc1c71f67f" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "685.996 1" "Cartridge.Name" "Teller-Jonglieren! (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Dishaster" "Display.Phosphor" "YES" "" "Cartridge.MD5" "205070b6a0d454961dd9196a8e81d877" "Cartridge.Name" "Hangman Monkey Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2091af29b4e7b86914d79d9aaa4cbd20" "Cartridge.Manufacturer" "CBS Electronics - Woodside Design Associates, Harley H. Puthuff Jr." "Cartridge.ModelNo" "4L1802" "Cartridge.Name" "Donkey Kong Junior (1983) (CBS Electronics) (PAL)" "Display.Height" "251" "" "Cartridge.MD5" "20ae62fb69c6cc6e8098cca8cd080487" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Tennis (Zirok)" "" "Cartridge.MD5" "20d4457ba22517253fcb62967af11b37" "Cartridge.Manufacturer" "Atari, Eric Manghise, Mimi Nyden, Joseph Tung" "Cartridge.ModelNo" "CX2640" "Cartridge.Name" "RealSports Baseball (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "20dca534b997bf607d658e77fbb3c0ee" "Cartridge.Manufacturer" "Mythicon, Bill Bryner, Bruce de Graaf" "Cartridge.ModelNo" "MA1002" "Cartridge.Name" "Fire Fly (1983) (Mythicon)" "" "Cartridge.MD5" "20edcc3aa6c189259fa7e2f044a99c49" "Cartridge.Manufacturer" "Spectravision - Spectravideo" "Cartridge.ModelNo" "SA-201" "Cartridge.Name" "Gangster Alley (1982) (Spectravision)" "" "Cartridge.MD5" "211774f4c5739042618be8ff67351177" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker" "Cartridge.ModelNo" "CX2684" "Cartridge.Name" "Galaxian (1983) (Atari)" "" "Cartridge.MD5" "211f76dff0b7dad3f6fcac9d938ee61a" "Cartridge.Manufacturer" "JSK" "Cartridge.Name" "Custer's Viagra (JSK) (Hack) [a]" "Cartridge.Note" "Hack of Custer's Revenge" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "211fbbdbbca1102dc5b43dc8157c09b3" "Cartridge.Manufacturer" "Apollo" "Cartridge.ModelNo" "AP-2009" "Cartridge.Name" "Final Approach (1982) (Apollo)" "" "Cartridge.MD5" "2124cf92978c46684b6c39ccc2e33713" "Cartridge.Name" "Sea Monster (Unknown) (PAL)" "" "Cartridge.MD5" "21299c8c3ac1d54f8289d88702a738fd" "Cartridge.Manufacturer" "K-Tel Vision" "Cartridge.Name" "Spider Maze (1982) (K-Tel Vision)" "Cartridge.Note" "AKA Spider Kong" "Display.Height" "220" "" "Cartridge.MD5" "212d0b200ed8b45d8795ad899734d7d7" "Cartridge.Manufacturer" "Atari, Richard Maurer, Christopher H. Omarzu - Coca Cola" "Cartridge.Name" "Pepsi Invaders (1983) (Atari)" "" "Cartridge.MD5" "213e5e82ecb42af237cfed8612c128ac" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC006" "Cartridge.Name" "Forest (1983) (Sancho) (PAL)" "Display.Height" "256" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2162266b906c939b35c84ff9a0f50ad1" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2664, CX2664P" "Cartridge.Name" "Brain Games (1978) (Atari) (PAL) (4K)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "2179dfd7edee76efafe698c1bc763735" "Cartridge.Name" "Yellow Submarine (Cody Pittman) (PD)" "" "Cartridge.MD5" "218b76f5a4142dc2ea9051a768583d70" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2684, CX2684P" "Cartridge.Name" "Galaxian (1983) (Atari) (PAL) [a2]" "" "Cartridge.MD5" "218c0fe53dfaaa37f3c823f66eafd3fc" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2624, CX2624P" "Cartridge.Name" "Basketball (1978) (Atari) (PAL)" "Cartridge.Note" "Console ports are swapped" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "21a96301bb0df27fde2e7eefa49e0397" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1003" "Cartridge.Name" "Sssnake (1982) (Data Age)" "" "Cartridge.MD5" "21b09c40295c2d7074a83ae040f22edf" "Cartridge.Name" "Marble Craze (V0.90) (Easy Version) (Paul Slocum)" "Display.YStart" "30" "" "Cartridge.MD5" "21d2c435bcccde7792d82844b3cf60f4" "Cartridge.Manufacturer" "Atari - GCC, Doug Macrae" "Cartridge.ModelNo" "CX2677, CX2677P" "Cartridge.Name" "Dig Dug (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "21d7334e406c2407e69dbddd7cec3583" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-011" "Cartridge.Name" "Stampede (1981) (Activision)" "" "Cartridge.MD5" "2228c67d25e507603d4873d3934f0757" "Cartridge.Name" "Fu Kung! (V0.10) (28-01-2003) (AD)" "" "Cartridge.MD5" "22319be7a640af5314ec3c482cceb676" "Cartridge.Name" "Joustpong (05-07-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "2240655247d6de1c585564004a853ab7" "Cartridge.Name" "Fu Kung! (V0.17) (07-02-2003) (AD)" "" "Cartridge.MD5" "225522777dc7155627808bde0c1d0ef0" "Cartridge.Name" "This Planet Sucks Demo 1 (Greg Troutman) (PD)" "Cartridge.Rarity" "New Release" "Display.YStart" "36" "" "Cartridge.MD5" "22675cacd9b71dea21800cbf8597f000" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX2605, CX2605P" "Cartridge.Name" "Outlaw (1978) (Atari) (PAL)" "" "Cartridge.MD5" "227532d82505c3c185a878273c285d5f" "Cartridge.Name" "Hangman Man Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "22abbdcb094d014388d529352abe9b4b" "Cartridge.Manufacturer" "Apollo" "Cartridge.ModelNo" "AP-2012" "Cartridge.Name" "Squoosh (1983) (Apollo) (Prototype) [a]" "Cartridge.Note" "AKA Vat's Incredible!, The Grape Escape" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "22b22c4ce240303012e8a9596ae8d189" "Cartridge.Name" "Skeleton+ (03-05-2003) (Eric Ball) (PAL)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "22f6b40fc82110d68e50a1208ae0bb97" "Cartridge.Name" "Purple Bar Demo (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "2319922df4d0c820b3e5f15faa870cc3" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein" "Cartridge.ModelNo" "CX2681, CX2681P" "Cartridge.Name" "Battlezone (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "2327456f86d7e0deda94758c518d05b3" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Mr. Postman (Digitel)" "" "Cartridge.MD5" "2351d26d0bfdee3095bec9c05cbcf7b0" "Cartridge.Name" "Warring Worms (19-01-2002) (Billy Eno)" "" "Cartridge.MD5" "2353725ec98e0f0073462109e886efd7" "Cartridge.Manufacturer" "Champ Games" "Cartridge.ModelNo" "CG-03-P" "Cartridge.Name" "Scramble (PAL60)" "Cartridge.Note" "Compatible with Genesis controller" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "235436ab0832370e73677c9c6f0c8b06" "Cartridge.Name" "Beast Invaders (Double Shot) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2365e1534d67f94d8670394ab99150ce" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (Atari Mouse) (2002) (TJ)" "Cartridge.Note" "Uses Atari ST Mouse Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "ATARIMOUSE" "Display.Phosphor" "YES" "" "Cartridge.MD5" "23d445ea19a18fb78d5035878d9fb649" "Cartridge.Manufacturer" "CBS Electronics - JWDA, Sylvia Day, Todd Marshall, Henry Will IV" "Cartridge.ModelNo" "4L1818, 4L1819, 4L1820, 4L1821" "Cartridge.Name" "Mouse Trap (1983) (CBS Electronics) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "23e4ca038aba11982e1694559f3be10f" "Cartridge.Name" "Big Dig (V3) (20-10-2002) (CT)" "" "Cartridge.MD5" "23fad5a125bcd4463701c8ad8a0043a9" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-840" "Cartridge.Name" "Stone Age (1983) (CCE)" "Cartridge.Note" "Uses the Joystick Controllers (swapped)" "Console.LeftDifficulty" "A" "Console.RightDifficulty" "A" "Console.SwapPorts" "YES" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "240bfbac5163af4df5ae713985386f92" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-022" "Cartridge.Name" "Seaquest (1983) (Activision)" "" "Cartridge.MD5" "2432f33fd278dea5fe6ae94073627fcc" "Cartridge.Manufacturer" "CBS Electronics, Tom DiDomenico" "Cartridge.ModelNo" "4L2477, 4L2482, 4L2485, 4L4171" "Cartridge.Name" "Blueprint (1983) (CBS Electronics) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "24385ba7f5109fbe76aadc0a375de573" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Xevious (CCE)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2447e17a4e18e6b609de498fe4ab52ba" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Futebol (CCE)" "Cartridge.Note" "AKA RealSports Soccer" "Display.Phosphor" "YES" "" "Cartridge.MD5" "244c6de27faff527886fc7699a41c3be" "Cartridge.Name" "Matt Demo (PD)" "" "Cartridge.MD5" "2450dfa1df70d12b60683185775efed8" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 7 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "24544ee5d76f579992d9522e9b238955" "Cartridge.Manufacturer" "Carrere Video - Western Technologies, Tom Sloper - Teldec - Prism" "Cartridge.ModelNo" "USC2004" "Cartridge.Name" "Picnic (1983) (Carrere Video) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 45" "" "Cartridge.MD5" "245f07c8603077a0caf5f83ee6cf8b43" "Cartridge.Manufacturer" "Home Vision - Thomas Jentzsch" "Cartridge.Name" "Parachute (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.Height" "240" "" "Cartridge.MD5" "24759be31e8fe55d2829fd86bdf3181f" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Worst Nightmare... (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "247fa1a29ad90e64069ee13d96fea6d6" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-867" "Cartridge.Name" "Radar (1983) (CCE)" "Cartridge.Note" "AKA Exocet" "" "Cartridge.MD5" "2496d404bfc561a40a80bea6a69695c3" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1007" "Cartridge.Name" "Jungle Hunt (1983) (CCE) [a]" "" "Cartridge.MD5" "24ad538291eb5f5cac4b9998f3b851c3" "Cartridge.Name" "Gunfight 2600 - This time it's your decission! (2001) (MP)" "" "Cartridge.MD5" "24aff972d58990f9b88a6d787c796f1e" "Cartridge.Manufacturer" "CBS Electronics" "Cartridge.ModelNo" "4L1767, 4L1768, 4L1769, 4L1770" "Cartridge.Name" "Smurf (1982) (CBS Electronics) (PAL) [a]" "" "Cartridge.MD5" "24b5f4bbdb853eca38ea0cae2dfe73a1" "Cartridge.Name" "Home Run (Unknown) (PAL) (4K)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "24b9adac1b4f85b0bac9bf9b9e180906" "Cartridge.Manufacturer" "Angelino" "Cartridge.Name" "Space 2002 (Angelino) (Hack)" "Cartridge.Note" "Hack of Space Jockey" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "24d018c4a6de7e5bd19a36f2b879b335" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-021" "Cartridge.Name" "Spider Fighter (1983) (Activision)" "" "Cartridge.MD5" "24d9a55d8f0633e886a1b33ee1e0e797" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Dragon Defender (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.YStart" "15" "Display.Height" "240" "Display.Phosphor" "YES" "" "Cartridge.MD5" "24df052902aa9de21c2b2525eb84a255" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "720000-100, 720100-1B, IA3000, IA3000C" "Cartridge.Name" "Trick Shot (1982) (Imagic)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "24fbf8250a71611e40ef18552e61b009" "Cartridge.Name" "Movable Grid Demo (PD)" "" "Cartridge.MD5" "2516f4f4b811ede4ecf6fbeb5d54a299" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "701.134 9" "Cartridge.Name" "Schiessbude (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Carnival" "" "Cartridge.MD5" "2517827950fee41a3b9de60275c8aa6a" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fishing (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Fishing Derby" "" "Cartridge.MD5" "25265d0e7f88b3026003809f25ee025e" "Cartridge.Manufacturer" "Atari - GCC, Ava-Robin Cohen" "Cartridge.ModelNo" "CX26123" "Cartridge.Name" "Jr. Pac-Man (1984) (Atari) [a]" "" "Cartridge.MD5" "25472dfdeef6a42581a231d631d6b04d" "Cartridge.Name" "Gunfight 2600 - Design thoughts (MP)" "" "Cartridge.MD5" "25710bde8fa181b0c5cf0846b983bec1" "Cartridge.Name" "Demo Image Series #15 - Three Marios (NTSC) (06-03-2003) (AD)" "" "Cartridge.MD5" "257bc3b72a6b5db3fd0d47619125b387" "Cartridge.Manufacturer" "CBS Electronics" "Cartridge.ModelNo" "4L 2737 0000" "Cartridge.Name" "Omega Race (1983) (CBS Electronics) [a]" "Cartridge.Note" "Set right difficulty to 'A' for BoosterGrip in both ports" "Controller.Left" "BOOSTERGRIP" "Controller.Right" "BOOSTERGRIP" "" "Cartridge.MD5" "25a21c47afe925a3ca0806876a2b4f3f" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "685.640 5" "Cartridge.Name" "Der kleine Baer (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Frostbite" "" "Cartridge.MD5" "25b52bf8dd215bcbd59c9abdb55c44f8" "Cartridge.Manufacturer" "Atari - GCC, Betty Ryan Tylko, Doug Macrae" "Cartridge.ModelNo" "CX2694, CX2694P" "Cartridge.Name" "Pole Position (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "25b6dc012cdba63704ea9535c6987beb" "Cartridge.Manufacturer" "Avalon Hill, Jean Baer, Bill Hood" "Cartridge.ModelNo" "5004002" "Cartridge.Name" "Shuttle Orbiter (1983) (Avalon Hill)" "" "Cartridge.MD5" "25bb080457351be724aac8a02021aa92" "Cartridge.Manufacturer" "CBS Electronics" "Cartridge.ModelNo" "4L1784, 4L1786, 4L1787, 4L2277" "Cartridge.Name" "Zaxxon (1983) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "25d4be3309b89583c6b39d9f93bf654f" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AX-015, AX-015-04" "Cartridge.Name" "Chopper Command (1982) (Activision) (16K)" "" "Cartridge.MD5" "25e73efb9a6edf119114718bd2f646ba" "Cartridge.Manufacturer" "Atari, Suki Lee" "Cartridge.ModelNo" "CX26113" "Cartridge.Name" "Miss Piggy's Wedding (1983) (Atari) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "Display.YStart" "24" "" "Cartridge.MD5" "25f2e760cd7f56b88aac88d63757d41b" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAG-002, EAG-002-04I, PAG-002 - 711 002-715" "Cartridge.Name" "Boxing (1980) (Activision) (PAL)" "" "Cartridge.MD5" "25f879ff678130fea615ac418e7943f1" "Cartridge.Manufacturer" "Activision, Garry Kitchen" "Cartridge.ModelNo" "EAX-025" "Cartridge.Name" "Keystone Kapers (1983) (Activision) (SECAM)" "Display.Format" "SECAM" "" "Cartridge.MD5" "25f9cf703575c5d63048c222f5463758" "Cartridge.Name" "Multi-Sprite Demo 1 (PD)" "" "Cartridge.MD5" "260c787e8925bf3649c8aeae5b97dcc0" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Hell Driver (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion, joystick ports swapped" "Cartridge.Rarity" "Homebrew" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "262ccb882ff617d9b4b51f24aee02cbe" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26154, CX26154P" "Cartridge.Name" "Super Football (1988) (Atari) (PAL)" "" "Cartridge.MD5" "265a85f66544eaf95fda06c3d9e48abf" "Cartridge.Name" "Tunnel Demo (Cycling Colours) (29-03-2003) (AD)" "" "Cartridge.MD5" "265c74a956500bd31efd24adc6d5ccf6" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-026, AX-026-04" "Cartridge.Name" "Enduro (1983) (Activision) (8K)" "" "Cartridge.MD5" "2683d29a282dd059535ac3bb250f540d" "Cartridge.Name" "Space Treat (12-01-2003) (Fabrizio Zavagli)" "" "Cartridge.MD5" "268f46038e29301568fa9e443e16e960" "Cartridge.Manufacturer" "Atarius Maximum" "Cartridge.Name" "Pitfall Unlimited (Atarius Maximus) (Hack)" "Cartridge.Note" "Hack of Pitfall" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "26bc2bdf447a17376aea7ef187ff6e44" "Cartridge.Name" "Amanda Invaders (PD)" "" "Cartridge.MD5" "26f4f8b098609164effef7809e0121e1" "Cartridge.Name" "Oystron (V2.7) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "270229c6d5578446e6a588492e4e5910" "Cartridge.Name" "Space Invaders 2 (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "271bfd5dc2673d382019f1fb6cab9332" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (Preview) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "273ce50db5a0d6da7ea827a54f44dee9" "Cartridge.Name" "Island Flyer Demo (PD)" "" "Cartridge.MD5" "274d17ccd825ef9c728d68394b4569d2" "Cartridge.Manufacturer" "Playaround - J.H.M." "Cartridge.ModelNo" "202" "Cartridge.Name" "Bachelorette Party (1982) (Playaround)" "Cartridge.Note" "AKA Bachelor Party, Uses the paddle controllers" "Cartridge.Rarity" "Extremely Rare" "Controller.Left" "PADDLES_IAXIS" "Controller.MouseAxis" "AUTO 65" "Display.YStart" "22" "Display.Height" "222" "Display.Phosphor" "YES" "" "Cartridge.MD5" "277c7281ac945b8331e2e6fcad560c11" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (2 of 3) (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "277cca62014fceebb46c549bac25a2e3" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-002, CAG-002, AG-002-04" "Cartridge.Name" "Boxing (1980) (Activision) (4K)" "" "Cartridge.MD5" "277fa4b9a6bb7a8dcea2c5f38a4c25f0" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Robert Zdybel" "Cartridge.ModelNo" "CX2668" "Cartridge.Name" "RealSports Football (1982) (Atari) (Prototype)" "Cartridge.Note" "AKA Football II" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "278155fc9956e9b6ef2359eb238f7c7f" "Cartridge.Name" "Donkey Kong Junior (Unknown) (Hack)" "Cartridge.Note" "Hack of Donkey Kong Junior" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2783006ee6519f15cbc96adae031c9a9" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Night Stalker (1989) (Telegames) (PAL) [a]" "Cartridge.Note" "AKA Dark Cavern" "" "Cartridge.MD5" "278531cc31915747018d22145823d2c9" "Cartridge.Name" "Defender MegaDrive (PAL) (Genesis)" "Cartridge.Note" "Genesis controller (C is smartbomb)" "Cartridge.Rarity" "Hack of Defender" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "278f14887d601b5e5b620f1870bc09f6" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "SWOOPS! (v0.96) (TJ)" "Cartridge.Note" "Uses the Joystick (L) and Paddle (R) Controllers" "Cartridge.Rarity" "Homebrew" "Controller.Right" "PADDLES" "Display.YStart" "28" "" "Cartridge.MD5" "27c4c2af4b46394bb98638af8e0f6e9d" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26109" "Cartridge.Name" "Sorcerer's Apprentice (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "27c6a2ca16ad7d814626ceea62fa8fb4" "Cartridge.Manufacturer" "Parker Brothers, Mark Lesser" "Cartridge.ModelNo" "PB5590" "Cartridge.Name" "Frogger II (1984) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "27f9e2e1b92af9dc17c6155605c38e49" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Nightmare (CCE)" "" "Cartridge.MD5" "2808dc745ff4321dc5c8122abef6711f" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.11) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "28148a52b1955ce12c7a74d3a3e620a4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Freeway (CCE) (4K)" "" "Cartridge.MD5" "281ff9bd0470643853de5cbd6d9e17f5" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Cubis (EM) (1997) (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "2823364702595feea24a3fbee138a243" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG206" "Cartridge.Name" "Bobby Is Going Home (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA Bobby geht Heim" "Cartridge.Rarity" "Rare" "Display.YStart" "42" "" "Cartridge.MD5" "2825f4d068feba6973e61c84649489fe" "Cartridge.Name" "Boom Bang (Unknown) (PAL)" "Cartridge.Note" "AKA Crackpots" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "282a77841cb3d33af5b56151acba770e" "Cartridge.Manufacturer" "Otto Versand" "Cartridge.ModelNo" "311388" "Cartridge.Name" "Black Hole (1983) (Otto Versand) (PAL)" "Cartridge.Note" "AKA Cosmic Ark (Double-Game Package)" "" "Cartridge.MD5" "283dee88f295834c4c077d788f151125" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.11) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "284ca61b2407bdba3938048b0a559015" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2695" "Cartridge.Name" "Xevious (05-25-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2854e5dfb84173fafc5bf485c3e69d5a" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.ModelNo" "C 3004" "Cartridge.Name" "Moon Patrol (Canal 3)" "" "Cartridge.MD5" "2880c6b59bd54b153174676e465167c7" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Donkey Kong Jr. (Tron)" "Cartridge.Note" "AKA Donkey Kong Junior" "" "Cartridge.MD5" "28a2bea8f84936cb2e063f857414cda0" "Cartridge.Manufacturer" "Thiago Paiva" "Cartridge.Name" "Mega Mania Raid (1999) (Thiago Paiva) (Hack)" "Cartridge.Note" "Hack of Megamania" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "28a4cd87fb9de4ee91693a38611cb53c" "Cartridge.Name" "Skeleton (V1.1) (NTSC) (24-10-2002) (Eric Ball)" "" "Cartridge.MD5" "28d5df3ed036ed63d33a31d0d8b85c47" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG204" "Cartridge.Name" "Open, Sesame! (1983) (BitCorp) (PAL) [a]" "Cartridge.Note" "AKA I Want My Mommy" "Display.YStart" "38" "Display.Height" "256" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2903896d88a341511586d69fcfc20f7d" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-014, AX-014-04" "Cartridge.Name" "Grand Prix (1982) (Activision)" "" "Cartridge.MD5" "291bcdb05f2b37cdf9452d2bf08e0321" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "32 in 1 Game Cartridge (1988) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "Cartridge.Type" "32IN1" "" "Cartridge.MD5" "291cc37604bc899e8e065c30153fc4b9" "Cartridge.Manufacturer" "Activision, Carol Shaw" "Cartridge.ModelNo" "AX-020, AX-020-04" "Cartridge.Name" "River Raid (1982) (Activision) (16K)" "" "Cartridge.MD5" "291dd47588b9158beebe4accc3a093a6" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "32 in 1 Console ROM (02-10-1989) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "Cartridge.Type" "32IN1" "" "Cartridge.MD5" "292a0bb975b2587f9ac784c960e1b453" "Cartridge.Name" "Qb (05-02-2001) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "292f2446a0325b7b423e88a2ebfeb5a0" "Cartridge.Name" "Cube Conquest (Non Interlaced) (Billy Eno) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "29396db58406084e416032c372734a3e" "Cartridge.Name" "Gunfight 2600 - Fixed Beta Release! (2001) (MP)" "" "Cartridge.MD5" "2942680c47beb9bf713a910706ffabfe" "Cartridge.Name" "Blue Line Demo (PD)" "" "Cartridge.MD5" "294762000e853b4319f9991c1ced5dfc" "Cartridge.Name" "T.F. Space Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "295f3679bdf91ca5e37da3f787b29997" "Cartridge.Name" "Exorcise (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "29630a20d356fb58685b150bfa8f00c3" "Cartridge.Manufacturer" "M Network, Kevin Miller" "Cartridge.ModelNo" "MT5687" "Cartridge.Name" "International Soccer (1982) (Mattel) [a]" "" "Cartridge.MD5" "297236cb9156be35679f83c4e38ee169" "Cartridge.Manufacturer" "Exus Corporation" "Cartridge.Name" "Video Reflex (1983) (Exus) [no roman numbers]" "Cartridge.Note" "AKA Foot Craz (no roman numbers)" "" "Cartridge.MD5" "297c405afd01f3ac48cdb67b00d273fe" "Cartridge.Manufacturer" "Atari - GCC, Ava-Robin Cohen" "Cartridge.ModelNo" "CX26123, CX26123P" "Cartridge.Name" "Jr. Pac-Man (1986) (Atari) (PAL)" "" "Cartridge.MD5" "2982e655dffc89d218a0a3072cfc6811" "Cartridge.Name" "Mini Golf 812631 (Hack)" "Cartridge.Note" "Hack of Miniature Golf" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "298387b0637173d2002770a649b4fbca" "Cartridge.Name" "S.I.PLIX 2 (Hack) [a]" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "29843f43b81f3736bf35c00b1bb88fb2" "Cartridge.Manufacturer" "Gray Games & AtariAge" "Cartridge.Name" "E.T. Book Cart (NTSC)" "Cartridge.Note" "Charles F. Gray & Michael Rideout" "Display.YStart" "15" "Display.Height" "240" "Display.Phosphor" "YES" "Display.PPBlend" "55" "" "Cartridge.MD5" "29949f893ef6cb9e8ecb368b9e99eee4" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Alpha) (NTSC) (31-08-2002) (Erik Eid)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "29dfa26b7988af9984d617708e4fc6e2" "Cartridge.Name" "Boulderdash Demo (05-04-2003) (AD)" "" "Cartridge.MD5" "2a0ba55e56e7a596146fa729acf0e109" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-019" "Cartridge.Name" "Sky Jinks (1982) (Activision)" "" "Cartridge.MD5" "2a10053fd08664c7cfbbb104386ed77f" "Cartridge.Name" "Alpha Demo - The Beta Demo (2000) (MP)" "" "Cartridge.MD5" "2a1b454a5c3832b0240111e7fd73de8a" "Cartridge.Manufacturer" "Tigervision, Bill Hogue" "Cartridge.ModelNo" "7-011" "Cartridge.Name" "Miner 2049er Volume II (1983) (Tigervision)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2a2f46b3f4000495239cbdad70f17c59" "Cartridge.Manufacturer" "CommaVid, John Bronstein - Ariola" "Cartridge.ModelNo" "CM-003 - 712 003-720" "Cartridge.Name" "Cosmic Swarm (1982) (CommaVid) (PAL)" "Cartridge.Note" "AKA Angriff der Termiten" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2a33e21447bf9e13dcfed85077ff6b40" "Cartridge.Name" "Backwards Cannonball v2 (Hack)" "Cartridge.Note" "Hack of Human Cannonball" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2a360bc85bf22de438651cf92ffda1de" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP213" "Cartridge.Name" "Spy Vs. Spy (4 Game in One) (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA Chopper Command" "" "Cartridge.MD5" "2a9f9001540c55a302befd8e9d54b47b" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX2697, CX2697P" "Cartridge.Name" "Mario Bros. (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "2aa5e56d36c2e58b6f2856109f2099a9" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2628 - 6-99842, 49-75117" "Cartridge.Name" "Bowling (1979) (Atari) (4K) [a]" "" "Cartridge.MD5" "2aba6a1b01a5859e96d6a66d2286772f" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-027" "Cartridge.Name" "Plaque Attack (1983) (Activision) (8K)" "" "Cartridge.MD5" "2abc3d46b3f2140160759e2e10bc86d9" "Cartridge.Name" "Gunfight 2600 - Beta Release! (2001) (MP)" "" "Cartridge.MD5" "2ac3a08cfbf1942ba169c3e9e6c47e09" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "EAK-046-04B" "Cartridge.Name" "Fighter Pilot (1988) (Activision) (PAL)" "Cartridge.Note" "AKA Tomcat - The F-14 Fighter Simulator" "" "Cartridge.MD5" "2ae700c9dba843a68dfdca40d7d86bd6" "Cartridge.Manufacturer" "TechnoVision - Thomas Jentzsch" "Cartridge.Name" "Pharaoh's Curse (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.YStart" "40" "Display.Height" "240" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2aeedcc6eb1602efb77161b0cef832ab" "Cartridge.Manufacturer" "SOLID Corp. (D. Scott Williamson)" "Cartridge.ModelNo" "CX2655-025" "Cartridge.Name" "Star Castle 2600 (SolidCorp) [025]" "Cartridge.Note" "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2b1589c7e1f394ae6a1c046944f06688" "Cartridge.Manufacturer" "Carrere Video - JWDA, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV - Teldec - Prism" "Cartridge.ModelNo" "USC2003" "Cartridge.Name" "Eggomania (1983) (Carrere Video) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 60" "" "Cartridge.MD5" "2b27eb194e13f3b38d23c879cc1e3abf" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "402.272 9" "Cartridge.Name" "Super-Ferrari (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "2b42da79a682ed6e2d735facbf70107e" "Cartridge.Name" "DKjr Improved (Hack)" "Cartridge.Note" "Hack of Donkey Kong Jr." "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2b430c00dc79e495762ac59b2f9b4fcd" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-018, AX-018-04" "Cartridge.Name" "Pitfall! (1982) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2b71a59a53be5883399917bf582b7772" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (final beta) (Greg Troutman) (PD)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2ba02f509a4991aa176ba8d9e540df3d" "Cartridge.Manufacturer" "Atari, Mark R. Hahn" "Cartridge.ModelNo" "CX2678" "Cartridge.Name" "Dukes of Hazzard (1983) (Atari) [a]" "" "Cartridge.MD5" "2bb0a1f1dee5226de648eb5f1c97f067" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Enduro (Robby)" "" "Cartridge.MD5" "2bb9f4686f7e08c5fcc69ec1a1c66fe7" "Cartridge.Manufacturer" "Atari - GCC, John Allred, Mike Feinstein" "Cartridge.ModelNo" "CX2688" "Cartridge.Name" "Jungle Hunt (1983) (Atari)" "" "Cartridge.MD5" "2bc26619e31710a9884c110d8430c1da" "Cartridge.Manufacturer" "Atari, Bob Whitehead" "Cartridge.ModelNo" "CX2652, CX2652P" "Cartridge.Name" "Casino (1979) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "" "Cartridge.MD5" "2bc6c53b19e0097a242f22375a6a60ff" "Cartridge.Name" "Droid Demo 2 (David Conrad Schweinsberg) (PD)" "" "Cartridge.MD5" "2bee7f226d506c217163bad4ab1768c0" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Beck-Tech, Steve Beck" "Cartridge.ModelNo" "6210, 06002, 06004, 99002" "Cartridge.Name" "Ghost Manor (1983) (Xonox)" "" "Cartridge.MD5" "2bf34b6ad7d2317a2d0808b3fb93571b" "Cartridge.Name" "Easy Playfield Graphics (1997) (Chris Cracknell)" "" "Cartridge.MD5" "2c0dc885d5ede94aa664bf3081add34e" "Cartridge.Name" "Earth Dies Screaming, The (Unknown) (PAL)" "" "Cartridge.MD5" "2c29182edf0965a7f56fe0897d2f84ba" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26192" "Cartridge.Name" "Klax (08-18-1990) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2c2aea31b01c6126c1a43e10cacbfd58" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Synthcart (2002) (Paul Slocum)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2c3b2843295c9d6b16996971180a3fe9" "Cartridge.Manufacturer" "HES - Activision" "Cartridge.Name" "Sports Action Pak - Enduro, Ice Hockey, Fishing Derby, Dragster (1988) (HES) (PAL)" "" "Cartridge.MD5" "2c3b9c171e214e9e46bbaa12bdf8977e" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2639 - 49-75162" "Cartridge.Name" "Othello (1981) (Atari) (4K) [a]" "" "Cartridge.MD5" "2c45c3eb819a797237820a1816c532eb" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Boxing (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "2c8835aed7f52a0da9ade5226ee5aa75" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (1982) (Arcadia)" "" "Cartridge.MD5" "2c8c11295d8613f875b7bcf5253ab9bb" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Kool Aid Man (PAL Conversion) (16-11-2002) (Fabrizio Zavagli) (PAL60)" "Cartridge.Note" "PAL60 Conversion" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "Cartridge.MD5" "2c9fadd510509cc7f28f1ccba931855f" "Cartridge.Name" "Hangman Invader Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2ca6445204ffb7686ddee3e33ba64d5b" "Cartridge.Manufacturer" "Alex Herbert" "Cartridge.Name" "AtariVox Test ROM" "Cartridge.Note" "Uses the AtariVox controller" "Controller.Right" "ATARIVOX" "" "Cartridge.MD5" "2cb42cf62b2f25f59f909b5447821b14" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu - Children's Computer Workshop" "Cartridge.ModelNo" "CX26104" "Cartridge.Name" "Big Bird's Egg Catch (1983) (Atari) (PAL) [a]" "Cartridge.Note" "Uses Kids/Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "2cccc079c15e9af94246f867ffc7e9bf" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "203" "Cartridge.Name" "Jungle Fever (1982) (PlayAround)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2cefa695df2ed020899a7df7bb1e3a95" "Cartridge.Manufacturer" "Manuel Polik, Fabrizio Zavagli" "Cartridge.Name" "A-Team (2002) (Manuel Polik) (Hack)" "Cartridge.Note" "Hack of A-Team" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2cf20f82abcae2decff88db99331e071" "Cartridge.Manufacturer" "Activision, Mike Lorenzen" "Cartridge.ModelNo" "AX-023" "Cartridge.Name" "Oink! (1983) (Activision) (8K)" "" "Cartridge.MD5" "2cfb188c1091cc7ec2a7e60064d2a758" "Cartridge.Name" "Space Invaders Hack Demo (2003) (SnailSoft)" "" "Cartridge.MD5" "2d15b092e8350912ec4b2e5e750fa1c6" "Cartridge.Manufacturer" "Wizard Video Games, Bob Davis, Robert H. O'Neil" "Cartridge.Name" "Texas Chainsaw Massacre, The (1982) (Wizard Video Games) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2d16a8b59a225ea551667be45f554652" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "802.744 3" "Cartridge.Name" "Der Geheimkurier (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Mr. Postman" "" "Cartridge.MD5" "2d1cf85fbc732856bf76470cd4060f4a" "Cartridge.Name" "Daredevil (V1) (Stunt_Cycle_Rules!) (PD)" "Display.Height" "216" "" "Cartridge.MD5" "2d2c5f0761e609e3c5228766f446f7f8" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26170, CX26170P" "Cartridge.Name" "Secret Quest (1989) (Atari) (PAL)" "" "Cartridge.MD5" "2d405da70af82b20a6b3ecc3d1d2c4ec" "Cartridge.Manufacturer" "Genus" "Cartridge.Name" "Pitfall (Genus)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "2d6741cda3000230f6bbdd5e31941c01" "Cartridge.Manufacturer" "CBS Electronics - VSS" "Cartridge.ModelNo" "80110" "Cartridge.Name" "Targ (1983) (CBS Electronics) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2d69a5f23784f1c2230143292a073b53" "Cartridge.Name" "Qb (Fixed background animation) (2001) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2d6da0eb85eabc93270e5bb8a466ca51" "Cartridge.Name" "Sprite Demo 7 (PD)" "" "Cartridge.MD5" "2d76c5d1aad506442b9e9fb67765e051" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo" "Cartridge.ModelNo" "AP-2004" "Cartridge.Name" "Lost Luggage (1982) (Apollo) [no opening scene]" "Cartridge.Note" "AKA Airport Mayhem" "" "Cartridge.MD5" "2d9e5d8d083b6367eda880e80dfdfaeb" "Cartridge.Manufacturer" "QDI, Mike Montana, Rich Montana - Selchow & Righter" "Cartridge.ModelNo" "87" "Cartridge.Name" "Glib (1983) (QDI)" "Cartridge.Note" "AKA Video Word Game" "" "Cartridge.MD5" "2d9e65959808a6098c16c82a59c9d9dc" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (1 of 3) (1982) (Starpath) (PAL)" "" "Cartridge.MD5" "2dbc92688f9ba92a7e086d62be9df79d" "Cartridge.Name" "How to Draw a Playfield (1997) (Jim Crawford) (PD)" "" "Cartridge.MD5" "2dbdca3058035d2b40c734dcf06a86d9" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Asteroids DC+ (Thomas Jentzsch) (Hack)" "Cartridge.Note" "Uses the Joystick (left) or Steering (right) Controller" "Cartridge.Rarity" "Hack" "Controller.Right" "DRIVING" "Controller.MouseAxis" "58" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2dcf9ce486393cd36ca0928cd53b96cb" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Allred" "Cartridge.ModelNo" "CX2688, CX2688P" "Cartridge.Name" "Jungle Hunt (1983) (Atari) (PAL) [a2]" "" "Cartridge.MD5" "2de41a11c6767e54a5ee9ebaffec72af" "Cartridge.Manufacturer" "Gray Games & AtariAge" "Cartridge.Name" "E.T. Book Cart (PAL60)" "Cartridge.Note" "Charles F. Gray & Michael Rideout" "Display.Format" "PAL60" "Display.YStart" "15" "Display.Height" "240" "Display.Phosphor" "YES" "Display.PPBlend" "55" "" "Cartridge.MD5" "2dfec1615c49501fefc02165c81955e6" "Cartridge.Name" "Song (05-11-2002) (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2e0aed5bb619edcefa3fafb4fbe7c551" "Cartridge.Name" "Qb (2.06) (Retroactive) (NTSC)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2e2885e68fa1045871ce1382b68f6efc" "Cartridge.Name" "Star Fire - Return of the Crosshair (MP)" "" "Cartridge.MD5" "2e2acef8513edcca991e7e5149412e11" "Cartridge.Manufacturer" "Parker Brothers, Larry Gelberg, Gary Goltz" "Cartridge.ModelNo" "PB5065" "Cartridge.Name" "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (16K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2e3728f3086dc3e71047ffd6b2d9f015" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Outlaw (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "2e5b184da8a27c4d362b5a81f0b4a68f" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Rabbit Transit (08-29-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2e663eaa0d6b723b645e643750b942fd" "Cartridge.Manufacturer" "Atari, Tom Rudadahl - Sears" "Cartridge.ModelNo" "CX2634 - 49-75121" "Cartridge.Name" "Golf (1980) (Atari)" "" "Cartridge.MD5" "2e7e9c6dcfcceaffc6fa73f0d08a402a" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-818" "Cartridge.Name" "Star Voyager (1983) (CCE) [a]" "" "Cartridge.MD5" "2e82a1628ef6c735c0ab8fa92927e9b0" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26109" "Cartridge.Name" "Sorcerer's Apprentice (1983) (Atari) (PAL)" "" "Cartridge.MD5" "2e842c2ee22e9dad9df16eed091315c4" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "701-157" "Cartridge.Name" "2 Pak Special - Motocross, Boom Bang (1990) (HES) (PAL)" "" "Cartridge.MD5" "2eaf8fa9e9fdf1fcfc896926a4bdbf85" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Excalibur Version 39 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)" "" "Cartridge.MD5" "2ec6b045cfd7bc52d9cdfd1b1447d1e5" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAG-009, PAG-009 - 711 009-720" "Cartridge.Name" "Freeway (1981) (Activision) (PAL)" "" "Cartridge.MD5" "2eda6a49a49fcb2b674ea9e160b6a617" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "Rambo in Afghanistan (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Riddle of the Sphinx" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2ef36341d1bf42e02c7ea2f71e024982" "Cartridge.Name" "Space Invaders (Explosion Hack)" "Cartridge.Note" "Hack of Space Invaders (Atari)" "" "Cartridge.MD5" "2f0546c4d238551c7d64d884b618100c" "Cartridge.Manufacturer" "Sega, Jeff Lorenz" "Cartridge.Name" "Ixion (1984) (Sega) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2f0a8bb4e18839f9b1dcaa2f5d02fd1d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Futebol (CCE) [a]" "Cartridge.Note" "AKA RealSports Football" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2f11ba54609777e2c6a5da9b302c98e8" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2676" "Cartridge.Name" "Centipede (1982) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2f16663b01591539624d0ef52934a17d" "Cartridge.Manufacturer" "M Network" "Cartridge.Name" "Rocky and Bullwinkle" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2f2f9061398a74c80420b99ddecf6448" "Cartridge.Manufacturer" "Rentacom - Brazil" "Cartridge.Name" "Bobby Is Going Home (Rentacom)" "" "Cartridge.MD5" "2f66ebf037321ed0442ac4b89ce22633" "Cartridge.Manufacturer" "Baroque Gaming (Brian Eno)" "Cartridge.Name" "Warring Worms (Beta 2) (2002) (Baroque Gaming)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "2f7772879a1ed04f660aa9d77a86a4bd" "Cartridge.Name" "Yars' Revenge (Genesis)" "Cartridge.Note" "Genesis controller (C is zorlon cannon)" "Cartridge.Rarity" "Hack of Yars' Revenge" "Controller.Left" "GENESIS" "Display.Phosphor" "YES" "" "Cartridge.MD5" "2f77f015fc880b05f28e84156f989a0c" "Cartridge.Name" "Plane Demo (Gonzalo) (PD)" "" "Cartridge.MD5" "2f7949f71076db42480d3f5036b4a332" "Cartridge.Name" "Name This Game (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "2facd460a6828e0e476d3ac4b8c5f4f7" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.Name" "Words-Attack (1983) (Sancho) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3025bdc30b5aec9fb40668787f67d24c" "Cartridge.Name" "Demo Image Series #14 - Two Marios (4K Interleaved Chronocolour Vertical Movement) (05-03-2003) (AD)" "" "Cartridge.MD5" "303242c239474f2d7763b843de58c1c3" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Laser Blast (CCE)" "" "Cartridge.MD5" "304512528a5530a9361e8a231ed9a6de" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "River Raid Plus (Thomas Jentzsch) (Hack)" "Cartridge.Note" "Hack of River Raid" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "30512e0e83903fc05541d2f6a6a62654" "Cartridge.Manufacturer" "Atari, Jim Huether - Sears" "Cartridge.ModelNo" "CX2644 - 6-99824" "Cartridge.Name" "Flag Capture (1978) (Atari)" "Cartridge.Note" "AKA Capture the Flag" "" "Cartridge.MD5" "30516cfbaa1bc3b5335ee53ad811f17a" "Cartridge.Manufacturer" "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin" "Cartridge.ModelNo" "007" "Cartridge.Name" "Halloween (1983) (Wizard Video Games)" "" "Cartridge.MD5" "3051b6071cb26377cd428af155e1bfc4" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2607 - 6-99828, 49-75115" "Cartridge.Name" "Canyon Bomber (1979) (Atari) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXDR" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10" "Display.YStart" "42" "" "Cartridge.MD5" "30685b9b6ebd9ba71536dd7632a1e3b6" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Tennis (Dactari)" "" "Cartridge.MD5" "3091af0ef1a61e801f4867783c21d45c" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-862" "Cartridge.Name" "Crackpots (1983) (CCE) [a]" "" "Cartridge.MD5" "30997031b668e37168d4d0e299ccc46f" "Cartridge.Name" "John K Harvey's Equalizer (PAL) (PD)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "30c92c685224dc7a72b9bbe5eb62d004" "Cartridge.Name" "Hangman Monkey Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "30e012e8d50330c8972f126b8e913bc4" "Cartridge.Name" "Indy 500 (Hack) [a2]" "Cartridge.Note" "Hack of Indy 500" "Cartridge.Rarity" "Hack" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "" "Cartridge.MD5" "30e0ab8be713208ae9a978b34e9e8e8c" "Cartridge.Manufacturer" "Atari, Mike Lorenzen" "Cartridge.ModelNo" "CX2630, CX2630P" "Cartridge.Name" "Circus Atari (1980) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 55" "" "Cartridge.MD5" "30f0b49661cfcfd4ec63395fab837dc3" "Cartridge.Manufacturer" "Sega, Jeff Lorenz - Teldec" "Cartridge.ModelNo" "004-01" "Cartridge.Name" "Star Trek - Strategic Operations Simulator (1983) (Sega) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3105967f7222cc36a5ac6e5f6e89a0b4" "Cartridge.Manufacturer" "Sega, Jeff Lorenz" "Cartridge.ModelNo" "011-01, 011-02" "Cartridge.Name" "Spy Hunter (1984) (Sega)" "Cartridge.Note" "Uses Joystick Coupler (Dual Control Module)" "" "Cartridge.MD5" "310ba30e25ea8957e58180b663503c0c" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Sound X6 (1994) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "313243fc41e49ef6bd3aa9ebc0d372dd" "Cartridge.Name" "Fast Food (Unknown) (PAL)" "" "Cartridge.MD5" "31512cdfadfd82bfb6f196e3b0fd83cd" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-004" "Cartridge.Name" "River Patrol (1984) (Tigervision)" "" "Cartridge.MD5" "3177cc5c04c1a4080a927dfa4099482b" "Cartridge.Manufacturer" "Atari - Imagineering, Alex DeMeo" "Cartridge.ModelNo" "CX26135" "Cartridge.Name" "RealSports Boxing (1987) (Atari)" "" "Cartridge.MD5" "317a4cdbab090dcc996833d07cb40165" "Cartridge.Manufacturer" "Goliath - Hot Shot" "Cartridge.ModelNo" "83-312" "Cartridge.Name" "Missile War (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Astrowar" "" "Cartridge.MD5" "318046ae3711c05fd16e479b298e5fcc" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.08) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "318a9d6dda791268df92d72679914ac3" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-017, AX-017-04" "Cartridge.Name" "MegaMania (1982) (Activision)" "" "Cartridge.MD5" "319a142aab6260842ab616382848c204" "Cartridge.Name" "Marble Craze (05-02-2002) (Paul Slocum)" "" "Cartridge.MD5" "31bb9b8ceed46cb3e506777a9e65f3ce" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.Name" "4 Game in One Light Green (1983) (BitCorp) (PAL)" "Cartridge.Note" "Phantom UFO, Ice Hockey, Cosmic Avenger, Spy Vs. Spy" "Cartridge.Type" "4IN1" "" "Cartridge.MD5" "31c5fd55a39db5ff30a0da065f86c140" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Enduro (Dactari)" "" "Cartridge.MD5" "31d08cb465965f80d3541a57ec82c625" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2641 - 99807, 49-75105" "Cartridge.Name" "Surround (1977) (Atari) (4K)" "" "Cartridge.MD5" "31df1c50c4351e144c9a378adb8c10ba" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "687.463 0" "Cartridge.Name" "Die Ratte und die Karotten (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Gopher" "" "Cartridge.MD5" "31e518debba46df6226b535fa8bd2543" "Cartridge.Manufacturer" "Atari, Douglas 'Solaris' Neubauer, Mimi Nyden" "Cartridge.ModelNo" "CX26134" "Cartridge.Name" "Last Starfighter (1984) (Atari) (Prototype)" "Cartridge.Note" "Solaris Beta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "31f4692ee2ca07a7ce1f7a6a1dab4ac9" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2642" "Cartridge.Name" "Game of Concentration (1980) (Atari) (4K)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "31fcbce1cfa6ec9f5b6de318e1f57647" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday" "Cartridge.ModelNo" "CX26115" "Cartridge.Name" "Dumbo's Flying Circus (1983) (Atari) (Prototype) (PAL)" "Cartridge.Note" "AKA Dumbo Flies Home" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "32199271dc980eb31a2cc96e10a9e244" "Cartridge.Name" "Radial Pong - Version 12 (Jeffry Johnston) (PD)" "" "Cartridge.MD5" "321c3451129357af42a375d12afd4450" "Cartridge.Manufacturer" "Atari - Imagineering, Dan Kitchen" "Cartridge.ModelNo" "CX26177" "Cartridge.Name" "Ikari Warriors (1991) (Atari) (PAL)" "" "Cartridge.MD5" "32244e55ce6ec6bfbd763f33384bdc2e" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-027" "Cartridge.Name" "Plaque Attack (1983) (Activision) (16K)" "" "Cartridge.MD5" "3225676f5c0c577aeccfaa7e6bedd765" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1002" "Cartridge.Name" "Pole Position (1983) (CCE)" "" "Cartridge.MD5" "322b29e84455aa41e7cc9af463bffa89" "Cartridge.Manufacturer" "Atari - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "CX2663" "Cartridge.Name" "Road Runner (06-25-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "324cb4a749bcac4f3db9da842b85d2f7" "Cartridge.Manufacturer" "Dennis Debro" "Cartridge.Name" "Climber 5 (01-05-2003) (Dennis Debro)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "327468d6c19697e65ab702f06502c7ed" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "Aster-Hawk (2002) (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Asteroids" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3276c777cbe97cdd2b4a63ffc16b7151" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Kevin Osborn" "Cartridge.ModelNo" "CX2691" "Cartridge.Name" "Joust (1983) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3278158e5c1f7eb5c5d28ccfd7285250" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Megamania (Dactari)" "" "Cartridge.MD5" "327fe8cf94f3a45c35a840a453df1235" "Cartridge.Name" "Spice Girls Rule Demo (PD)" "" "Cartridge.MD5" "328949872e454181223a80389d03c122" "Cartridge.Name" "Home Run (Unknown) (PAL)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "32ae78abbb5e677e2aabae5cc86cec29" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu, Courtney Granner" "Cartridge.ModelNo" "CX26112" "Cartridge.Name" "Good Luck, Charlie Brown (04-18-1984) (Atari) (Prototype)" "Cartridge.Note" "Prototype" "" "Cartridge.MD5" "32d1260ea682e1bb10850fa94c04ec5f" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Basketball (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "32dcd1b535f564ee38143a70a8146efe" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson" "Cartridge.ModelNo" "99007, 6240" "Cartridge.Name" "Tomarc the Barbarian (1983) (Xonox)" "Cartridge.Note" "AKA Thundarr the Barbarian" "" "Cartridge.MD5" "32e65d1e4dfcbcd9b57fee72cafe074c" "Cartridge.Name" "Eckhard Stolberg's Scrolling Text Demo 3 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "32ecb5a652eb73d287e883eea751d99c" "Cartridge.Manufacturer" "Dactar - Milmar" "Cartridge.Name" "Bowling (Dactar - Milmar)" "" "Cartridge.MD5" "32f4e47a71601ab06cfb59e1c6a0b846" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Sound X (1994) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "3316ee2f887e9cb9b54dd23c5b98c3e2" "Cartridge.Name" "Texas Golf (miniature Gold Hack)" "" "Cartridge.MD5" "331938989f0f33ca39c10af4c09ff640" "Cartridge.Manufacturer" "Zach Matley" "Cartridge.Name" "Combat - Tank AI (19-04-2003) (Zach Matley)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "332f01fd18e99c6584f61aa45ee7791e" "Cartridge.Name" "X'Mission (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3347a6dd59049b15a38394aa2dafa585" "Cartridge.Manufacturer" "Parker Brothers - JWDA, Henry Will IV" "Cartridge.ModelNo" "PB5760" "Cartridge.Name" "Montezuma's Revenge (1984) (Parker Bros)" "Cartridge.Note" "Featuring Panama Joe" "" "Cartridge.MD5" "335793736cbf6fc99c9359ed2a32a49d" "Cartridge.Name" "Analog Clock (V0.0) (20-01-2003) (AD) [a]" "" "Cartridge.MD5" "335a7c5cfa6fee0f35f5824d1fa09aed" "Cartridge.Manufacturer" "Sega - Beck-Tech, Steve Beck, Phat Ho - Teldec" "Cartridge.ModelNo" "006-01 - 3.60105 VG" "Cartridge.Name" "Congo Bongo (1983) (Sega) (PAL)" "" "Cartridge.MD5" "3367eeba3269aa04720abe6169767502" "Cartridge.Name" "Space Treat (30-12-2002) (Fabrizio Zavagli)" "" "Cartridge.MD5" "3391f7c4c656793f92299f4187e139f7" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype) [a4]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "33cac5e767a534c95d292b04f439dc37" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Tapeworm (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "33d68c3cd74e5bc4cf0df3716c5848bc" "Cartridge.Manufacturer" "CBS Electronics, Tom DiDomenico" "Cartridge.ModelNo" "4L 2486 5000" "Cartridge.Name" "Blueprint (1983) (CBS Electronics)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "33ed6dfac4b9ea2f81f778ceddbb4a75" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "River Raid (1982) (SpkSoft) [t1]" "" "Cartridge.MD5" "340f546d59e72fb358c49ac2ca8482bb" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC003" "Cartridge.Name" "Skindiver (1983) (Sancho) (PAL)" "" "Cartridge.MD5" "34340c8eecd1e557314789cc6477e650" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 4 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "345488d3b014b684a181108f0ef823cb" "Cartridge.Manufacturer" "CBS Electronics, Tom DiDomenico" "Cartridge.ModelNo" "4L 2486 5000" "Cartridge.Name" "Blueprint (1983) (CBS Electronics) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "345758747b893e4c9bdde8877de47788" "Cartridge.Manufacturer" "CBS Electronics, Joseph Biel" "Cartridge.ModelNo" "4L1802, 4L1803, 4L1804, 4L2278" "Cartridge.Name" "Venture (1983) (CBS Electronics) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "345769d085113d57937198262af52298" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-007" "Cartridge.Name" "Space Raid (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA MegaMania" "" "Cartridge.MD5" "346555779a2d51b48833463b5433472f" "Cartridge.Name" "Thrust (V0.1) (2000) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "348615ffa30fab3cec1441b5a76e9460" "Cartridge.Manufacturer" "Activision, Alan Miller - Ariola" "Cartridge.ModelNo" "EAX-016, PAX-016 - 711 016-725" "Cartridge.Name" "StarMaster (1982) (Activision) (PAL) [fixed]" "Cartridge.Note" "Use Color/BW switch to change between galactic chart and front views" "" "Cartridge.MD5" "34b269387fa1aa5a396636f5ecdd63dd" "Cartridge.Name" "Marble Craze (mc7_23) (Paul Slocum)" "Display.YStart" "30" "" "Cartridge.MD5" "34c808ad6577dbfa46169b73171585a3" "Cartridge.Manufacturer" "Apollo" "Cartridge.ModelNo" "AP-2012" "Cartridge.Name" "Squoosh (1983) (Apollo) (Prototype)" "Cartridge.Note" "AKA Vat's Incredible!, The Grape Escape" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "34ca2fcbc8ba4a0b544acd94991cfb50" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.Name" "Dukes of Hazzard (1980) (Atari) (Prototype) (4K)" "Cartridge.Note" "AKA Stunt Cycle" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "34e37eaffc0d34e05e40ed883f848b40" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.15) (Retroactive) (Stella)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "34f4b1d809aa705ace6e46b13253fd3b" "Cartridge.Manufacturer" "Aaron Bergstrom" "Cartridge.Name" "Nothern Alliance (Aaron Bergstrom) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "34fd4fcb40ff5babce67f8b806d5969c" "Cartridge.Name" "Boxing (Dactari) (4K)" "" "Cartridge.MD5" "350e0f7b562ec5e457b3f5af013648db" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX26119" "Cartridge.Name" "Saboteur (06-09-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "35156407e54f67eb1f625450d5c093e1" "Cartridge.Name" "Mouse Trap (Genesis)" "Cartridge.Note" "Genesis controller (C changes to dog)" "Cartridge.Rarity" "Hack of Mouse Trap" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "35163b56f4a692a232ae96ad3e23310f" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.12) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3556e125681aea864e17b09f3f3b2a75" "Cartridge.Name" "Incoming (2 Player Demo) (PD)" "" "Cartridge.MD5" "3576037c9281656655fa114a835be553" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (1 of 4) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "3577e19714921912685bb0e32ddf943c" "Cartridge.Manufacturer" "TechnoVision - Video Technology" "Cartridge.ModelNo" "TVS1003" "Cartridge.Name" "Pharaoh's Curse (1983) (TechnoVision) (PAL)" "Display.YStart" "34" "Display.Phosphor" "YES" "" "Cartridge.MD5" "35ae903dff7389755ad4a07f2fb7400c" "Cartridge.Name" "Colored Wall Demo (PD)" "" "Cartridge.MD5" "35b10a248a7e67493ec43aeb9743538c" "Cartridge.Manufacturer" "Dor-x" "Cartridge.Name" "Defender (Dor-x) (Hack)" "Cartridge.Note" "Hack of Defender" "" "Cartridge.MD5" "35b43b54e83403bb3d71f519739a9549" "Cartridge.Manufacturer" "Parker Brothers, Dave Engman, Isabel Garret" "Cartridge.Name" "McDonald's (06-06-1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "35be55426c1fec32dfb503b4f0651572" "Cartridge.Manufacturer" "Men-A-Vision" "Cartridge.Name" "Air Raid (Men-A-Vision) (PAL)" "Cartridge.Rarity" "Extremely Rare" "Display.Phosphor" "YES" "" "Cartridge.MD5" "35fa32256982774a4f134c3347882dff" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.05) (Macintosh) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "360ba640f6810ec902b01a09cc8ab556" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (06-15-1983) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "360c0dcb11506e73bd0b77207c81bc62" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Enduro (1983) (Digitel)" "" "Cartridge.MD5" "3619786f6a32efc1e4a262d5aca8a070" "Cartridge.Manufacturer" "Atari, John Dunn - Sears" "Cartridge.ModelNo" "CX2631 - 49-75152" "Cartridge.Name" "Superman (1979) (Atari) (8K)" "" "Cartridge.MD5" "3624e5568368929fabb55d7f9df1022e" "Cartridge.Manufacturer" "Activision - Imagineering, Dan Kitchen" "Cartridge.ModelNo" "EAK-050-04" "Cartridge.Name" "Double Dragon (1989) (Activision) (PAL)" "" "Cartridge.MD5" "36306070f0c90a72461551a7a4f3a209" "Cartridge.Manufacturer" "U.S. Games Corporation - JWDA, Roger Booth, Sylvia Day, Ron Dubren, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV" "Cartridge.ModelNo" "VC1007" "Cartridge.Name" "Name This Game (1983) (U.S. Games)" "Cartridge.Note" "AKA Octopussy" "" "Cartridge.MD5" "36547bc6faa5132b87504e18d088e1d7" "Cartridge.Name" "Cosmic Swarm (Unknown) (PAL) (4K)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "367411b78119299234772c08df10e134" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Skiing (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "3685060707df27d4091ba0ea2dc4b059" "Cartridge.Name" "PezZerk - PezMan in Ghost Manor (Hack)" "Cartridge.Note" "Hack of Berzerk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "368d88a6c071caba60b4f778615aae94" "Cartridge.Manufacturer" "Atari, Matthew L. Hubbard" "Cartridge.ModelNo" "CX26159" "Cartridge.Name" "Double Dunk (1989) (Atari)" "Cartridge.Note" "AKA Super Basketball" "" "Cartridge.MD5" "36a701c60a9f9768d057bc2a83526a80" "Cartridge.Name" "Cube Conquest (Interlaced) (Billy Eno) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "36b20c427975760cb9cf4a47e41369e4" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26143" "Cartridge.Name" "Donkey Kong (1987) (Atari)" "" "Cartridge.MD5" "36c29ceee2c151b23a1ad7aa04bd529d" "Cartridge.Manufacturer" "Atari - GCC, Ava-Robin Cohen" "Cartridge.ModelNo" "CX26123" "Cartridge.Name" "Jr. Pac-Man (1986) (Atari)" "" "Cartridge.MD5" "36c31bb5daeb103f488c66de67ac5075" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia)" "Cartridge.Note" "Uses Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 56" "" "Cartridge.MD5" "36c993dc328933e4dd6374a8ffe224f4" "Cartridge.Manufacturer" "Gameworld, J. Ray Dettling" "Cartridge.ModelNo" "133-007" "Cartridge.Name" "Bermuda Triangle (1983) (Gameworld) (PAL)" "" "Cartridge.MD5" "36e47ed74968c365121eab60f48c6517" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "343.373 7" "Cartridge.Name" "Master Builder (1983) (Quelle) (PAL)" "" "Cartridge.MD5" "36edef446ab4c2395666efc672b92ed0" "Cartridge.Manufacturer" "Atari - Axlon, John Vifian" "Cartridge.ModelNo" "CX26168" "Cartridge.Name" "Off the Wall (1989) (Atari) (PAL)" "" "Cartridge.MD5" "36f9a953ebdd9a8be97ccf27a2041903" "Cartridge.Name" "Chinese Character Demo (PD)" "" "Cartridge.MD5" "37252757a79dc5b174e3c03d6ea0bdcb" "Cartridge.Name" "Sky Diver (Unknown) (PAL) (4K) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "372bddf113d088bc572f94e98d8249f5" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA285" "Cartridge.Name" "Wall-Defender (1983) (Bomb) (PAL)" "Cartridge.Note" "AKA Wall Break" "" "Cartridge.MD5" "373b8a081acd98a895db0cb02df35673" "Cartridge.Name" "Demo Image Series #5 - Boofly (19-02-2003) (AD)" "" "Cartridge.MD5" "3750f2375252b6a20e4628692e94e8b1" "Cartridge.Manufacturer" "Dismac" "Cartridge.Name" "Ases do Ar (Dismac)" "Cartridge.Note" "AKA Sky Jinks" "" "Cartridge.MD5" "37527966823ee9243d34c7da8302774f" "Cartridge.Name" "Word Zapper (Unknown) (PAL)" "" "Cartridge.MD5" "376944889dcfa96c73d3079f308e3d32" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (0.11) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3783f12821b88b08814da8adb1a9f220" "Cartridge.Name" "Mission Survive (PAL) (Genesis)" "Cartridge.Note" "Genesis controller (C is vertical fire)" "Cartridge.Rarity" "Hack of Mission Survive)" "Console.RightDifficulty" "A" "Controller.Left" "GENESIS" "Display.Phosphor" "YES" "" "Cartridge.MD5" "378a62af6e9c12a760795ff4fc939656" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26171" "Cartridge.Name" "MotoRodeo (1991) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "378c118b3bda502c73e76190ca089eef" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2662P" "Cartridge.Name" "Hangman (1978) (Atari) (PAL)" "" "Cartridge.MD5" "37ab3affc7987995784b59fcd3fcbd31" "Cartridge.Name" "Sprite Test (29-11-2002) (Eric Ball)" "" "Cartridge.MD5" "37b98344c8e0746c486caf5aaeec892a" "Cartridge.Manufacturer" "K-Tel Vision" "Cartridge.ModelNo" "6" "Cartridge.Name" "Spider Maze (1982) (K-Tel Vision) (PAL)" "Cartridge.Note" "AKA Spider Kong" "" "Cartridge.MD5" "37e828675d556775ae8285c0caf7d11c" "Cartridge.Manufacturer" "AtariAge - Fred Quimby" "Cartridge.Name" "Gingerbread Man (Fred Quimby) (Genesis)" "Cartridge.Note" "Genesis controller (C throws cookie)" "Cartridge.Rarity" "New Release" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "37f42ab50018497114f6b0f4f01aa9a1" "Cartridge.Name" "Droid Demo 2-M (David Conrad Schweinsberg) (PD)" "" "Cartridge.MD5" "37fd7fa52d358f66984948999f1213c5" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-004" "Cartridge.Name" "Pyramid War (Rainbow Vision) (PAL) [a2]" "Cartridge.Note" "AKA Chopper Command" "" "Cartridge.MD5" "384db97670817103dd8c0bbdef132445" "Cartridge.Manufacturer" "Atari - Sears" "Cartridge.ModelNo" "CX2626 - 6-99829, 49-75116" "Cartridge.Name" "Miniature Golf (1979) (Atari) (4K)" "" "Cartridge.MD5" "384f5fbf57b5e92ed708935ebf8a8610" "Cartridge.Manufacturer" "20th Century Fox Video Games, John W.S. Marvin" "Cartridge.ModelNo" "11009" "Cartridge.Name" "Crypts of Chaos (1983) (20th Century Fox)" "" "Cartridge.MD5" "3856b9425cc0185ed770376a62af0282" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "Yellow Submarine (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Bermuda Triangle" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "386ff28ac5e254ba1b1bac6916bcc93a" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "AR-4300" "Cartridge.Name" "Fireball (1982) (Arcadia)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "3882224adbd0ca7c748b2a1c9b87263e" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2657" "Cartridge.Name" "SwordQuest - FireWorld (1982) (Atari) (PAL) [a]" "" "Cartridge.MD5" "3889351c6c2100b9f3aef817a7e17a7a" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Dolphin (CCE)" "" "Cartridge.MD5" "3897744dd3c756ea4b1542e5e181e02a" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday" "Cartridge.ModelNo" "CX26115" "Cartridge.Name" "Dumbo's Flying Circus (05-05-1983) (Atari) (Prototype)" "Cartridge.Note" "AKA Dumbo Flies Home" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "38bd172da8b2a3a176e517c213fcd5a6" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "MA017600" "Cartridge.Name" "Diagnostic Test Cartridge 2.6 (1982) (Atari)" "" "Cartridge.MD5" "38c362dcd5cad5a62e73ae52631bd9d8" "Cartridge.Manufacturer" "Jake Patterson" "Cartridge.Name" "Baubles (14-11-2001) (Jake Patterson) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "38cf93eacfb2fa9a2c5e39059ff35a74" "Cartridge.Manufacturer" "Greg Zumwalt" "Cartridge.Name" "WacMan (2003) (Greg Zumwalt) (Hack)" "Cartridge.Note" "Hack of Ms. Pac-Man" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "38de7b68379770b9bd3f7bf000136eb0" "Cartridge.Manufacturer" "Imagic, Mark Klein" "Cartridge.ModelNo" "EIZ-003-04I" "Cartridge.Name" "Subterranea (1983) (Imagic) (PAL)" "" "Cartridge.MD5" "391764720140c432aec454a468f77a40" "Cartridge.Manufacturer" "Video Game Program" "Cartridge.Name" "Miss Pack Man (Video Game Program) (PAL)" "Cartridge.Note" "AKA Ms. Pac-Man" "" "Cartridge.MD5" "392d34c0498075dd58df0ce7cd491ea2" "Cartridge.Manufacturer" "Atari, Frank Hausman, Mimi Nyden, Steve Woita" "Cartridge.ModelNo" "CX2686" "Cartridge.Name" "Quadrun (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "392f00fd1a074a3c15bc96b0a57d52a1" "Cartridge.Manufacturer" "Atari, Rob Fulop - Sears" "Cartridge.ModelNo" "CX2633 - 49-75119" "Cartridge.Name" "Night Driver (1980) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 65" "Display.Phosphor" "YES" "" "Cartridge.MD5" "393948436d1f4cc3192410bb918f9724" "Cartridge.Manufacturer" "Activision, Carol Shaw" "Cartridge.ModelNo" "AX-020, AX-020-04" "Cartridge.Name" "River Raid (1982) (Activision)" "" "Cartridge.MD5" "393e41ca8bdd35b52bf6256a968a9b89" "Cartridge.Manufacturer" "U.S. Games Corporation - Western Technologies" "Cartridge.ModelNo" "VC1012" "Cartridge.Name" "M.A.D. (1983) (U.S. Games)" "Cartridge.Note" "AKA Missile Intercept" "" "Cartridge.MD5" "3947eb7305b0c904256cdbc5c5956c0f" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Lilly Adventure (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.Height" "230" "" "Cartridge.MD5" "396f7bc90ab4fa4975f8c74abe4e81f0" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2612 - 99804, 49-75103" "Cartridge.Name" "Street Racer (1977) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers (swapped)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 60" "" "Cartridge.MD5" "39790a2e9030751d7db414e13f1b6960" "Cartridge.Name" "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a1]" "" "Cartridge.MD5" "39a6a5a2e1f6297cceaa48bb03af02e9" "Cartridge.Name" "Pitfall 2 Plus (Hack)" "Cartridge.Note" "Hack of Pitfall 2" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "39b94d41bd3b01c12b4054c1a8733783" "Cartridge.Manufacturer" "SOLID Corp. (D. Scott Williamson)" "Cartridge.ModelNo" "CX2655-016" "Cartridge.Name" "Star Castle 2600 (SolidCorp) [016]" "Cartridge.Note" "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "39c78d682516d79130b379fa9deb8d1c" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo" "Cartridge.ModelNo" "AP-1001" "Cartridge.Name" "Skeet Shoot (1981) (Apollo)" "" "Cartridge.MD5" "39d36366ae7e6dfd53393fb9ebab02a0" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-811" "Cartridge.Name" "River Raid (1983) (CCE) [a]" "" "Cartridge.MD5" "39da69ff9833f8c143f03b6e0e7a996b" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "Ventrra Invaders 2002 (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Megamania" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "39fe316952134b1277b6a81af8e05776" "Cartridge.Manufacturer" "Robby" "Cartridge.ModelNo" "18" "Cartridge.Name" "River Raid (Robby)" "" "Cartridge.MD5" "3a2e2d0c6892aa14544083dfb7762782" "Cartridge.Manufacturer" "Atari, Rob Fulop - Sears" "Cartridge.ModelNo" "CX2638 - 49-75166" "Cartridge.Name" "Missile Command (1981) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3a35d7f1dc2a33565c8dca52baa86bc4" "Cartridge.Name" "Rubik's Cube Demo 2 (23-12-2002) (CT)" "" "Cartridge.MD5" "3a51a6860848e36e6d06ffe01b71fb13" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.07) (Retroactive) (NTSC)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3a526e6a1f9fe918af0f2ce997dfea73" "Cartridge.Manufacturer" "CBS Electronics, Dan Kitchen, Garry Kitchen" "Cartridge.ModelNo" "4L1700, 4L1701, 4L1702, 4L1802, 4L2274" "Cartridge.Name" "Donkey Kong (1982) (CBS Electronics) (PAL) [a1]" "" "Cartridge.MD5" "3a53963f053b22599db6ac9686f7722f" "Cartridge.Name" "Word Zapper (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "3a771876e4b61d42e3a3892ad885d889" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Andrew Fuchs" "Cartridge.ModelNo" "CX26120" "Cartridge.Name" "Defender II (1987) (Atari)" "Cartridge.Note" "AKA Stargate" "" "Cartridge.MD5" "3aad0ef62885736a5b8c6ccac0dbe00c" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Atlantis (1983) (Dynacom)" "" "Cartridge.MD5" "3ab5d138e26d88c8190e7cc629a89493" "Cartridge.Name" "Phased Color Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3ac6c50a8e62d4ce71595134cbd8035e" "Cartridge.Manufacturer" "Absolute Entertainment, Dan Kitchen" "Cartridge.ModelNo" "AK-046-04" "Cartridge.Name" "Tomcat (1988) (Absolute)" "" "Cartridge.MD5" "3ad3dc799211ccd424d7c6d454401436" "Cartridge.Manufacturer" "Probe 2000 - North American Philips Consumer Electronics Corporation" "Cartridge.Name" "Power Lords (1983) (Probe) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "3ad58b53a1e972396890bd86c735e78d" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Excalibur Version 36 (Dragonstomper Beta) (1982) (Arcadia) (Prototype)" "" "Cartridge.MD5" "3b040ed7d1ef8acb4efdeebebdaa2052" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-008" "Cartridge.Name" "Miner 2049er (1983) (Tigervision) [fixed]" "Display.YStart" "28" "Display.Height" "214" "" "Cartridge.MD5" "3b097a7ed5bd2a84dc3d3ed361e9c31c" "Cartridge.Name" "Interleaved ChronoColour Demo (PAL) (05-03-2003) (AD)" "" "Cartridge.MD5" "3b10106836565e5db28c7823c0898fbb" "Cartridge.Manufacturer" "Xonox - Beck-Tech" "Cartridge.ModelNo" "6210, 06002, 06004, 99002" "Cartridge.Name" "Ghost Manor (1983) (Xonox) (PAL) [a]" "Display.YStart" "30" "" "Cartridge.MD5" "3b2c32fcd331664d037952bcaa62df94" "Cartridge.Manufacturer" "Xonox" "Cartridge.ModelNo" "6230, 6250" "Cartridge.Name" "Super Kung-Fu (1983) (Xonox) (PAL) [a]" "" "Cartridge.MD5" "3b5751a8d20f7de41eb069f76fecd5d7" "Cartridge.Name" "Eckhard Stolberg's Scrolling Text Demo 4 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "3b64a00ce147c3c29f7f8f8e531d08d8" "Cartridge.Name" "This Planet Sucks (16K) (Greg Troutman)" "Cartridge.Rarity" "New Release" "Display.YStart" "36" "" "Cartridge.MD5" "3b69f8929373598e1752f43f8da61aa4" "Cartridge.Manufacturer" "Apollo - Games by Apollo - RCA Video Jeux" "Cartridge.ModelNo" "AP-2006" "Cartridge.Name" "Infiltrate (1921) (Apollo) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3b6dba1a24bb2893bd3bd0593f92016b" "Cartridge.Manufacturer" "CBS Electronics / Thomas Jentzsch" "Cartridge.Name" "Omega Race JS (TJ)" "Cartridge.Note" "Hack of Omega Race (CBS Electronics)" "Cartridge.Rarity" "New Release (Hack)" "" "Cartridge.MD5" "3b76242691730b2dd22ec0ceab351bc6" "Cartridge.Manufacturer" "M Network, Connie Goldman, Joe King, Patricia Lewis Du Long, Gerald Moore, Mike Sanders, Jossef Wagner - INTV" "Cartridge.ModelNo" "MT4319" "Cartridge.Name" "Masters of the Universe (1983) (M Network)" "Console.RightDifficulty" "A" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3b80b8f52a0939e16b5059f93a3fc19a" "Cartridge.Manufacturer" "V007" "Cartridge.Name" "Virtual Pet (V007) (after Demo 2) (CRACKERS) (PD)" "" "Cartridge.MD5" "3b86a27132fb74d9b35d4783605a1bcb" "Cartridge.Manufacturer" "Atari, Chris Crawford" "Cartridge.Name" "Wizard (1980) (Atari) (Prototype) (4K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "3b8aacf5f5638492b926b5124de19f18" "Cartridge.Manufacturer" "Atari, Tod Frye - Sears" "Cartridge.ModelNo" "CX2646 - 49-75185" "Cartridge.Name" "Pac-Man (1981) (Atari) (8K)" "" "Cartridge.MD5" "3b91c347d8e6427edbe942a7a405290d" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "PB5350" "Cartridge.Name" "Sky Skipper (1983) (Parker Bros)" "" "Cartridge.MD5" "3b9480bb6fb1e358c9c0a64e86945aee" "Cartridge.Name" "Title Match Pro Wrestling (2002) (Skyworks)" "" "Cartridge.MD5" "3b966bf3c2ca34ac6ca1de4cf6383582" "Cartridge.Name" "Double-Height 6-Digit Score Display (2001) (AD)" "" "Cartridge.MD5" "3bb9793c60c92911895cf44530846136" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Dragster (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "3c21a89bc38d8cd0b010a2916bcff5c2" "Cartridge.Name" "Colony 7 - CX-22 Hack v0.4 (NTSC)" "Controller.Left" "TRAKBALL" "Display.Phosphor" "YES" "Display.PPBlend" "50" "" "Cartridge.MD5" "3c3a2bb776dec245c7d6678b5a56ac10" "Cartridge.Name" "Unknown Title (bin00003) (PD)" "" "Cartridge.MD5" "3c4223316c835ceaad619651e25df0f9" "Cartridge.Name" "Defender (Genesis)" "Cartridge.Note" "Genesis controller (C is smartbomb)" "Cartridge.Rarity" "Hack of Defender" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "3c4a6f613ca8ba27ce9e43c6c92a3128" "Cartridge.Name" "Qb (V0.04) (Non-Lax Version) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3c57748c8286cf9e821ecd064f21aaa9" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira" "Cartridge.ModelNo" "CX26118" "Cartridge.Name" "Millipede (1984) (Atari)" "" "Cartridge.MD5" "3c72ddaf41158fdd66e4f1cb90d4fd29" "Cartridge.Manufacturer" "Dismac" "Cartridge.Name" "Comando Suicida (Dismac)" "Cartridge.Note" "AKA Chopper Command" "" "Cartridge.MD5" "3c7a7b3a0a7e6319b2fa0f923ef6c9af" "Cartridge.Manufacturer" "Atari - Roklan, Joe Gaucher" "Cartridge.Name" "Racer (1982) (Atari) (Prototype)" "Cartridge.Note" "ROM must be started in bank 0" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "3c7a96978f52b2b15426cdd50f2c4048" "Cartridge.Name" "Overhead Adventure Demo 3 (PD)" "" "Cartridge.MD5" "3c82e808fe0e6a006dc0c4e714d36209" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-004" "Cartridge.Name" "Fishing Derby (1980) (Activision) (16K)" "" "Cartridge.MD5" "3c853d864a1d5534ed0d4b325347f131" "Cartridge.Manufacturer" "Telesys, Don 'Donyo' Ruffcorn" "Cartridge.ModelNo" "1002" "Cartridge.Name" "Cosmic Creeps (1982) (Telesys)" "Cartridge.Note" "AKA Space Maze, Spaze Maze" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3c8e57a246742fa5d59e517134c0b4e6" "Cartridge.Manufacturer" "Parker Brothers, Rex Bradford, Sam Kjellman" "Cartridge.ModelNo" "PB5050" "Cartridge.Name" "Star Wars - The Empire Strikes Back (1982) (Parker Bros)" "" "Cartridge.MD5" "3ca51b5c08f5a0ecfb17d0c1ec6d0942" "Cartridge.Manufacturer" "Atari, James Andreasen - Sears" "Cartridge.ModelNo" "CX2654 - 49-75141" "Cartridge.Name" "Haunted House (09-28-81) (Atari) (Prototype)" "Cartridge.Note" "AKA Mystery Mansion, Graves' Manor, Nightmare Manor" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "3caa902ac0ce4509308990645876426a" "Cartridge.Manufacturer" "Atari - GCC, Dave Payne" "Cartridge.ModelNo" "CX2669, CX2669P" "Cartridge.Name" "Vanguard (1983) (Atari) (PAL)" "" "Cartridge.MD5" "3cbdf71bb9fd261fbc433717f547d738" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-803" "Cartridge.Name" "Bobby Is Going Home (1983) (CCE) (PAL)" "Cartridge.Note" "AKA Bobby Vai Para Casa" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "3cdd91e1c28d28e856c0063d602da166" "Cartridge.Name" "Stell-A-Sketch (03-11-1997) (Bob Colbert) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3d1e83afdb4265fa2fb84819c9cfd39c" "Cartridge.Manufacturer" "Coleco - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV" "Cartridge.ModelNo" "2465" "Cartridge.Name" "Smurf - Rescue in Gargamel's Castle (1983) (Coleco)" "Cartridge.Note" "AKA Smurf, Smurf Action" "" "Cartridge.MD5" "3d2367b2b09c28f1659c082bb46a7334" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "720103-2A, IA3203P, EIX-010-04I" "Cartridge.Name" "Atlantis (1982) (Imagic) (PAL)" "Cartridge.Note" "AKA Lost City of Atlantis" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "3d2652cbea462a886a41791dd7c8d073" "Cartridge.Name" "Ritorno dei frattelli di Mario (Mario Bros Hack)" "" "Cartridge.MD5" "3d48b8b586a09bdbf49f1a016bf4d29a" "Cartridge.Manufacturer" "Video Game Cartridge - Ariola" "Cartridge.ModelNo" "TP-606" "Cartridge.Name" "Hole Hunter (Video Game Cartridge)" "Cartridge.Note" "AKA Topy" "" "Cartridge.MD5" "3d6fc7a19be76d808aa233415cb583fc" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-833" "Cartridge.Name" "Target Practice (1983) (CCE)" "Cartridge.Note" "AKA Carnival" "Display.Height" "214" "" "Cartridge.MD5" "3d7749fb9c2f91a276dfe494495234c5" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Checkers (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "3d7aad37c55692814211c8b590a0334c" "Cartridge.Manufacturer" "Atari, Dan Oliver" "Cartridge.Name" "Telepathy (1983) (Atari) (Prototype)" "Cartridge.Note" "Uses both left joystick and right Mindlink controllers (press Fire on respective controller to begin)" "Cartridge.Rarity" "Prototype" "Controller.Right" "MINDLINK" "Controller.MouseAxis" "78" "Display.Height" "215" "" "Cartridge.MD5" "3d8a2d6493123a53ade45e3e2c5cafa0" "Cartridge.Manufacturer" "Atari, Jim Huether - Sears" "Cartridge.ModelNo" "CX2629 - 6-99843, 49-75118" "Cartridge.Name" "Sky Diver (1979) (Atari) (4K)" "" "Cartridge.MD5" "3d934bb980e2e63e1ead3e7756928ccd" "Cartridge.Manufacturer" "Activision, Steve Cartwright - Ariola" "Cartridge.ModelNo" "EAX-017, EAX-017-04I - 711 017-720" "Cartridge.Name" "MegaMania (1982) (Activision) (PAL)" "" "Cartridge.MD5" "3d9c2fccf8b11630762ff00811c19277" "Cartridge.Name" "Challenge of.... Nexar, The (Unknown) (PAL)" "" "Cartridge.MD5" "3da7cc7049d73d34920bb73817bd05a9" "Cartridge.Manufacturer" "Activision, Mike Lorenzen" "Cartridge.ModelNo" "AX-023" "Cartridge.Name" "Oink! (1983) (Activision) (16K)" "" "Cartridge.MD5" "3dfb7c1803f937fadc652a3e95ff7dc6" "Cartridge.Manufacturer" "Dimax - Sinmax" "Cartridge.ModelNo" "SM8001" "Cartridge.Name" "Space Robot (Dimax - Sinmax)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3e03086da53ecc29d855d8edf10962cb" "Cartridge.Manufacturer" "CBS Electronics - Roklan, Joe Gaucher, Alex Leavens" "Cartridge.ModelNo" "4L1751, 4L1752, 4L1753, 4L2275" "Cartridge.Name" "Gorf (1982) (CBS Electronics) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3e1682ddaec486d8b6b90b527aaa0fc4" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Robot City (V0.12) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "3e22c7eaf6459b67388602e4bebbb3a8" "Cartridge.Manufacturer" "CommaVid, John Bronstein - Ariola" "Cartridge.ModelNo" "CM-003 - 712 003-720" "Cartridge.Name" "Cosmic Swarm (1982) (CommaVid) (PAL) (4K)" "Cartridge.Note" "AKA Angriff der Termiten" "" "Cartridge.MD5" "3e33ac10dcf2dff014bc1decf8a9aea4" "Cartridge.Manufacturer" "Spectravideo - Video Games Industries Corporation, Mike Schwartz - Ralston Purina" "Cartridge.Name" "Chase the Chuckwagon (1983) (Spectravideo)" "Display.YStart" "22" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3e49da621193d2611a4ea152d5d5ca3a" "Cartridge.Name" "Atari Logo Demo 3 (PD)" "" "Cartridge.MD5" "3e4b1137433cc1e617b5508619e13063" "Cartridge.Name" "Asteroids (Genesis)" "Cartridge.Note" "Genesis controller (C is hyperspace)" "Cartridge.Rarity" "Hack of Asteroids" "Controller.Left" "GENESIS" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3e5ca1afaa27c5da3c54c9942fec528b" "Cartridge.Name" "2600 Digital Clock (Demo 2) (PD)" "" "Cartridge.MD5" "3e6dab92009d6034618cb6b7844c5216" "Cartridge.Name" "Ed Invaders (Hack)" "Cartridge.Note" "Hack of Pepsi Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "3e7d10d0a911afc4b492d06c99863e65" "Cartridge.Manufacturer" "VGS" "Cartridge.Name" "Super Tenis (VGS)" "Cartridge.Note" "AKA RealSports Tennis" "" "Cartridge.MD5" "3e88cca5b860d0bd8947479e74c44284" "Cartridge.Manufacturer" "Atari, Lou Harp" "Cartridge.ModelNo" "CX26122" "Cartridge.Name" "Sinistar (01-23-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "3e899eba0ca8cd2972da1ae5479b4f0d" "Cartridge.Manufacturer" "Coleco, Joseph Biel" "Cartridge.ModelNo" "2457" "Cartridge.Name" "Venture (1982) (Coleco)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3e90cf23106f2e08b2781e41299de556" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-018, AX-018-04" "Cartridge.Name" "Pitfall! (1982) (Activision)" "Cartridge.Note" "Pitfall Harry's Jungle Adventure (Jungle Runner)" "" "Cartridge.MD5" "3eae062a9b722bda1255d474a87eca5c" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX2605, CX2605P" "Cartridge.Name" "Outlaw (1978) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "3eb1e34a4f0eec36f12e7336badcecf2" "Cartridge.Manufacturer" "Jake Patterson" "Cartridge.Name" "Baubles (V0.001) (2001) (Jake Patterson) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "3eb21313ea5d5764c5ed9160a5a55a83" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AX-012, CAX-012, AX-012-04" "Cartridge.Name" "Ice Hockey (1981) (Activision) (8K)" "" "Cartridge.MD5" "3ec12372ca3e870b11ca70edc7ec26a4" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-002" "Cartridge.Name" "Video Life (1981) (CommaVid) (4K)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3eccf9f363f5c5de0c8b174a535dc83b" "Cartridge.Name" "Plaque Attack (Unknown) (PAL)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "3ef9573536730dcd6d9c20b6822dbdc4" "Cartridge.Manufacturer" "Atari, Larry Wagner, Bob Whitehead" "Cartridge.ModelNo" "CX2645, CX2645P" "Cartridge.Name" "Video Chess (1979) (Atari) (PAL)" "Cartridge.Note" "AKA Computer Chess" "" "Cartridge.MD5" "3f01bd6d059396f495a4cde7de0ab180" "Cartridge.Name" "Qb (Special Edition) (NTSC) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "3f039981255691d3859d04ef813a1264" "Cartridge.Manufacturer" "Xonox, John Perkins" "Cartridge.ModelNo" "6230, 7210, 06004, 99004" "Cartridge.Name" "Artillery Duel (1983) (Xonox) [a]" "Cartridge.Rarity" "Extremely Rare" "Display.YStart" "20" "" "Cartridge.MD5" "3f251c50aa7237e61a38ab42315ebed4" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Ikari Warriors (1990) (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "3f3ad2765c874ca13c015ca6a44a40a1" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-862" "Cartridge.Name" "Crackpots (1983) (CCE)" "" "Cartridge.MD5" "3f540a30fdee0b20aed7288e4a5ea528" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2670" "Cartridge.Name" "Atari Video Cube (1983) (Atari)" "Cartridge.Note" "AKA Atari Cube, Video Cube" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "3f58f972276d1e4e0e09582521ed7a5b" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "6082 A145" "Cartridge.Name" "Kung Fu Superkicks (1988) (Telegames)" "Cartridge.Note" "AKA Chuck Norris Superkicks" "" "Cartridge.MD5" "3f5a43602f960ede330cd2f43a25139e" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-003" "Cartridge.Name" "Checkers (1980) (Activision)" "" "Cartridge.MD5" "3f6938aa6ce66e6f42e582c1eb19b18c" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Laser Blast (Jone Yuan) (4K) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "Display.YStart" "30" "" "Cartridge.MD5" "3f6dbf448f25e2bd06dea44248eb122d" "Cartridge.ModelNo" "5687 A279" "Cartridge.Name" "Soccer (1988) (Telegames)" "Cartridge.Note" "AKA International Soccer" "" "Cartridge.MD5" "3f75a5da3e40d486b21dfc1c8517adc0" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Sky Diver (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "3f9431cc8c5e2f220b2ac14bbc8231f4" "Cartridge.Name" "Colors Demo (PD)" "" "Cartridge.MD5" "3f96eb711928a6fac667c04ecd41f59f" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP218" "Cartridge.Name" "Rodeo Champ (4 Game in One Dark Green) (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA Stampede" "" "Cartridge.MD5" "3f9cb1aba8ec20e2c243ae642f9942bf" "Cartridge.Name" "New Questions (1998) (John K. Harvey) (PD)" "" "Cartridge.MD5" "3fd1f9d66a418c9f787fc5799174ddb7" "Cartridge.Manufacturer" "Aaron Curtis" "Cartridge.Name" "AStar (PAL)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "3fd53bfeee39064c945a769f17815a7f" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Sea Hawk (CCE)" "Cartridge.Note" "AKA Seahawk" "" "Cartridge.MD5" "3fe43915e5655cf69485364e9f464097" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-863" "Cartridge.Name" "Fisher Price (1983) (CCE)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "3ff5165378213dab531ffa4f1a41ae45" "Cartridge.Manufacturer" "Otto Versand" "Cartridge.ModelNo" "311377" "Cartridge.Name" "Pygmy (1983) (Otto Versand) (PAL)" "Cartridge.Note" "AKA Lock 'n' Chase (Double-Game Package)" "" "Cartridge.MD5" "402b1ca3c230a60fb279d4a2a10fa677" "Cartridge.Name" "3-D Tic-Tac-Toe (Unknown) (PAL) (4K)" "Display.YStart" "62" "" "Cartridge.MD5" "402d876ec4a73f9e3133f8f7f7992a1e" "Cartridge.Manufacturer" "Alex Herbert" "Cartridge.Name" "Man Goes Down (2006) (A. Herbert) (Prototype)" "Cartridge.Note" "Uses AtariVox controller" "Cartridge.Rarity" "Homebrew" "Controller.Right" "ATARIVOX" "" "Cartridge.MD5" "405f8591b6941cff56c9b392c2d5e4e5" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Star Strike (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "4066309eb3fa3e7a725585b9814bc375" "Cartridge.Name" "Multi Ball Demo (PD)" "" "Cartridge.MD5" "4066d7d88ec4a2c656127a67fa52dcf1" "Cartridge.Name" "Overhead Adventure Demo 2 (PD)" "Display.YStart" "64" "" "Cartridge.MD5" "407a0c6cc0ff777f67b669440d68a242" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Alpha) (PAL) (31-08-2002) (Erik Eid)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "4093382187f8387e6d011883e8ea519b" "Cartridge.Name" "Go Go Home (Unknown)" "Display.Height" "220" "" "Cartridge.MD5" "40aa851e8d0f1c555176a5e209a5fabb" "Cartridge.Name" "Euchre (More for less) (NTSC) (22-08-2002) (Erik Eid)" "" "Cartridge.MD5" "40b1832177c63ebf81e6c5b61aaffd3a" "Cartridge.Manufacturer" "Atari, Peter C. Niday" "Cartridge.Name" "Rubik's Cube 3-D (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "40b59249e05135bca33861e383735e9e" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Skiing (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "40d7ccd460c9b1198238af6ceea1737d" "Cartridge.Name" "Star Fire - Enemy Mine (2002) (MP)" "" "Cartridge.MD5" "40d8ed6a5106245aa79f05642a961485" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Beck-Tech, Steve Beck" "Cartridge.ModelNo" "6210, 06002, 06004, 99002" "Cartridge.Name" "Ghost Manor (1983) (Xonox) (PAL)" "Display.YStart" "30" "" "Cartridge.MD5" "40d9f5709877ecf3dd1184f9791dd35e" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Skiing (Dactari - Milmar)" "" "Cartridge.MD5" "40e12c008037a323a1290c8fa4d2fe7f" "Cartridge.Name" "Skeleton (NTSC) (06-09-2002) (Eric Ball)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "40eb4e263581b3dfec6dd8920b68e00f" "Cartridge.Manufacturer" "Sears Tele-Games, Marilyn Churchill, Matthew L. Hubbard" "Cartridge.ModelNo" "CX2647 - 49-75142" "Cartridge.Name" "Seawolf 3 (03-23-1981) (Sears) (Prototype) (PAL)" "Cartridge.Note" "Submarine Commander Beta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "413c925c5fdcea62842a63a4c671a5f2" "Cartridge.Manufacturer" "Activision, Larry Kaplan" "Cartridge.ModelNo" "AX-006" "Cartridge.Name" "Bridge (1980) (Activision) [fixed]" "" "Cartridge.MD5" "4153dd2beed648e9dc082140ebe8e836" "Cartridge.Name" "Coke Zero (v1.0) (NTSC)" "Display.YStart" "28" "" "Cartridge.MD5" "415c11fcac66bbd2ace2096687774b5a" "Cartridge.Name" "Fu Kung! (V0.00) (07-01-2003) (AD)" "" "Cartridge.MD5" "4181087389a79c7f59611fb51c263137" "Cartridge.Manufacturer" "Atari, Suki Lee" "Cartridge.ModelNo" "CX26113" "Cartridge.Name" "Miss Piggy's Wedding (06-24-1983) (Atari) (Prototype) (8K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "41810dd94bd0de1110bedc5092bef5b0" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Dragon Treasure (Funvision)" "Cartridge.Note" "AKA Dragonfire" "" "Cartridge.MD5" "41818738ab1745e879024a17784d71f5" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-832" "Cartridge.Name" "Atlantis (1983) (CCE)" "" "Cartridge.MD5" "4189adfc1b30c121248876e3a1a3ac7e" "Cartridge.Manufacturer" "Eric Ball" "Cartridge.Name" "Skeleton (Complete) (06-09-2002) (Eric Ball)" "Cartridge.Rarity" "New Release" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "4191b671bcd8237fc8e297b4947f2990" "Cartridge.Manufacturer" "Exus Corporation" "Cartridge.Name" "Video Jogger (1983) (Exus)" "Cartridge.Note" "AKA Foot Craz" "" "Cartridge.MD5" "41c4e3d45a06df9d21b7aae6ae7e9912" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-826" "Cartridge.Name" "Grand Prix (1983) (CCE)" "" "Cartridge.MD5" "41f252a66c6301f1e8ab3612c19bc5d4" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Brad Rice" "Cartridge.ModelNo" "CX2681" "Cartridge.Name" "Battlezone (1983) (Atari)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "4209e9dcdf05614e290167a1c033cfd2" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-002" "Cartridge.Name" "Video Life (1984) (CommaVid) [higher sounds]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "42249ec8043a9a0203dde0b5bb46d8c4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Resgate Espacial (CCE)" "Cartridge.Note" "AKA Moonsweeper" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4233eb824c2b4811abef9b6d00355ae9" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.10) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4251b4557ea6953e88afb22a3a868724" "Cartridge.Name" "Robot City (V1.1) (TJ)" "" "Cartridge.MD5" "425ee444a41d218598893d6b6e03431a" "Cartridge.Name" "Invaders Demo (2001) (TJ)" "" "Cartridge.MD5" "4279485e922b34f127a88904b31ce9fa" "Cartridge.Name" "Enduro (Unknown)" "" "Cartridge.MD5" "428b2d36f5d716765460701f7016ac91" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Brooni (2001) (Andrew Wallace) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "42ae81ae8ac51e5c238639f9f77d91ae" "Cartridge.Name" "Multi-Sprite Demo 2 (Piero Cavina) (PD)" "" "Cartridge.MD5" "42b2c3b4545f1499a083cfbc4a3b7640" "Cartridge.Manufacturer" "U.S. Games Corporation - JWDA, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV" "Cartridge.ModelNo" "VC2003" "Cartridge.Name" "Eggomania (1982) (U.S. Games)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 60" "Display.YStart" "26" "" "Cartridge.MD5" "42b3ab3cf661929bdc77b621a8c37574" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Volleyball (Robby)" "Cartridge.Note" "AKA RealSports Volleyball" "" "Cartridge.MD5" "42b5e3a35b032f033809afb0ea28802d" "Cartridge.Manufacturer" "Atari, Mimi Nyden, Scott Smith, Robert Vieira" "Cartridge.ModelNo" "CX26127" "Cartridge.Name" "Gremlins (03-12-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "42cdd6a9e42a3639e190722b8ea3fc51" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-007, CAG-007" "Cartridge.Name" "Tennis (1981) (Activision)" "" "Cartridge.MD5" "42dcc02777b0bcfacd85aeb61d33558a" "Cartridge.Name" "Human Cannonball (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "42e0ec5ab8f5deba53e4169ff2a5efbe" "Cartridge.Name" "Atari Logo Demo 5 (PD)" "" "Cartridge.MD5" "4311a4115fb7bc68477c96cf44cebacf" "Cartridge.Name" "Challenge (Unknown)" "Display.YStart" "14" "Display.Height" "240" "" "Cartridge.MD5" "4326edb70ff20d0ee5ba58fa5cb09d60" "Cartridge.Manufacturer" "Atari - GCC, Kevin Osborn" "Cartridge.ModelNo" "CX2689" "Cartridge.Name" "Kangaroo (1983) (Atari)" "" "Cartridge.MD5" "435fd469f088468c4d66be6b5204d887" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680, CX2680P" "Cartridge.Name" "RealSports Tennis (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "438968a26b7cfe14a499f5bbbbf844db" "Cartridge.Name" "Raft Rider (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "43adf60ebdd6b5a0fae21594ecf17154" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Stampede (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "43c6cfffeddab6b3787357fed9d44529" "Cartridge.Manufacturer" "20th Century Fox Video Games, Frank Cohen, Douglas 'Dallas North' Neubauer" "Cartridge.ModelNo" "11111" "Cartridge.Name" "M.A.S.H (1983) (20th Century Fox) (PAL)" "" "Cartridge.MD5" "43e6c5159c3a093fca88656628c6ef34" "Cartridge.Name" "Star Fire (17-02-2003) (MP)" "" "Cartridge.MD5" "43f33c6dfdeaf5138ce6e6968ad7c5ce" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 11 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "43f8459d39fb4eddf9186d62722ff795" "Cartridge.Name" "Skeleton+ (17-04-2003) (Eric Ball) (PAL)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "442602713cb45b9321ee93c6ea28a5d0" "Cartridge.Name" "Demon Attack (Unknown) (PAL)" "" "Cartridge.MD5" "442b7863683e5f084716fda050474feb" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Frame Timed Sound Effects-EM (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "4431428a7500c96fc0e2798a5dbd36d6" "Cartridge.Name" "Kangaroo (Genesis)" "Cartridge.Note" "Genesis controller (B is punch, C is jump)" "Cartridge.Rarity" "Hack of Kangaroo" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "44560e324ffb30741a483218ba5b4342" "Cartridge.Name" "Star Fire - Faster Skipping 2 (24-10-2002) (MP)" "" "Cartridge.MD5" "4474b3ad3bf6aabe719a2d7f1d1fb4cc" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "EAX-039-04B, EAX-039-04I" "Cartridge.Name" "Kung-Fu Master (1987) (Activision) (PAL)" "" "Cartridge.MD5" "4476c39736090dabac09f6caf835fc49" "Cartridge.Name" "Text Screen (25-01-2003) (AD)" "" "Cartridge.MD5" "448c2a175afc8df174d6ff4cce12c794" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AB-035-04" "Cartridge.Name" "Pitfall II (1983) (Activision) [a2]" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "44e9c4a047c348dbeb7ace60f45484b4" "Cartridge.Name" "Moon Patrol Arcade (Genesis)" "Cartridge.Note" "Genesis controller (C is jump)" "Cartridge.Rarity" "Hack of Moon Patrol" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "44f71e70b89dcc7cf39dfd622cfb9a27" "Cartridge.Manufacturer" "Tigervision, Robert H. O'Neil" "Cartridge.ModelNo" "7-007" "Cartridge.Name" "Polaris (1983) (Tigervision)" "" "Cartridge.MD5" "45027dde2be5bdd0cab522b80632717d" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite" "Cartridge.ModelNo" "80561-00250" "Cartridge.Name" "Summer Games (1987) (Epyx)" "" "Cartridge.MD5" "45040679d72b101189c298a864a5b5ba" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius Software, David Lubar" "Cartridge.ModelNo" "11022" "Cartridge.Name" "SpaceMaster X-7 (1983) (20th Century Fox)" "" "Cartridge.MD5" "4543b7691914dfd69c3755a5287a95e1" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines" "Cartridge.ModelNo" "CM-005" "Cartridge.Name" "Mines of Minos (1982) (CommaVid)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "456453a54ca65191781aef316343ae00" "Cartridge.Name" "Full Screen Bitmap (3-D Green) (PD)" "" "Cartridge.MD5" "4565c1a7abce773e53c75b35414adefd" "Cartridge.Manufacturer" "Arcadia Corporation" "Cartridge.Name" "Supercharger BIOS (1982) (Arcadia)" "" "Cartridge.MD5" "457b03cd48ff6d895795ef043c6b0f1e" "Cartridge.Manufacturer" "AtariAge, Chris Spry" "Cartridge.ModelNo" "CX26201" "Cartridge.Name" "Zippy the Porcupine (2014) (Sprybug)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "457e7d4fcd56ebc47f5925dbea3ee427" "Cartridge.Manufacturer" "Carrere Video - JWDA, Garry Kitchen - Teldec - Prism" "Cartridge.ModelNo" "USC1001" "Cartridge.Name" "Space Jockey (1983) (Carrere Video) (PAL)" "" "Cartridge.MD5" "457f4ad2cda5f4803f122508bfbde3f5" "Cartridge.Name" "Canyon Bomber (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "458883f1d952cd772cf0057abca57497" "Cartridge.Name" "Fishing Derby (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "45a095645696a217e416e4bd2baea723" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Snoopy (Digivision)" "Cartridge.Note" "AKA Snoopy and the Red Baron" "" "Cartridge.MD5" "45a4f55bb9a5083d470ad479afd8bca2" "Cartridge.Manufacturer" "CommaVid, Joseph Biel" "Cartridge.Name" "Frog Demo (1983) (CommaVid)" "" "Cartridge.MD5" "45beef9da1a7e45f37f3f445f769a0b3" "Cartridge.Manufacturer" "Atari, Suki Lee" "Cartridge.ModelNo" "CX2658" "Cartridge.Name" "Math Gran Prix (1982) (Atari) (PAL)" "" "Cartridge.MD5" "45c4413dd703b9cfea49a13709d560eb" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Challenge of.... Nexar, The (Jone Yuan) (Hack)" "Cartridge.Note" "Hack" "" "Cartridge.MD5" "45cb0f41774b78def53331e4c3bf3362" "Cartridge.Manufacturer" "Carrere Video - JWDA, Roger Booth, Sylvia Day, Todd Marshall, Robin McDaniel, Wes Trager, Henry Will IV - Teldec - Prism" "Cartridge.ModelNo" "USC1007" "Cartridge.Name" "Octopus (1983) (Carrere Video) (PAL)" "Cartridge.Note" "AKA Name This Game" "" "Cartridge.MD5" "4605a00f5b44a9cbd5803a7a55de150e" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (07-03-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "461029ab23800833e9645be3e472d470" "Cartridge.Name" "Combat TC (v0.1)" "" "Cartridge.MD5" "46258bd92b1f66f4cb47864d7654f542" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Turmoil (Zellers)" "" "Cartridge.MD5" "463dd4770506e6c0ef993a40c52c47be" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen H. Landrum" "Cartridge.ModelNo" "4 AR-4102" "Cartridge.Name" "Suicide Mission (Preview) (1982) (Arcadia)" "Cartridge.Note" "AKA Meteoroids" "Display.Phosphor" "YES" "" "Cartridge.MD5" "463e66ad98806a49106cffa49c08e2ed" "Cartridge.Name" "Interlace Game Demo (01-09-2002) (Billy Eno)" "" "Cartridge.MD5" "467340a18158649aa5e02a4372dcfccd" "Cartridge.Manufacturer" "Activision, John Van Ryzin - Ariola" "Cartridge.ModelNo" "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720" "Cartridge.Name" "H.E.R.O. (1984) (Activision) (PAL) [a1]" "" "Cartridge.MD5" "4689081b7363721858756fe781cc7713" "Cartridge.Name" "Oystron (V2.6) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "468f2dec984f3d4114ea84f05edf82b6" "Cartridge.Manufacturer" "Tigervision - Teldec" "Cartridge.ModelNo" "7-011 - 3.60015 VG" "Cartridge.Name" "Miner 2049er Volume II (1983) (Tigervision) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4690fdb70c86604bb35da26696818667" "Cartridge.Name" "Euchre (Release Candidate) (NTSC) (28-09-2002) (Erik Eid)" "" "Cartridge.MD5" "469473ff6fed8cc8d65f3c334f963aab" "Cartridge.Manufacturer" "Atari, Bruce Poehlman, Gary Stark" "Cartridge.Name" "Dune (07-10-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "46c021a3e9e2fd00919ca3dd1a6b76d8" "Cartridge.Manufacturer" "Atari, Jim Huether - Sears" "Cartridge.ModelNo" "CX2629 - 6-99843, 49-75118" "Cartridge.Name" "Sky Diver (1979) (Atari)" "" "Cartridge.MD5" "46c43fdcbce8fde3a91ebeafc05b7cbd" "Cartridge.Name" "Invaders Demo (PAL) (2001) (Eckhard Stolberg)" "" "Cartridge.MD5" "46e9428848c9ea71a4d8f91ff81ac9cc" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Astroblast (1988) (Telegames) (PAL)" "Cartridge.Note" "Can also use left joystick" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 55" "" "Cartridge.MD5" "4702d8d9b48a332724af198aeac9e469" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (1983) (Atari) [a]" "" "Cartridge.MD5" "470878b9917ea0348d64b5750af149aa" "Cartridge.Manufacturer" "Atari, Suki Lee - Sears" "Cartridge.ModelNo" "CX2658 - 49-75128" "Cartridge.Name" "Math Gran Prix (1982) (Atari)" "" "Cartridge.MD5" "47464694e9cce07fdbfd096605bf39d4" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "EAK-050-04" "Cartridge.Name" "Double Dragon (1989) (Activision) (PAL) [a]" "" "Cartridge.MD5" "4767356fa0ed3ebe21437b4473d4ee28" "Cartridge.Manufacturer" "Atari, Dan Hitchens, Mimi Nyden" "Cartridge.ModelNo" "CX2685" "Cartridge.Name" "Gravitar (04-12-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "47711c44723da5d67047990157dcb5dd" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Ice Hockey (CCE)" "" "Cartridge.MD5" "47911752bf113a2496dbb66c70c9e70c" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams" "Cartridge.ModelNo" "CX26101" "Cartridge.Name" "Oscar's Trash Race (1984) (Atari) (PAL)" "Cartridge.Note" "Uses the Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "4799a40b6e889370b7ee55c17ba65141" "Cartridge.Manufacturer" "Konami" "Cartridge.ModelNo" "RC 100-X 02" "Cartridge.Name" "Pooyan (1983) (Konami)" "Display.Height" "215" "" "Cartridge.MD5" "47aad247cce2534fd70c412cb483c7e0" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-010" "Cartridge.Name" "Mafia (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Gangster Alley" "" "Cartridge.MD5" "47abfb993ff14f502f88cf988092e055" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Inca Gold (Zellers)" "" "Cartridge.MD5" "47aef18509051bab493589cb2619170b" "Cartridge.Name" "Stell-A-Sketch (Bob Colbert) (PD)" "Cartridge.Note" "Uses Driving, Joystick, or Amiga/Atari ST mouse Controllers" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "47b82d47e491ac7fdb5053a88fccc832" "Cartridge.Manufacturer" "Atari Freak 1, Franklin Cruz" "Cartridge.Name" "Asteroid 2 (Atari Freak 1) (Hack)" "Cartridge.Note" "Hack of Asteroids" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "47bb1c677fe7ba5f376372ae7358e790" "Cartridge.Name" "Star Fire (10-10-2002) (MP)" "" "Cartridge.MD5" "47cd61f83457a0890de381e478f5cf5f" "Cartridge.Manufacturer" "Imagic, Wilfredo Aguilar, Michael Becker, Rob Fulop" "Cartridge.ModelNo" "720111-2A, 13205" "Cartridge.Name" "Fathom (1983) (Imagic) (PAL)" "Cartridge.Note" "AKA Scuba" "Display.Phosphor" "YES" "" "Cartridge.MD5" "481d20ec22e7a63e818d5ef9679d548b" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Freeway Rabbit (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Freeway" "" "Cartridge.MD5" "481f9a742052801cc5f3defb41cb638e" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 4 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "48287a9323a0ae6ab15e671ac2a87598" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Laser Volley (Zellers)" "Cartridge.Note" "AKA Innerspace" "" "Cartridge.MD5" "48411c9ef7e2cef1d6b2bee0e6055c27" "Cartridge.Manufacturer" "Telesys, Don Ruffcorn, Jack Woodman" "Cartridge.ModelNo" "1003" "Cartridge.Name" "Fast Food (1982) (Telesys) (PAL)" "" "Cartridge.MD5" "484b0076816a104875e00467d431c2d2" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26150" "Cartridge.Name" "Q-bert (1987) (Atari)" "" "Cartridge.MD5" "4868a81e1b6031ed66ecd60547e6ec85" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (V2.1) (1-3-98) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "4884b1297500bd1243659e43c7e7579e" "Cartridge.Manufacturer" "Atari - Axlon, Tod Frye" "Cartridge.ModelNo" "CX26178" "Cartridge.Name" "Save Mary! (10-24-1991) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "4892b85c248131d6a42c66a4163a40d0" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Tac-Scan (Canal 3)" "Cartridge.Note" "Uses the Paddle Controllers" "Console.SwapPorts" "YES" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 60" "Display.Height" "215" "" "Cartridge.MD5" "48bcf2c5a8c80f18b24c55db96845472" "Cartridge.Manufacturer" "Activision, John Van Ryzin - Ariola" "Cartridge.ModelNo" "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720" "Cartridge.Name" "H.E.R.O. (1984) (Activision) (PAL) (16K)" "" "Cartridge.MD5" "48e5c4ae4f2d3b62b35a87bca18dc9f5" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "476.774 5" "Cartridge.Name" "Bobby geht nach Hause (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Bobby Is Going Home" "Display.YStart" "42" "" "Cartridge.MD5" "48f18d69799a5f5451a5f0d17876acef" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "GN-070" "Cartridge.Name" "Mysterious Thief, A (1983) (ZiMAG) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4901c05068512828367fde3fb22199fe" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.ModelNo" "720101-2B, IA3200P, EIX-006-04I" "Cartridge.Name" "Demon Attack (1982) (Imagic) (PAL)" "Cartridge.Note" "AKA Death from Above" "" "Cartridge.MD5" "4904a2550759b9b4570e886374f9d092" "Cartridge.Manufacturer" "Parker Brothers, Charlie Heath" "Cartridge.ModelNo" "931506" "Cartridge.Name" "Reactor (1983) (Parker Bros) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "490e3cc59d82f85fae817cdf767ea7a0" "Cartridge.Name" "Berzerk (Unknown) (PAL) [a]" "" "Cartridge.MD5" "490eed07d4691b27f473953fbea6541a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AB-035-04" "Cartridge.Name" "Pitfall II (1983) (Activision) [a]" "" "Cartridge.MD5" "493daaf9fb1ba450eba6b8ed53ffb37d" "Cartridge.Name" "3-D Corridor Demo (27-03-2003) (MP)" "" "Cartridge.MD5" "493de059b32f84ab29cde6213964aeee" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Andrew Fuchs" "Cartridge.ModelNo" "CX26120" "Cartridge.Name" "Stargate (1984) (Atari) (PAL)" "" "Cartridge.MD5" "493e90602a4434b117c91c95e73828d1" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Lock 'n' Chase (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "4947c9de2e28b2f5f3b0c40ce7e56d93" "Cartridge.Name" "3-D Corridor Demo 2 (29-03-2003) (MP)" "" "Cartridge.MD5" "494cda91cc640551b4898c82be058dd9" "Cartridge.Manufacturer" "Andreas Dietrich" "Cartridge.Name" "Donkey Kong VCS (2017) (1.0) (PAL60)" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "49571b26f46620a85f93448359324c28" "Cartridge.Name" "Save Our Ship (Unknown)" "Display.YStart" "37" "" "Cartridge.MD5" "497f3d2970c43e5224be99f75e97cbbb" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-002" "Cartridge.Name" "Video Life (1984) (CommaVid)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4981cefe5493ea512284e7f9f27d1e54" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83136" "Cartridge.Name" "Cosmic War (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Cosmic Corridor" "Display.Height" "256" "" "Cartridge.MD5" "4999b45be0ab5a85bac1b7c0e551542b" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Double Dragon (CCE) (PAL)" "" "Cartridge.MD5" "499b612f6544ae71d4915aa63e403e10" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Checkers (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "4a196713a21ef07a3f74cf51784c6b12" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Frogs and Flies (Jone Yuan) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4a2fe6f0f6317f006fd6d4b34515448b" "Cartridge.Name" "Warring Worms (Midwest Classic Edition) (08-06-2002) (Billy Eno)" "" "Cartridge.MD5" "4a45c6d75b1ba131f94a9c13194d8e46" "Cartridge.Name" "How to Draw a Playfield II (Joystick Hack) (1997) (Eric Bacher) (PD)" "" "Cartridge.MD5" "4a5fddf89801336637ac8e57a7c9a881" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "1125" "Cartridge.Name" "Power Play Arcade Video Game Album IV (1984) (Amiga) (Prototype)" "Cartridge.Note" "Atlantis, Cosmic Ark, Dragonfire" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "4a6be79310f86f0bebc7dfcba4d74161" "Cartridge.Name" "Demolition Herby (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4a7eee19c2dfb6aeb4d9d0a01d37e127" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Crazy Valet (Hozer Video Games)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "4a8c743396b8ad69d97e6fd3dd3e3132" "Cartridge.Manufacturer" "Arcadia Corporation" "Cartridge.Name" "Supercharger BIOS (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "4a9009620038f7f30aaeb2a00ae58fde" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (3 of 3) (1983) (Arcadia)" "" "Cartridge.MD5" "4ab2ebd95a8f861ea451abebdad914a5" "Cartridge.Manufacturer" "Nukey Shay, Thomas Jentzsch" "Cartridge.ModelNo" "PAL conversion (F6)" "Cartridge.Name" "Montezuma's Revenge (PAL) (Genesis)" "Cartridge.Note" "Genesis controller (B jumps left, C jumps right)" "Cartridge.Rarity" "Homebrew" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "4ab4af3adcdae8cdacc3d06084fc8d6a" "Cartridge.Manufacturer" "Nick Bensema" "Cartridge.Name" "Sucky Zepplin (Nick Bensema) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "4abb4c87a4c5f5d0c14ead2bb36251be" "Cartridge.Manufacturer" "Atari - Imagineering, Alex DeMeo" "Cartridge.ModelNo" "CX26135, CX26135P" "Cartridge.Name" "RealSports Boxing (1987) (Atari) (PAL)" "" "Cartridge.MD5" "4ac9f40ddfcf194bd8732a75b3f2f214" "Cartridge.Manufacturer" "Atari - CCW, Stephan R. Keith, Laura Scholl, Preston Stuart" "Cartridge.ModelNo" "CX26106" "Cartridge.Name" "Grover's Music Maker (12-29-1982) (Atari) (Prototype)" "Cartridge.Note" "Uses Keypad Controller" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "" "Cartridge.MD5" "4ae8c76cd6f24a2e181ae874d4d2aa3d" "Cartridge.Name" "Flash Gordon (Unknown) (PAL)" "" "Cartridge.MD5" "4af4103759d603c82b1c9c5acd2d8faf" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "720114-2A, 13207, EIZ-001-04I" "Cartridge.Name" "Moonsweeper (1983) (Imagic) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4afa7f377eae1cafb4265c68f73f2718" "Cartridge.Manufacturer" "Ed Fries" "Cartridge.Name" "Halo 2600 (2010) (Ed Fries)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "4afe528a082f0d008e7319ebd481248d" "Cartridge.Name" "Multi-Color Demo 1 (Bob Colbert) (PD)" "" "Cartridge.MD5" "4b143d7dcf6c96796c37090cba045f4f" "Cartridge.Manufacturer" "Atari, Jim Huether - Sears" "Cartridge.ModelNo" "CX2644 - 6-99824" "Cartridge.Name" "Flag Capture (1978) (Atari) (4K)" "" "Cartridge.MD5" "4b205ef73a5779acc5759bde3f6d33ed" "Cartridge.Name" "Berzerk (Unknown) (PAL)" "" "Cartridge.MD5" "4b27f5397c442d25f0c418ccdacf1926" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX2613, 49-75154" "Cartridge.Name" "Adventure (1980) (Atari) (PAL)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "4b71197153d651480830638cb6a03249" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Bowling (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "4b753a97aee91e4b3e4e02f5e9758c72" "Cartridge.Manufacturer" "Glenn Saunders, Roger Williams" "Cartridge.Name" "Asymmetric Reflected Playfield (Glenn Saunders)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "4b94fd272785d7ec6c95fb7279d0f522" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams" "Cartridge.ModelNo" "CX26101" "Cartridge.Name" "Oscar's Trash Race (12-03-1982) (Atari) (Prototype)" "Cartridge.Note" "Uses the Keypad Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "4b9581c3100a1ef05eac1535d25385aa" "Cartridge.Name" "IQ 180 (Unknown)" "Display.YStart" "20" "Display.Height" "235" "" "Cartridge.MD5" "4baada22435320d185c95b7dd2bcdb24" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Dave Staugas" "Cartridge.ModelNo" "CX2682" "Cartridge.Name" "Krull (1983) (Atari)" "" "Cartridge.MD5" "4bcc7f6ba501a26ee785b7efbfb0fdc8" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn" "Cartridge.ModelNo" "CX2690" "Cartridge.Name" "Pengo (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "4bdae9246d6ee258c26665512c1c8de3" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Human Cannonball (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "4c030667d07d1438f0e5c458a90978d8" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.03) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4c0fb2544ae0f8b5f7ae8bce7bd7f134" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix (Preview) (1983) (Arcadia)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "" "Cartridge.MD5" "4c205f166157154df2f1ef60d87e552f" "Cartridge.Name" "Single-Scanline Positioning Demo 2 (2001) (Roger Williams)" "" "Cartridge.MD5" "4c39a2c97917d3d71739b3e21f60bba5" "Cartridge.Name" "Whale (Sub Scan Hack)" "" "Cartridge.MD5" "4c462b2b6fb0a19a1437eb2c3dc20783" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (1 of 3) (1983) (Arcadia)" "" "Cartridge.MD5" "4c4ce802cbfd160f7b3ec0f13f2a29df" "Cartridge.Name" "Beta Demo (V1.1) (26-09-2002) (MP)" "" "Cartridge.MD5" "4c606235f4ec5d2a4b89139093a69437" "Cartridge.Manufacturer" "Andrew Davies" "Cartridge.Name" "Andrew Davies early notBoulderDash demo (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4c6afb8a44adf8e28f49164c84144bfe" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-806" "Cartridge.Name" "Mission 3,000 A.D. (1983) (CCE)" "" "Cartridge.MD5" "4c8832ed387bbafc055320c05205bc08" "Cartridge.Manufacturer" "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears" "Cartridge.ModelNo" "CX2601 - 99801, 6-99801, 49-75124" "Cartridge.Name" "Combat (1977) (Atari)" "" "Cartridge.MD5" "4c8970f6c294a0a54c9c45e5e8445f93" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson" "Cartridge.ModelNo" "99006, 6220" "Cartridge.Name" "Sir Lancelot (1983) (Xonox)" "" "Cartridge.MD5" "4c9307de724c36fd487af6c99ca078f2" "Cartridge.Manufacturer" "Imagic, Brad Stewart" "Cartridge.ModelNo" "720106-1A, IA3409" "Cartridge.Name" "Sky Patrol (1982) (Imagic) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "4ca0959f846d2beada18ecf29efe137e" "Cartridge.Manufacturer" "Atari, Jim Huether, Alan J. Murphy, Robert C. Polaro" "Cartridge.ModelNo" "CX2666, CX2666P" "Cartridge.Name" "RealSports Volleyball (1982) (Atari) (PAL)" "" "Cartridge.MD5" "4ca73eb959299471788f0b685c3ba0b5" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-031" "Cartridge.Name" "Frostbite (1983) (Activision)" "" "Cartridge.MD5" "4ca90ba45eced6f5ad560ea8938641b2" "Cartridge.Name" "Hangman Man Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4cabc895ea546022c2ecaa5129036634" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Ocean City (Funvision)" "Cartridge.Note" "AKA Atlantis" "" "Cartridge.MD5" "4cd796b5911ed3f1062e805a3df33d98" "Cartridge.Manufacturer" "Tigervision - Software Electronics Corporation - Teldec" "Cartridge.ModelNo" "7-006" "Cartridge.Name" "Springer (1983) (Tigervision)" "Display.Height" "220" "" "Cartridge.MD5" "4d0a28443f7df5f883cf669894164cfa" "Cartridge.Name" "Beast Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4d2cef8f19cafeec72d142e34a1bbc03" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-422" "Cartridge.Name" "2 Pak Special - Star Warrior, Frogger (1990) (HES) (PAL) [a]" "" "Cartridge.MD5" "4d38e1105c3a5f0b3119a805f261fcb5" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP212" "Cartridge.Name" "Phantom UFO (4 Game in One Light Green) (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA Spider Fighter" "" "Cartridge.MD5" "4d502d6fb5b992ee0591569144128f99" "Cartridge.Manufacturer" "Atari - Axlon, Tod Frye" "Cartridge.ModelNo" "CX26178" "Cartridge.Name" "Save Mary! (11-21-1989) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "4d5f6db55f7f44fd0253258e810bde21" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Betterblast (Fabrizio Zavagli) (Hack)" "Cartridge.Note" "Hack of Astroblast" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4d7517ae69f95cfbc053be01312b7dba" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2641 - 99807, 49-75105" "Cartridge.Name" "Surround (1977) (Atari)" "" "Cartridge.MD5" "4d77f291dca1518d7d8e47838695f54b" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1004" "Cartridge.Name" "Airlock (1982) (Data Age)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "4d8396deeabb40b5e8578276eb5a8b6d" "Cartridge.Manufacturer" "Otto Versand" "Cartridge.ModelNo" "781698" "Cartridge.Name" "Volleyball (1983) (Otto Versand) (PAL)" "Cartridge.Note" "AKA RealSports Volleyball (Double-Game Package)" "" "Cartridge.MD5" "4dbf47c7f5ac767a3b07843a530d29a5" "Cartridge.Manufacturer" "Ric Pryor" "Cartridge.Name" "Breaking News (2002) (Ric Pryor) (Hack)" "Cartridge.Note" "Hack of Bump 'n' Jump" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4dcc7e7c2ec0738e26c817b9383091af" "Cartridge.Name" "Unknown Title (bin00026 (200110)) (PD)" "" "Cartridge.MD5" "4dd6c7ab9ef77f2b4950d8fc7cd42ee1" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.04) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4df6124093ccb4f0b6c26a719f4b7706" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2622 - 6-99813, 49-75107" "Cartridge.Name" "Breakout (1978) (Atari) [a]" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 60" "" "Cartridge.MD5" "4df9d7352a56a458abb7961bf10aba4e" "Cartridge.Name" "Racing Car (Unknown)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "4e01d9072c500331e65bb87c24020d3f" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX26119" "Cartridge.Name" "Saboteur (06-15-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "4e02880beeb8dbd4da724a3f33f0971f" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "EIZ-002-04I" "Cartridge.Name" "Wing War (1983) (Imagic) (PAL)" "Cartridge.Note" "AKA Flap!" "" "Cartridge.MD5" "4e15ddfd48bca4f0bf999240c47b49f5" "Cartridge.Manufacturer" "Avalon Hill, Jean Baer, Jim Jacob" "Cartridge.ModelNo" "5001002" "Cartridge.Name" "Death Trap (1983) (Avalon Hill)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4e2c884d04b57b43f23a5a2f4e9d9750" "Cartridge.Name" "Baby Center Animation (PD)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4e37992a37ea36489283f7eb90913bbc" "Cartridge.Manufacturer" "Kris" "Cartridge.Name" "Hangman Ghost Halloween (Kris) (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4e4895c3381aa4220f8c2795d6338237" "Cartridge.Name" "Backwards Cannonball v1 (Hack)" "Cartridge.Note" "Hack of Human Cannonball" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "4e66c8e7c670532569c70d205f615dad" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680, CX2680P" "Cartridge.Name" "RealSports Tennis (1983) (Atari) (PAL)" "" "Cartridge.MD5" "4e86866d9cde738d1630e2e35d7288ce" "Cartridge.Manufacturer" "Supergame" "Cartridge.Name" "River Raid III (Supergame)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "4e99ebd65a967cabf350db54405d577c" "Cartridge.Manufacturer" "Coleco" "Cartridge.ModelNo" "2663" "Cartridge.Name" "Time Pilot (1983) (Coleco) [b1]" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "4eb4fd544805babafc375dcdb8c2a597" "Cartridge.Manufacturer" "Inspirational Video Concepts, Steve Shustack" "Cartridge.ModelNo" "321430" "Cartridge.Name" "Red Sea Crossing (1983) (Inspirational Video Concepts)" "" "Cartridge.MD5" "4edb251f5f287c22efc64b3a2d095504" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Atari VCS Point-of-Purchase ROM (1982) (Atari)" "" "Cartridge.MD5" "4f0071946e80ca68edfdccbac86dcce0" "Cartridge.Name" "Virtual Pet Demo 1 (CRACKERS) (PD)" "" "Cartridge.MD5" "4f2d47792a06da224ba996c489a87939" "Cartridge.Manufacturer" "HES - Activision" "Cartridge.ModelNo" "223" "Cartridge.Name" "Super Action Pak - Pitfall, Barnstorming, Grand Prix, Laser Blast (1988) (HES) (PAL)" "" "Cartridge.MD5" "4f32b24869d8c1310fecf039c6424db6" "Cartridge.Manufacturer" "U.S. Games Corporation - JWDA, Todd Marshall" "Cartridge.Name" "3-D Zapper (12-15-82) (U.S. Games) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "4f618c2429138e0280969193ed6c107e" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AZ-028, AG-028-04" "Cartridge.Name" "Robot Tank (1983) (Activision)" "" "Cartridge.MD5" "4f634893d54e9cabe106e0ec0b7bdcdf" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.14) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4f64d6d0694d9b7a1ed7b0cb0b83e759" "Cartridge.Manufacturer" "20th Century Fox Video Games, John Russell" "Cartridge.ModelNo" "11016" "Cartridge.Name" "Revenge of the Beefsteak Tomatoes (1983) (20th Century Fox)" "Cartridge.Note" "AKA Revenge of the Cherry Tomatoes" "" "Cartridge.MD5" "4f6702c3ba6e0ee2e2868d054b00c064" "Cartridge.Manufacturer" "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen - Ariola" "Cartridge.ModelNo" "EAZ-033 - 711 033-725" "Cartridge.Name" "Space Shuttle (1983) (Activision) (PAL)" "Cartridge.Note" "A Journey Into Space, Eine Reise ins All" "" "Cartridge.MD5" "4f781f0476493c50dc578336f1132a67" "Cartridge.Name" "Indy 500 (Unknown) (PAL) (4K)" "Cartridge.Note" "Uses Driving Controllers" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "Controller.MouseAxis" "45" "" "Cartridge.MD5" "4f7b07ec2bef5ccffe06403a142f80db" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2003" "Cartridge.Name" "Racquetball (1982) (Apollo) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4f82d8d78099dd71e8e169646e799d05" "Cartridge.Name" "Miniature Golf (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "4f89b897444e7c3b36aed469b8836839" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26190" "Cartridge.Name" "BMX Air Master (1989) (Atari) (PAL)" "" "Cartridge.MD5" "4fae08027365d31c558e400b687adf21" "Cartridge.Name" "Qb (V2.17) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "4faeb04b1b7fb0fa25db05753182a898" "Cartridge.Name" "2600 Digital Clock (V x.xx) (PD) [a1]" "" "Cartridge.MD5" "4fbe0f10a6327a76f83f83958c3cbeff" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-816" "Cartridge.Name" "Keystone Kappers (1983) (CCE)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "4fc1b85b8074b4b9436d097900e34f29" "Cartridge.Manufacturer" "John K. Harvey" "Cartridge.Name" "John K. Harvey's Equalizer (John K. Harvey)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "50200f697aeef38a3ce31c4f49739551" "Cartridge.Manufacturer" "Mystique - American Multiple Industries, Joel H. Martin" "Cartridge.Name" "Custer's Revenge (1982) (Mystique) (PAL60)" "Display.Format" "PAL60" "" "Cartridge.MD5" "502044b1ac111b394e6fbb0d821fca41" "Cartridge.Name" "Hangman Invader 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "502168660bfd9c1d2649d415dc89c69d" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAG-019, EAG-019-04I - 711 019-715" "Cartridge.Name" "Sky Jinks (1982) (Activision) (PAL) (4K)" "" "Cartridge.MD5" "504688d49a41bf03d8a955512609f3f2" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "SWOOPS! (TJ)" "Cartridge.Note" "Uses the Joystick (L) and Paddle (R) Controllers" "Cartridge.Rarity" "Homebrew" "Controller.Right" "PADDLES" "Display.YStart" "28" "" "Cartridge.MD5" "50568c80ac61cab789d9923c9b05b68e" "Cartridge.Manufacturer" "Ebivision" "Cartridge.Name" "Merlin's Walls - Standard Edition (1999) (Ebivision)" "Cartridge.Note" "Image rotated 90 degrees CW" "" "Cartridge.MD5" "5069fecbe4706371f17737b0357cfa68" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Steve Stringfellow" "Cartridge.ModelNo" "AP-2005" "Cartridge.Name" "Shark Attack (1982) (Apollo) (PAL)" "Cartridge.Note" "AKA Lochjaw" "" "Cartridge.MD5" "5079bfbc7b8f5770f84215ed2e3bdd1b" "Cartridge.Manufacturer" "Omegamatrix (2012)" "Cartridge.Name" "Genesis Button Tester" "Cartridge.Rarity" "Homebrew" "Controller.Left" "GENESIS" "Controller.Right" "GENESIS" "" "Cartridge.MD5" "50a410a5ded0fc9aa6576be45a04f215" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAG-019, EAG-019-04I - 711 019-715" "Cartridge.Name" "Sky Jinks (1982) (Activision) (PAL)" "" "Cartridge.MD5" "50c7edc9f9dc0369abcdab3b4efeb5e9" "Cartridge.Manufacturer" "U.S. Games Corporation - JWDA, Todd Marshall" "Cartridge.Name" "3-D Zapper (U.S. Games) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "50ef88f9a5e0e1e6b86e175362a27fdb" "Cartridge.Name" "Multi-Sprite Game V2.4 (Piero Cavina) (PD)" "" "Cartridge.MD5" "512e874a240731d7378586a05f28aec6" "Cartridge.Manufacturer" "Tigervision, Rorke Weigandt - Teldec" "Cartridge.ModelNo" "7-005" "Cartridge.Name" "Marauder (1982) (Tigervision) (PAL)" "" "Cartridge.MD5" "5131ab3797fe8c127e3e135b18b4d2c8" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-004" "Cartridge.Name" "Fishing Derby (1980) (Activision) (8K)" "" "Cartridge.MD5" "514f911ecff2be5eeff2f39c49a9725c" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "931510" "Cartridge.Name" "Sky Skipper (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "515046e3061b7b18aa3a551c3ae12673" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692" "Cartridge.Name" "Moon Patrol (1983) (Atari)" "" "Cartridge.MD5" "516ffd008057a1d78d007c851e6eff37" "Cartridge.Manufacturer" "Parker Brothers, Dawn Stockbridge" "Cartridge.ModelNo" "PB5910" "Cartridge.Name" "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "517592e6e0c71731019c0cebc2ce044f" "Cartridge.Manufacturer" "Parker Brothers - JWDA, Todd Marshall" "Cartridge.ModelNo" "PB5550" "Cartridge.Name" "Q-bert's Qubes (1984) (Parker Bros)" "Display.YStart" "30" "Display.Height" "214" "" "Cartridge.MD5" "517923e655755086a3b72c0b17b430e6" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Super Tennis (Tron)" "Cartridge.Note" "AKA RealSports Tennis" "" "Cartridge.MD5" "5188fee071d3c5ef0d66fb45c123e4a5" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-001" "Cartridge.Name" "Encounter at L-5 (1983) (Gameworld) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 50" "" "Cartridge.MD5" "519f007c0e14fb90208dbb5199dfb604" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.Name" "Depth Charge (1983) (Amiga) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "51de328e79d919d7234cf19c1cd77fbc" "Cartridge.Manufacturer" "Atari, Mark R. Hahn" "Cartridge.ModelNo" "CX2678" "Cartridge.Name" "Dukes of Hazzard (1983) (Atari)" "" "Cartridge.MD5" "51e390424f20e468d2b480030ce95d7b" "Cartridge.Manufacturer" "Video Game Program" "Cartridge.Name" "Fire Bird (Video Game Program) (PAL)" "Cartridge.Note" "AKA Phoenix" "" "Cartridge.MD5" "51f15b39d9f502c2361b6ba6a73464d4" "Cartridge.Name" "Amanda Invaders (PD) [a]" "" "Cartridge.MD5" "51f211c8fc879391fee26edfa7d3f11c" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AX-015, AX-015-04" "Cartridge.Name" "Chopper Command (1982) (Activision) (8K)" "" "Cartridge.MD5" "521f4dd1eb84a09b2b19959a41839aad" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG206" "Cartridge.Name" "Bobby Is Going Home (1983) (BitCorp)" "Cartridge.Note" "AKA Bobby geht Heim" "" "Cartridge.MD5" "522c9cf684ecd72db2f85053e6f6f720" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-008" "Cartridge.Name" "Year 1999, The (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Condor Attack" "" "Cartridge.MD5" "52385334ac9e9b713e13ffa4cc5cb940" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-804" "Cartridge.Name" "Open, Sesame! (1983) (CCE)" "Cartridge.Note" "AKA I Want My Mommy" "Display.Height" "214" "Display.Phosphor" "YES" "" "Cartridge.MD5" "523f5cbb992f121e2d100f0f9965e33f" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide (1.30) (CGE 2001 Release) (Joe Grand)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "AUTO 65" "" "Cartridge.MD5" "524693b337f7ecc9e8b9126e04a232af" "Cartridge.Name" "Euchre (19-08-2001) (Eric Eid) (PD)" "" "Cartridge.MD5" "5256f68d1491986aae5cfdff539bfeb5" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692" "Cartridge.Name" "Moon Patrol (07-26-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "525ea747d746f3e80e3027720e1fa7ac" "Cartridge.Manufacturer" "Activision, Garry Kitchen - Ariola" "Cartridge.ModelNo" "EAZ-032 - 771 032-712" "Cartridge.Name" "Pressure Cooker (1983) (Activision) (PAL)" "" "Cartridge.MD5" "525f2dfc8b21b0186cff2568e0509bfc" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-930-04, AZ-030" "Cartridge.Name" "Decathlon (1983) (Activision) [fixed]" "" "Cartridge.MD5" "52615ae358a68de6e76467e95eb404c7" "Cartridge.Name" "DJdsl-wopd (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "528400fad9a77fd5ad7fc5fdc2b7d69d" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum, Jon Leupp" "Cartridge.ModelNo" "11 AR-4201" "Cartridge.Name" "Sword of Saros (1983) (Starpath)" "" "Cartridge.MD5" "52a0003efb3b1c49fcde4dbc2c685d8f" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2641 - 99807, 49-75105" "Cartridge.Name" "Surround (1977) (Atari) (4K) [a]" "Cartridge.Type" "2K" "" "Cartridge.MD5" "52b448757081fd9fabf859f4e2f91f6b" "Cartridge.Name" "Worm War I (Unknown) (PAL)" "" "Cartridge.MD5" "52bae1726d2d7a531c9ca81e25377fc3" "Cartridge.Name" "Space Instigators (V1.8 Fixed) (20-10-2002) (CT)" "" "Cartridge.MD5" "52e1954dc01454c03a336b30c390fb8d" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.14) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "52e9db3fe8b5d336843acac234aaea79" "Cartridge.Name" "Fu Kung! (V0.11) (28-01-2003) (AD)" "" "Cartridge.MD5" "5305f69fbf772fac4760cdcf87f1ab1f" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Ski Run (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "5324cf5b6dc17af4c64bf8696c39c2c1" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "IA3203, IX-010-04" "Cartridge.Name" "Atlantis (1982) (Imagic) (8K)" "Cartridge.Note" "AKA Lost City of Atlantis" "" "Cartridge.MD5" "5336f86f6b982cc925532f2e80aa1e17" "Cartridge.Manufacturer" "Parker Brothers - JWDA, Todd Marshall, Robin McDaniel, Ray Miller" "Cartridge.ModelNo" "PB5060" "Cartridge.Name" "Star Wars - Death Star Battle (1983) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "534e23210dd1993c828d944c6ac4d9fb" "Cartridge.Manufacturer" "M Network, Stephen Tatsumi, Jane Terjung - Kool Aid" "Cartridge.ModelNo" "MT4648" "Cartridge.Name" "Kool-Aid Man (1983) (M Network)" "Cartridge.Note" "AKA Kool Aid Pitcher Man" "" "Cartridge.MD5" "5355f80cacf0e63a49cbf4ade4e27034" "Cartridge.Manufacturer" "Christian Samuel" "Cartridge.Name" "Cute Dead Things House (Christian Samuel) (Hack)" "Cartridge.Note" "Hack of Haunted House" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "5360693f1eb90856176bd1c0a7b17432" "Cartridge.Name" "Oystron (V2.85) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "537ed1e0d80e6c9f752b33ea7acbe079" "Cartridge.Name" "A-VCS-tec Challenge (beta 5) (PD)" "" "Cartridge.MD5" "5385cf2a04de1d36ab55c73174b84db0" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Combat Rock (PD) (Hack)" "Cartridge.Note" "Hack of Combat" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "539b7038acec0ccedeae40f238998579" "Cartridge.Name" "Star Fire (25-10-2002) (MP)" "" "Cartridge.MD5" "539d26b6e9df0da8e7465f0f5ad863b7" "Cartridge.Manufacturer" "Atari, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2636 - 49-75156" "Cartridge.Name" "Video Checkers (1980) (Atari)" "" "Cartridge.MD5" "53b66f11f67c3b53b2995e0e02017bd7" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1005" "Cartridge.Name" "Super Tennis (1983) (CCE)" "Cartridge.Note" "AKA RealSports Tennis" "" "Cartridge.MD5" "53d181cde2e0219b5754caad246fcb66" "Cartridge.Name" "Missile Demo (1998) (Ruffin Bailey) (PD)" "" "Cartridge.MD5" "53f147b9746fdc997c62f3dd67888ee5" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-011" "Cartridge.Name" "Stampede (1981) (Activision) (8K)" "" "Cartridge.MD5" "540075f657d4b244a1f74da1b9e4bf92" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP230" "Cartridge.Name" "Festival (4 Game in One Dark Green) (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA Carnival" "" "Cartridge.MD5" "5409d20c1aea0b89c56993aec5dc5740" "Cartridge.Name" "Carnival Shooter (PD)" "" "Cartridge.MD5" "5428cdfada281c569c74c7308c7f2c26" "Cartridge.Manufacturer" "Activision, Larry Kaplan, David Crane" "Cartridge.ModelNo" "AG-010, AG-010-04" "Cartridge.Name" "Kaboom! (1981) (Activision)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "542c6dd5f7280179b51917a4cba4faff" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "GN-080" "Cartridge.Name" "Spinning Fireball (1983) (ZiMAG) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5438e84b90e50a5362f01cc843b358d4" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "3 AR-4300" "Cartridge.Name" "Fireball (1982) (Arcadia) (Prototype)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "543b4b8ff1d616fa250c648be428a75c" "Cartridge.Manufacturer" "Warren Robinett" "Cartridge.Name" "Adventure (1978) (Warren Robinett) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "545048ccb045f9efc6cf2b125cd0dfa8" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum, Jon Leupp" "Cartridge.ModelNo" "AR-4201" "Cartridge.Name" "Sword of Saros (1983) (Arcadia) [a]" "" "Cartridge.MD5" "54785fa29e28aae6038929ba29d33d38" "Cartridge.Name" "Poker Squares (V0.19) (2001) (B. Watson)" "" "Cartridge.MD5" "5494b9ee403d9757f0fd1f749e80214a" "Cartridge.Manufacturer" "Larry Petit" "Cartridge.Name" "Xenophobe Arcade (2003) (Larry Petit) (Hack)" "Cartridge.Note" "Hack of Xenophobe" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "54a1c1255ed45eb8f71414dadb1cf669" "Cartridge.Manufacturer" "Spectravideo" "Cartridge.ModelNo" "SA-212" "Cartridge.Name" "Mangia' (1983) (Spectravideo)" "" "Cartridge.MD5" "54bafc299423f5a50b8bc3a797914706" "Cartridge.Manufacturer" "SOLID Corp. (D. Scott Williamson)" "Cartridge.ModelNo" "CX2655*" "Cartridge.Name" "Star Castle 2600 (SolidCorp) (PAL)" "Cartridge.Note" "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "54da3b0b3f43f5b37911c135b9432b49" "Cartridge.Name" "Halloween III Revision (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "54f7efa6428f14b9f610ad0ca757e26c" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Steve Stringfellow" "Cartridge.ModelNo" "AP-2005" "Cartridge.Name" "Shark Attack (1982) (Apollo)" "Cartridge.Note" "AKA Lochjaw" "" "Cartridge.MD5" "551a64a945d7d6ece81e9c1047acedbc" "Cartridge.Manufacturer" "Matthias Jaap" "Cartridge.Name" "Coffee Cup Soccer (Matthias Jaap) (Hack)" "Cartridge.Note" "Hack of Pele's Soccer" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "551ef75593ec18d078e8f5cc0229e1c4" "Cartridge.Name" "Star Fire - New Paulstar WIP (MP)" "" "Cartridge.MD5" "5524718a19107a04ec3265c93136a7b5" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "RealSports Basketball (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "557e893616648c37a27aab5a47acbf10" "Cartridge.Manufacturer" "Atari - Axlon, Tod Frye - Heuristica, Augustin Ortiz" "Cartridge.ModelNo" "CX26169" "Cartridge.Name" "Shooting Arcade (01-16-1990) (Atari) (Prototype) (PAL)" "Cartridge.Note" "Uses the Light Gun Controller (left only)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "559317712f989f097ea464517f1a8318" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "100" "Cartridge.Name" "Space Canyon (1983) (Panda)" "Cartridge.Note" "AKA Space Cavern" "" "Cartridge.MD5" "55949cb7884f9db0f8dfcf8707c7e5cb" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2639 - 49-75162" "Cartridge.Name" "Othello (1981) (Atari)" "" "Cartridge.MD5" "55ace3c775f42eb46f08bb1dca9114e7" "Cartridge.Name" "Shadow Keep (04-03-2003) (Andrew Towers)" "" "Cartridge.MD5" "55ef6ab2321ca0c3d369e63d59c059c8" "Cartridge.Name" "Pitfall! (Unknown) (PAL)" "" "Cartridge.MD5" "55ef7b65066428367844342ed59f956c" "Cartridge.Manufacturer" "Atari - Roklan, Joe Gaucher, Alex Leavens" "Cartridge.ModelNo" "CX2683" "Cartridge.Name" "Crazy Climber (1983) (Atari)" "" "Cartridge.MD5" "562acb1b7ff182aba133bda8e21ad7c1" "Cartridge.Name" "Space Treat Deluxe (08-03-2003) (Fabrizio Zavagli)" "" "Cartridge.MD5" "562bf02f5031d51c6b53b03972a56b22" "Cartridge.Name" "Star Fire - Framework Done (30-10-2002) (MP)" "" "Cartridge.MD5" "56300ed31fef018bd96768ccc982f7b4" "Cartridge.Manufacturer" "HES - Activision" "Cartridge.ModelNo" "559" "Cartridge.Name" "Rad Action Pak - Kung-Fu Master, Freeway, Frostbite (1990) (HES) (PAL)" "" "Cartridge.MD5" "5641c0ff707630d2dd829b26a9f2e98f" "Cartridge.Manufacturer" "Joystik" "Cartridge.Name" "Motocross (Joystik)" "Cartridge.Note" "AKA Motocross Racer" "" "Cartridge.MD5" "5643ee916f7dc760148fca4db3aa7d10" "Cartridge.Name" "Moon Patrol (Genesis)" "Cartridge.Note" "Genesis controller (C is jump)" "Cartridge.Rarity" "Hack of Moon Patrol" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "5678ebaa09ca3b699516dba4671643ed" "Cartridge.Manufacturer" "Coleco, Sylvia Day, Henry Will IV" "Cartridge.ModelNo" "2459" "Cartridge.Name" "Mouse Trap (1982) (Coleco)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "568371fbae6f5e5b936af80031cd8888" "Cartridge.Name" "Robotfindskitten2600 (26-04-2003) (Jeremy Penner)" "" "Cartridge.MD5" "571c6d9bc71cb97617422851f787f8fe" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAG-004, PAG-004 - 711 004-715" "Cartridge.Name" "Fishing Derby (1980) (Activision) (PAL)" "Cartridge.Note" "AKA Schneller als der Hai" "" "Cartridge.MD5" "572d0a4633d6a9407d3ba83083536e0f" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Busy Police (Funvision)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "575c0fb61e66a31d982c95c9dea6865c" "Cartridge.Name" "Blackjack (Unknown) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "" "Cartridge.MD5" "57939b326df86b74ca6404f64f89fce9" "Cartridge.Manufacturer" "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX26111" "Cartridge.Name" "Snoopy and the Red Baron (1983) (Atari)" "" "Cartridge.MD5" "579baa6a4aa44f035d245908ea7a044d" "Cartridge.Manufacturer" "Jess Ragan" "Cartridge.Name" "Galaxian Enhanced Graphics (Jess Ragan) (Hack)" "Cartridge.Note" "Hack of Galaxian" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "57a66b6db7efc5df17b0b0f2f2c2f078" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.08) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "57c5b351d4de021785cf8ed8191a195c" "Cartridge.Manufacturer" "Atari - CCW, Gary Stark" "Cartridge.ModelNo" "CX26102" "Cartridge.Name" "Cookie Monster Munch (1983) (Atari)" "Cartridge.Note" "Uses Kids/Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "5835a78a88f97acea38c964980b7dbc6" "Cartridge.Name" "Cosmic Creeps (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5846b1d34c296bf7afc2fa05bbc16e98" "Cartridge.Manufacturer" "Atari - Sears" "Cartridge.ModelNo" "CX2643 - 6-99815" "Cartridge.Name" "Codebreaker (1978) (Atari)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "58513bae774360b96866a07ca0e8fd8e" "Cartridge.Manufacturer" "Mystique - American Multiple Industries, Joel H. Martin" "Cartridge.ModelNo" "1001" "Cartridge.Name" "Custer's Revenge (1982) (Mystique)" "" "Cartridge.MD5" "585600522b1f22f617652c962e358a5d" "Cartridge.Name" "Multi-Sprite Game V2.2 (Piero Cavina) (PD)" "" "Cartridge.MD5" "585f73010e205ae5b04ee5c1a67e632d" "Cartridge.Name" "Daredevil (V3) (Stunt_Cycle_Rules!) (PD)" "" "Cartridge.MD5" "5864cab0bc21a60be3853b6bcd50c59f" "Cartridge.Name" "Commando Raid (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "58746219d8094edff869f0f5c2aeaad5" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Bowling (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "5894c9c0c1e7e29f3ab86c6d3f673361" "Cartridge.Manufacturer" "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen" "Cartridge.ModelNo" "AZ-033, AZ-033-04" "Cartridge.Name" "Space Shuttle (1983) (Activision)" "Cartridge.Note" "A Journey Into Space" "" "Cartridge.MD5" "589c73bbcd77db798cb92a992b4c06c3" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Action Graphics, John Perkins, David Thiel" "Cartridge.ModelNo" "6230, 7210, 06004, 99004" "Cartridge.Name" "Artillery Duel (1983) (Xonox) (PAL60)" "Display.Format" "PAL60" "" "Cartridge.MD5" "58a82e1da64a692fd727c25faef2ecc9" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-824" "Cartridge.Name" "Jaw Breaker (1983) (CCE)" "" "Cartridge.MD5" "58c396323ea3e85671e34c98eb54e2a4" "Cartridge.Manufacturer" "Brian Watson" "Cartridge.Name" "Color Tweaker (B. Watson)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "58d331c23297ed98663d11b869636f16" "Cartridge.Name" "Fu Kung! (V0.09) (26-01-2003) (AD)" "" "Cartridge.MD5" "58e313e2b5613b2439b5f12bb41e3eef" "Cartridge.Name" "Cube Conquest (Demo Interlace) (Billy Eno) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "590ac71fa5f71d3eb29c41023b09ade9" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker" "Cartridge.ModelNo" "CX2684" "Cartridge.Name" "Galaxian (01-05-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "59135f13985b84c4f13cc9e55eec869a" "Cartridge.Name" "Multi-Sprite Game V2.0 (Piero Cavina) (PD)" "" "Cartridge.MD5" "594dbc80b93fa5804e0f1368c037331d" "Cartridge.Manufacturer" "Telesys, Alex Leavens" "Cartridge.Name" "Bouncin' Baby Bunnies (1983) (Telesys) (Prototype)" "Cartridge.Note" "AKA Bouncing Baby Monkeys" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5961d259115e99c30b64fe7058256bcf" "Cartridge.Manufacturer" "Universal Gamex Corporation, Miguel Castillo, H.K. Poon" "Cartridge.ModelNo" "GX-001" "Cartridge.Name" "X-Man (1983) (Universal)" "" "Cartridge.MD5" "59734e1cc41822373845a09c51e6ba21" "Cartridge.Manufacturer" "Activision, John Van Ryzin" "Cartridge.ModelNo" "AG-038-04" "Cartridge.Name" "Cosmic Commuter (1984) (Activision) (8K)" "" "Cartridge.MD5" "598a4e6e12f8238b7e7555f5a7777b46" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-008" "Cartridge.Name" "Miner 2049er (1982) (Tigervision) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Height" "214" "" "Cartridge.MD5" "599cbf919d47a05af975ad447df29497" "Cartridge.Manufacturer" "Jake Patterson" "Cartridge.Name" "Baubles (V0.002) (2001) (Jake Patterson) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "59b70658f9dd0e2075770b07be1a35cf" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Surfer's Paradise (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "59d33e00c07665395209c1e55da0b139" "Cartridge.Name" "Imagic Selector ROM (1982) (Imagic)" "" "Cartridge.MD5" "59e53894b3899ee164c91cfa7842da66" "Cartridge.Manufacturer" "Data Age" "Cartridge.Name" "Survival Run (1983) (Data Age) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "59e96de9628e8373d1c685f5e57dcf10" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "204" "Cartridge.Name" "Beat 'Em & Eat 'Em (1982) (PlayAround)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "Extremely Rare" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 45" "" "Cartridge.MD5" "59f596285d174233c84597dee6f34f1f" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-811" "Cartridge.Name" "River Raid (1983) (CCE)" "" "Cartridge.MD5" "5a0ff99ba10bd26d542e1d6f59f56850" "Cartridge.Manufacturer" "Champ Games" "Cartridge.ModelNo" "CG-04-P" "Cartridge.Name" "Super Cobra Arcade (PAL60)" "Cartridge.Note" "Compatible with Genesis controller" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5a17e30e6e911e74ccd7b716d02b16c6" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AX-029" "Cartridge.Name" "Crackpots (1983) (Activision) (8K)" "" "Cartridge.MD5" "5a272012a62becabcd52920348c7c60b" "Cartridge.Manufacturer" "Star Game" "Cartridge.Name" "Pitfall (Star Game)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "5a2f2dcd775207536d9299e768bcd2df" "Cartridge.Manufacturer" "Otto Versand" "Cartridge.ModelNo" "781698" "Cartridge.Name" "Flippern (Double-Game Package) (1983) (Otto Versand) (PAL)" "Cartridge.Note" "AKA Video Pinball" "" "Cartridge.MD5" "5a5390f91437af9951a5f8455b61cd43" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (0.11) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5a6febb9554483d8c71c86a84a0aa74e" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1003" "Cartridge.Name" "Donkey Kong Jr (1983) (CCE)" "Cartridge.Note" "AKA Donkey Kong Junior" "" "Cartridge.MD5" "5a734779d797ccef25dc8acfa47244c7" "Cartridge.Name" "Oh No! (Version 2) (18-01-2003) (AD)" "" "Cartridge.MD5" "5a80b857eb8b908ab477ec4ef902edc8" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-002, CAG-002, AG-002-04" "Cartridge.Name" "Boxing (1980) (Activision) (8K)" "" "Cartridge.MD5" "5a81ad4e184050851e63c8e16e3dac77" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.ModelNo" "Hack" "Cartridge.Name" "Sky Diver (Jone Yuan) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "5a8afe5422abbfb0a342fb15afd7415f" "Cartridge.Manufacturer" "Atari - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "CX26155" "Cartridge.Name" "Sprint Master (1988) (Atari)" "Cartridge.Note" "AKA Sprint 88, Sprint 2000" "" "Cartridge.MD5" "5a93265095146458df2baf2162014889" "Cartridge.Manufacturer" "Activision, Steve Cartwright - Ariola" "Cartridge.ModelNo" "EAX-031, EAX-031-04B - 711 031-717" "Cartridge.Name" "Frostbite (1983) (Activision) (PAL)" "" "Cartridge.MD5" "5a9685c4d51a6c1d6a9544946d9e8dc3" "Cartridge.Manufacturer" "AtariAge" "Cartridge.Name" "Grandma's Revenge (AtariAge)" "Cartridge.Note" "Can use driving controller in right port" "" "Cartridge.MD5" "5a9d188245aff829efde816fcade0b16" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-808" "Cartridge.Name" "Phantom Tank (1983) (CCE) (PAL)" "Cartridge.Note" "AKA Tanks But No Tanks" "Display.YStart" "36" "" "Cartridge.MD5" "5acf9865a72c0ce944979f76ff9610f0" "Cartridge.Name" "Dodge Demo 2 (PD)" "" "Cartridge.MD5" "5ae73916fa1da8d38ceff674fa25a78a" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Barnstorming (CCE)" "" "Cartridge.MD5" "5aea9974b975a6a844e6df10d2b861c4" "Cartridge.Manufacturer" "Atari, Dan Hitchens. Mimi Nyden" "Cartridge.ModelNo" "CX2656" "Cartridge.Name" "SwordQuest - EarthWorld (1982) (Atari)" "Cartridge.Note" "AKA Adventure I, SwordQuest I - EarthWorld" "" "Cartridge.MD5" "5af9cd346266a1f2515e1fbc86f5186a" "Cartridge.Manufacturer" "Sega" "Cartridge.ModelNo" "002-01" "Cartridge.Name" "Sub-Scan (1983) (Sega)" "Cartridge.Note" "AKA Subterfuge" "" "Cartridge.MD5" "5b124850de9eea66781a50b2e9837000" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "205" "Cartridge.Name" "Bachelor Party (1982) (PlayAround)" "Cartridge.Note" "Uses the paddle controllers" "Cartridge.Rarity" "Extremely Rare" "Controller.Left" "PADDLES_IAXIS" "Controller.MouseAxis" "AUTO 65" "Display.YStart" "22" "Display.Height" "222" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5b574faa56836da0866ba32ae32547f2" "Cartridge.Name" "Tomb Raider 2600 [REV 03] (Montezuma's Revenge Hack)" "" "Cartridge.MD5" "5b5d04887922b430de0b7b2a21f9cd25" "Cartridge.Name" "Omega Race (Genesis)" "Cartridge.Note" "Genesis controller (B is thrust, C is fire)" "Cartridge.Rarity" "Hack of Omega Race" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "5b6f5bcbbde42fc77d0bdb3146693565" "Cartridge.Name" "Seaquest (Unknown) (PAL)" "" "Cartridge.MD5" "5b7ea6aa6b35dc947c65ce665fde624b" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (2 of 3) (1982) (Starpath)" "" "Cartridge.MD5" "5b85e987e2b1618769d97ba9182333d0" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Brad Rice" "Cartridge.ModelNo" "CX2681" "Cartridge.Name" "Battlezone (05-12-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5b92a93b23523ff16e2789b820e2a4c5" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AG-039-04" "Cartridge.Name" "Kung-Fu Master (1987) (Activision)" "" "Cartridge.MD5" "5b98e0536c3f60547dd708ae22adb04b" "Cartridge.Manufacturer" "Ben Hudman" "Cartridge.Name" "Donkey Kong Gingerbread Man (Ben Hudman) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5b9c2e0012fbfd29efd3306359bbfc4a" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL) [a]" "" "Cartridge.MD5" "5babe0cad3ec99d76b0aa1d36a695d2f" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.ModelNo" "2654" "Cartridge.Name" "Looping (1983) (Coleco) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5bba254e18257e578c245ed96f6b003b" "Cartridge.Name" "Music Effects Demo (21-01-2003) (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5bbab3f3e4b47e3e23f9820765dbb45c" "Cartridge.Name" "Pitfall! (says 1985) [h1]" "" "Cartridge.MD5" "5bc9998b7e9a970e31d2cb60e8696cc4" "Cartridge.Manufacturer" "Jack Kortkamp" "Cartridge.Name" "Borgwars Asteroids (2003) (Jack Kortkamp) (Hack)" "Cartridge.Note" "Hack of Asteroids" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5bcc83677d68f7ef74c1b4a0697ba2a8" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AX-012, CAX-012, AX-012-04" "Cartridge.Name" "Ice Hockey (1981) (Activision) (16K)" "Cartridge.Type" "4K" "" "Cartridge.MD5" "5bd79139a0c03b63f6f2cf00a7d385d2" "Cartridge.Manufacturer" "Marc de Smet" "Cartridge.Name" "An Exercise In Minimalism (V1) (1999) (Marc de Smet) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "5be03a1fe7b2c114725150be04b38704" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2642" "Cartridge.Name" "Hunt & Score (1978) (Atari) (PAL)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "5c0227ad63300670a647fcebf595ea37" "Cartridge.Manufacturer" "Josh" "Cartridge.Name" "Battle for Naboo (Josh) (Hack)" "Cartridge.Note" "Hack of Atlantis" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "5c0520c00163915a4336e481ca4e7ef4" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "262.794 1" "Cartridge.Name" "Wuestenschlacht (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Chopper Command" "" "Cartridge.MD5" "5c19f6da638c4c7c1f98d09e63df43e4" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Cosmic Ark (Canal 3)" "" "Cartridge.MD5" "5c1b1aa78b7609d43c5144c3b3b60adf" "Cartridge.Name" "Demo Image Series #8 - Two Marios (Different Interlacing) (27-02-2003) (AD)" "" "Cartridge.MD5" "5c3a6d27c026f59a96b7af91e8b1bf26" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.Name" "PlayAround Demo (PlayAround) (1982)" "" "Cartridge.MD5" "5c618a50dfa23daac97ba459b9ff5206" "Cartridge.Manufacturer" "Steve Engelhardt" "Cartridge.Name" "Berzerk Renegade (2002) (Steve Engelhardt) (Hack)" "Cartridge.Note" "Hack of Room of Doom" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5c73693a89b06e5a09f1721a13176f95" "Cartridge.Name" "Wavy Line Test 2 (PD)" "" "Cartridge.MD5" "5c86e938e0845b9d61f458539e9a552b" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Surround (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "5cbd7c31443fb9c308e9f0b54d94a395" "Cartridge.Manufacturer" "Spectravideo, Mark Turmell" "Cartridge.ModelNo" "SA-217" "Cartridge.Name" "Gas Hog (1983) (Spectravideo) [fixed]" "" "Cartridge.MD5" "5ce98f22ade915108860424d8dde0d35" "Cartridge.Name" "Hangman Man Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "5d0e8a25cbd23e76f843c75a86b7e15b" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (09-07-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5d132d121aabc5235dd039dfc46aa024" "Cartridge.Name" "Basketball (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Note" "Console ports are swapped" "Cartridge.Rarity" "Hack" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "5d25df9dc2cde746ceac48e834cf84a7" "Cartridge.Manufacturer" "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen" "Cartridge.ModelNo" "EAZ-033" "Cartridge.Name" "Space Shuttle (1983) (Activision) (SECAM)" "Cartridge.Note" "A Journey Into Space" "Cartridge.Type" "FE" "Display.Format" "SECAM" "" "Cartridge.MD5" "5d2cc33ca798783dee435eb29debf6d6" "Cartridge.Manufacturer" "Activision - Imagineering, Mike Reidel" "Cartridge.ModelNo" "AK-043-04" "Cartridge.Name" "Commando (1988) (Activision)" "" "Cartridge.MD5" "5d799bfa9e1e7b6224877162accada0d" "Cartridge.Manufacturer" "Spectravision - Spectravideo - Sirius Software, David Lubar" "Cartridge.ModelNo" "SA-206" "Cartridge.Name" "Challenge of.... Nexar, The (1982) (Spectravision)" "" "Cartridge.MD5" "5d8f1ab95362acdf3426d572a6301bf2" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "SWOOPS! (v0.96) (TJ) (PAL)" "Cartridge.Note" "Uses the Joystick (L) and Paddle (R) Controllers" "Cartridge.Rarity" "Homebrew" "Controller.Right" "PADDLES" "Display.YStart" "28" "" "Cartridge.MD5" "5d8fb14860c2f198472b233874f6b0c9" "Cartridge.Name" "Boing! (PD) [a2]" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "5d9592756425192ec621d2613d0e683d" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-839" "Cartridge.Name" "Misterious Thief, A (1983) (CCE) [a]" "Cartridge.Note" "AKA A Mysterious Thief" "" "Cartridge.MD5" "5da8fd0b5ed33a360bff37f8b5d0cd58" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Pole Position (Tron)" "" "Cartridge.MD5" "5dae540347cf0a559962d62604ecf750" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Freeway (Canal 3)" "" "Cartridge.MD5" "5db9e5bf663cad6bf159bc395f6ead53" "Cartridge.Manufacturer" "Goliath - Hot Shot" "Cartridge.ModelNo" "83-212" "Cartridge.Name" "Time Race (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Space Jockey" "Display.Height" "256" "" "Cartridge.MD5" "5dccf215fdb9bbf5d4a6d0139e5e8bcb" "Cartridge.Manufacturer" "Froggo" "Cartridge.ModelNo" "FG1009" "Cartridge.Name" "Sea Hunt (1987) (Froggo)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "5de8803a59c36725888346fdc6e7429d" "Cartridge.Manufacturer" "Atari, John Dunn - Sears" "Cartridge.ModelNo" "CX2631 - 49-75152" "Cartridge.Name" "Superman (1979) (Atari) [fixed]" "" "Cartridge.MD5" "5df32450b9fbcaf43f9d83bd66bd5a81" "Cartridge.Manufacturer" "Eric Ball" "Cartridge.Name" "Atari Logo Playfield Demo (2001) (Eric Ball) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "5df559a36347d8572f9a6e8075a31322" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Enduro (Digivision)" "" "Cartridge.MD5" "5e0c37f534ab5ccc4661768e2ddf0162" "Cartridge.Manufacturer" "Telegames - VSS, Ed Salvo" "Cartridge.ModelNo" "5667 A106" "Cartridge.Name" "Glacier Patrol (1988) (Telegames)" "" "Cartridge.MD5" "5e1b4629426f4992cf3b2905a696e1a7" "Cartridge.Manufacturer" "Activision - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "AK-049-04" "Cartridge.Name" "Rampage! (1989) (Activision)" "" "Cartridge.MD5" "5e1b7a6078af428ef056fe85a37a95ca" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-014, AX-014-04" "Cartridge.Name" "Grand Prix (1982) (Activision) (8K)" "" "Cartridge.MD5" "5e1cd11a6d41fc15cf4792257400a31e" "Cartridge.Manufacturer" "Philip R. Frey" "Cartridge.Name" "Return of Mario Bros (Philip R. Frey) (Hack)" "Cartridge.Note" "Hack of Mario Bros." "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "5e201d6bfc520424a28f129ee5e56835" "Cartridge.Manufacturer" "Universal Gamex Corporation, Miguel Castillo, H.K. Poon" "Cartridge.ModelNo" "GX-001" "Cartridge.Name" "X-Man (1983) (Universal) (PAL)" "" "Cartridge.MD5" "5e2495d43b981010304af55efed1e798" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Math Gran Prix (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "5e2928f089490017e88e9f9e5a881a25" "Cartridge.Name" "Star Fire - Faster Skipping 1 (24-10-2002) (MP)" "" "Cartridge.MD5" "5e99aa93d0acc741dcda8752c4e813ce" "Cartridge.Name" "2600 Digital Clock (V b2) (PD)" "" "Cartridge.MD5" "5ec73ac7d2ac95ac9530c6d33e713d14" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "13" "Cartridge.Name" "Sweat! - The Decathlon Game (2 of 3) (1983) (Arcadia) (Prototype)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Cartridge.Rarity" "Prototype" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "5eeb81292992e057b290a5cd196f155d" "Cartridge.Manufacturer" "Wizard Video Games - VSS, Ed Salvo" "Cartridge.ModelNo" "008" "Cartridge.Name" "Texas Chainsaw Massacre, The (1983) (Wizard Video)" "" "Cartridge.MD5" "5ef303b9f0aa8cf20720c560e5f9baa1" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX2629, CX2629P" "Cartridge.Name" "Sky Diver (1979) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "5f1b7d5fa73aa071ba0a3c2819511505" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Cosmic Commuter (CCE)" "" "Cartridge.MD5" "5f2b4c155949f01c06507fb32369d42a" "Cartridge.Manufacturer" "Apollo, Ed Salvo" "Cartridge.ModelNo" "AP-1001" "Cartridge.Name" "Skeet Shoot (1981) (Apollo) (4K)" "" "Cartridge.MD5" "5f316973ffd107f7ab9117e93f50e4bd" "Cartridge.Name" "Commando Raid (Unknown) (PAL)" "" "Cartridge.MD5" "5f39353f7c6925779b0169a87ff86f1e" "Cartridge.Manufacturer" "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko" "Cartridge.ModelNo" "CX2694" "Cartridge.Name" "Pole Position (1983) (Atari) [a]" "Cartridge.Note" "AKA RealSports Driving" "" "Cartridge.MD5" "5f46d1ff6d7cdeb4b09c39d04dfd50a1" "Cartridge.Manufacturer" "Atari, Gary Palmer" "Cartridge.ModelNo" "CX2661P" "Cartridge.Name" "Fun with Numbers (1980) (Atari) (PAL)" "Cartridge.Note" "AKA Basic Math" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "5f560837396387455c9dcb05cdd4b053" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Eggomania (Canal 3)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 60" "" "Cartridge.MD5" "5f681403b1051a0822344f467b05a94d" "Cartridge.Manufacturer" "Atari, Howard Scott Warshaw - Sears" "Cartridge.ModelNo" "CX2655 - 49-75167" "Cartridge.Name" "Yars' Revenge (1982) (Atari) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5f69453a69f21dc49697a80d2e933491" "Cartridge.Name" "Star Fire - Reduced Flickering (06-10-2002) (MP)" "" "Cartridge.MD5" "5f708ca39627697e859d1c53f8d8d7d2" "Cartridge.Manufacturer" "Atari, Warren Robinett - Sears" "Cartridge.ModelNo" "CX2606 - 6-99825, 49-75112" "Cartridge.Name" "Slot Racers (1978) (Atari) (4K)" "" "Cartridge.MD5" "5f73e7175474c1c22fb8030c3158e9b3" "Cartridge.Manufacturer" "Atari, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX2665" "Cartridge.Name" "Frog Pond (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "5f786b67e05fb9985b77d4beb35e06ee" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Andrew Fuchs" "Cartridge.ModelNo" "CX26120" "Cartridge.Name" "Defender II (1987) (Atari) (PAL)" "Cartridge.Note" "AKA Stargate" "" "Cartridge.MD5" "5f7ae9a7f8d79a3b37e8fc841f65643a" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26109" "Cartridge.Name" "Sorcerer's Apprentice (1983) (Atari)" "" "Cartridge.MD5" "5f7de62a408b9de3a1168898298fd31d" "Cartridge.Name" "Super Cobra (Genesis)" "Cartridge.Note" "Genesis controller (B is bomb, C is laser)" "Cartridge.Rarity" "Hack of Super Cobra" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "5f950a2d1eb331a1276819520705df94" "Cartridge.Manufacturer" "20th Century Fox Video Games" "Cartridge.Name" "Unknown 20th Century Fox Game (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "5f9b62350b31be8bd270d9a241cbd50e" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5658 A088" "Cartridge.Name" "Football (1988) (Telegames) (PAL)" "Cartridge.Note" "AKA Super Challenge Football" "" "Cartridge.MD5" "5faffe1c4c57430978dec5ced32b9f4a" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Volleyball (Dactari - Milmar)" "Cartridge.Note" "AKA RealSports Volleyball" "" "Cartridge.MD5" "5fb71cc60e293fe10a5023f11c734e55" "Cartridge.Name" "This Planet Sucks (Fix) (27-12-2002) (Greg Troutman)" "Display.YStart" "36" "" "Cartridge.MD5" "600d48eef5c0ec27db554b7328b3251c" "Cartridge.Name" "Bars and Text Demo 3 (PD)" "" "Cartridge.MD5" "6015a9cef783e97e98a2aa2cf070ae06" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Battlezone TC (Thomas Jentzsch) (Hack)" "Cartridge.Note" "Uses two simultaneous Joystick Controllers, Hack of Battlezone" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "60358edf0c2cc76b1e549e031e50e130" "Cartridge.Manufacturer" "Manuel Polik" "Cartridge.Name" "Cyber Goth Galaxian (Manuel Polik) (Hack)" "Cartridge.Note" "Hack of Galaxian" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "603c7a0d12c935df5810f400f3971b67" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG209" "Cartridge.Name" "Mr. Postman (1983) (BitCorp) (PAL)" "" "Cartridge.MD5" "6041f400b45511aa3a69fab4b8fc8f41" "Cartridge.Manufacturer" "Apollo, Ban Tran" "Cartridge.ModelNo" "AP-2010" "Cartridge.Name" "Wabbit (1982) (Apollo)" "" "Cartridge.MD5" "604e09724555807c28108049efe34a13" "Cartridge.Name" "Sokoban (01-01-2003) (Adam Wozniak)" "" "Cartridge.MD5" "6058e40ce79d7434c7f7477b29abd4a5" "Cartridge.Name" "Rubik's Cube Demo (23-12-2002) (CT)" "" "Cartridge.MD5" "605dcb73d22f4efdb90ef9da2f290f7c" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL) (4K)" "Display.YStart" "40" "Display.Height" "256" "" "Cartridge.MD5" "605fd59bfef88901c8c4794193a4cbad" "Cartridge.Manufacturer" "Data Age" "Cartridge.Name" "Secret Agent (1983) (Data Age) (Prototype)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 45" "" "Cartridge.MD5" "606c2c1753051e03c1f1ac096c9d2832" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Crackpots (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "6076b187a5d8ea7a2a05111c19b5d5cd" "Cartridge.Name" "Fu Kung! (V0.14) (01-02-2003) (AD)" "" "Cartridge.MD5" "60a61da9b2f43dd7e13a5093ec41a53d" "Cartridge.Manufacturer" "VentureVision, Dan Oliver" "Cartridge.ModelNo" "VV2001" "Cartridge.Name" "Rescue Terra I (1982) (VentureVision)" "" "Cartridge.MD5" "60bbd425cb7214ddb9f9a31948e91ecb" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-005, CAG-005, AG-005-04" "Cartridge.Name" "Skiing (1980) (Activision) (4K)" "" "Cartridge.MD5" "60cd61a2dfccb0e2736434f9792c1672" "Cartridge.Manufacturer" "Amiga - Video Soft, Frank Ellis, Jerry Lawson" "Cartridge.ModelNo" "2110" "Cartridge.Name" "3-D Havoc (1983) (Amiga) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "60d304582d33e2957b73eb300a7495bb" "Cartridge.Name" "Jam Demo 2 (PD)" "" "Cartridge.MD5" "60e0ea3cbe0913d39803477945e9e5ec" "Cartridge.Manufacturer" "Atari, Joe Decuir - Sears" "Cartridge.ModelNo" "CX2621 - 99806, 6-99806, 49-75104" "Cartridge.Name" "Video Olympics (1977) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXDR" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 60" "" "Cartridge.MD5" "613abf596c304ef6dbd8f3351920c37a" "Cartridge.Name" "Boring Pac-Man (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "6141c095d0aee4e734bebfaac939030a" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-017" "Cartridge.Name" "Mariana (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Seaquest" "" "Cartridge.MD5" "61426cee013306e7f7367534ab124747" "Cartridge.Name" "One Blue Bar Demo (PD)" "" "Cartridge.MD5" "615a3bf251a38eb6638cdc7ffbde5480" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX2674" "Cartridge.Name" "E.T. - The Extra-Terrestrial (1982) (Atari)" "" "Cartridge.MD5" "61621a556ad3228f0234f5feb3ab135c" "Cartridge.Name" "Fu Kung! (V0.05 Cuttle Card Compattle Revision) (14-01-2003) (AD)" "" "Cartridge.MD5" "61631c2f96221527e7da9802b4704f93" "Cartridge.Manufacturer" "Activision - Imagineering, Mike Reidel" "Cartridge.ModelNo" "AK-043-04" "Cartridge.Name" "Commando (1988) (Activision) [different logo]" "" "Cartridge.MD5" "61719a8bdafbd8dab3ca9ce7b171b9e2" "Cartridge.Name" "Enduro (Unknown) (PAL)" "" "Cartridge.MD5" "61728c6cfb052e62a9ed088c5bf407ba" "Cartridge.Name" "Sprite Demo 4 (PD)" "" "Cartridge.MD5" "619de46281eb2e0adbb98255732483b4" "Cartridge.Name" "Time Warp (Unknown)" "Display.YStart" "20" "" "Cartridge.MD5" "61dbe94f110f30ca4ec524ae5ce2d026" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-820" "Cartridge.Name" "Space Invaders (1983) (CCE)" "" "Cartridge.MD5" "61e0f5e1cc207e98704d0758c68df317" "Cartridge.Manufacturer" "Star Game" "Cartridge.ModelNo" "007" "Cartridge.Name" "Tennis (Star Game)" "" "Cartridge.MD5" "61ef8c2fc43be9a04fe13fdb79ff2bd9" "Cartridge.Name" "Gas Gauge Demo - Revisited (2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "6205855cc848d1f6c4551391b9bfa279" "Cartridge.Name" "Euchre (Release Candidate 2) (NTSC) (01-10-2002) (Erik Eid)" "" "Cartridge.MD5" "624e0a77f9ec67d628211aaf24d8aea6" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "108" "Cartridge.Name" "Sea Hawk (1983) (Panda)" "Cartridge.Note" "AKA Seahawk" "" "Cartridge.MD5" "626d67918f4b5e3f961e4b2af2f41f1d" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "50008" "Cartridge.Name" "Diagnostic Test Cartridge 2.0 (1980) (Atari) (Prototype)" "" "Cartridge.MD5" "6272f348a9a7f2d500a4006aa93e0d08" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Michael Sierchio" "Cartridge.ModelNo" "CX2667, CX2667P" "Cartridge.Name" "RealSports Soccer (1983) (Atari) (PAL) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "62899430338e0538ee93397867d85957" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-004" "Cartridge.Name" "Airlock (1983) (Gameworld) (PAL)" "" "Cartridge.MD5" "62921652f6634eb1a0940ed5489c7e18" "Cartridge.Name" "SCSIcide (V1.09) (2001) (Joe Grand)" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "AUTO 65" "" "Cartridge.MD5" "62992392ea651a16aa724a92e4596ed6" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (Beta) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "62d1f50219edf9a429a9f004c19f31b3" "Cartridge.Manufacturer" "JWDA, Todd Marshall" "Cartridge.Name" "Euro Gen (02-01-83) (JWDA) (PAL)" "" "Cartridge.MD5" "62f74a2736841191135514422b20382d" "Cartridge.Name" "Pharaoh's Curse (Unknown)" "Display.Format" "PAL60" "Display.YStart" "20" "Display.Height" "225" "Display.Phosphor" "YES" "" "Cartridge.MD5" "62ffd175cac3f781ef6e4870136a2520" "Cartridge.Name" "2600 Digital Clock (V x.xx) (PD)" "" "Cartridge.MD5" "63166867f75869a3592b7a94ea62d147" "Cartridge.Name" "Indy 500 (Hack) [a1]" "Cartridge.Note" "Hack of Indy 500" "Cartridge.Rarity" "Hack" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "" "Cartridge.MD5" "6333ef5b5cbb77acd47f558c8b7a95d3" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (Greg Troutman) (PD) (8K)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6337927ad909aa739d6d0044699a916d" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 2 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "6339d28c9a7f92054e70029eb0375837" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart" "Cartridge.ModelNo" "PB5540" "Cartridge.Name" "Star Wars - The Arcade Game (1984) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6342afe9c9ad1b6120b8f6fb040d0926" "Cartridge.Name" "Move a Blue Blob Demo (PD)" "" "Cartridge.MD5" "6354f9c7588a27109c66905b0405825b" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Amidar DS (2003) (TJ) (Hack)" "Cartridge.Note" "Hack of Amidar" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "635cc7a0db33773959d739d04eff96c2" "Cartridge.Name" "Minesweeper (V.90) (Soren Gust) (PD)" "" "Cartridge.MD5" "6362396c8344eec3e86731a700b13abf" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "109" "Cartridge.Name" "Exocet (1983) (Panda)" "" "Cartridge.MD5" "637efac676ff063f2fbb0abff77c4fa5" "Cartridge.Name" "Noize Maker Demo (PD)" "" "Cartridge.MD5" "63811ed69bdbc35c69d8aa7806c3d6e9" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Homerun (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "638cc82ea96f67674595ba9ae05da6c6" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-011" "Cartridge.Name" "Super Ferrari (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "63a6eda1da30446569ac76211d0f861c" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-001" "Cartridge.Name" "Dragster (1980) (Activision) (4K)" "Display.YStart" "27" "" "Cartridge.MD5" "63a7445b1d3046d3cdcdbd488dca38d9" "Cartridge.Manufacturer" "Rob Kudla" "Cartridge.Name" "Better Space Invaders (1999) (Rob Kudla) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "63c5fef3208bb1424d26cf1ab984b40c" "Cartridge.Name" "Analog Clock (V0.1) (20-01-2003) (AD)" "" "Cartridge.MD5" "63c7395d412a3cd095ccdd9b5711f387" "Cartridge.Manufacturer" "Eric Ball" "Cartridge.ModelNo" "ELB005" "Cartridge.Name" "Skeleton+ (PAL)" "Cartridge.Note" "Stereo sound" "Cartridge.Rarity" "Homebrew" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "63d6247f35902ba32aa49e7660b0ecaa" "Cartridge.Name" "Space War (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "63e42d576800086488679490a833e097" "Cartridge.Manufacturer" "Telesys, Jim Rupp" "Cartridge.ModelNo" "1004" "Cartridge.Name" "Ram It (1983) (Telesys) (PAL)" "" "Cartridge.MD5" "63e783994df824caf289b69a084cbf3e" "Cartridge.Manufacturer" "David Marli" "Cartridge.Name" "Fat Albert (David Marli) (Hack)" "Cartridge.Note" "Hack of Fast Food" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "63e9e612bbee31045f8d184a4e53f8ec" "Cartridge.Manufacturer" "ATARITALIA" "Cartridge.Name" "Moby Blues (2002) (ATARITALIA) (Hack)" "Cartridge.Note" "Hack of Mario Bros" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "640a08e9ca019172d612df22a9190afb" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Kevin Osborn" "Cartridge.ModelNo" "CX2691, CX2691P" "Cartridge.Name" "Joust (1983) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "64198bb6470c78ac24fcf13fe76ab28c" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (1982) (Arcadia) [a]" "" "Cartridge.MD5" "643e6451eb6b8ab793eb60ba9c02e000" "Cartridge.Manufacturer" "Salu - Avantgarde Software, Michael Buetepage" "Cartridge.ModelNo" "460741" "Cartridge.Name" "Ghostbusters II (1992) (Salu) (PAL) [different tune]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "645bf7f9146f0e4811ff9c7898f5cd93" "Cartridge.Manufacturer" "Xonox - K-Tel Software - VSS, Robert Weatherby" "Cartridge.ModelNo" "6230, 6250" "Cartridge.Name" "Super Kung-Fu (1983) (Xonox) (PAL)" "" "Cartridge.MD5" "6468d744be9984f2a39ca9285443a2b2" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Reversi (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Othello" "" "Cartridge.MD5" "647162cceb550fd49820e2206d9ee7e8" "Cartridge.Name" "Skeleton (NTSC) (2002) (Eric Ball)" "" "Cartridge.MD5" "64b8e19c767191ccdc97acc6904c397b" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 6 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "64ca518905311d2d9aeb56273f6caa04" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Cubo Magico (CCE)" "Cartridge.Note" "AKA Cubicolor" "" "Cartridge.MD5" "64d43859258dc8ca54949e9ff4174202" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Lilly Adventure (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.Height" "230" "" "Cartridge.MD5" "64fab9d15df937915b1c392fc119b83b" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX26119" "Cartridge.Name" "Saboteur (05-20-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "650df778c6ce22d3fd1a7c33c565bcc3" "Cartridge.Manufacturer" "Atari - GCC, Betty Ryan Tylko, Douglas B. Macrae" "Cartridge.ModelNo" "CX2694" "Cartridge.Name" "Pole Position (1983) (Atari)" "Cartridge.Note" "Genesis controller (B is high gear, C is low gear, left difficulty switch swaps gear buttons)" "Cartridge.Rarity" "Hack of Pole Position" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "651d2b6743a3a18b426bce2c881af212" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-812" "Cartridge.Name" "Pac Man (1983) (CCE) [a]" "" "Cartridge.MD5" "6522717cfd75d1dba252cbde76992090" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83102" "Cartridge.Name" "War 2000 (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Astrowar" "" "Cartridge.MD5" "6538e454b0498ad2befe1ef0f87815c0" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide (v1.2) (2001) (Joe Grand)" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "AUTO 65" "" "Cartridge.MD5" "65490d61922f3e3883ee1d583ce10855" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692, CX2692P" "Cartridge.Name" "Moon Patrol (1983) (Atari) (PAL)" "" "Cartridge.MD5" "65562f686b267b21b81c4dddc129d724" "Cartridge.Name" "Euchre (28-07-2001) (Eric Eid) (PD)" "" "Cartridge.MD5" "655c84e5b951258c9d20f0bf2b9d496d" "Cartridge.Name" "2600_2003 Demo (PD)" "" "Cartridge.MD5" "656dc247db2871766dffd978c71da80c" "Cartridge.Manufacturer" "Sears Tele-Games, Jim Huether" "Cartridge.ModelNo" "CX2614 - 49-75126" "Cartridge.Name" "Steeplechase (1980) (Sears)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "Controller.Right" "PADDLES" "Controller.MouseAxis" "AUTO 60" "" "Cartridge.MD5" "65917ae29a8c9785bb1f2acb0d6aafd0" "Cartridge.Name" "Junkosoft One Year Demo (1999) (PD)" "" "Cartridge.MD5" "6596b3737ae4b976e4aadb68d836c5c7" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Defender (Digivision)" "" "Cartridge.MD5" "659a20019de4a23c748ec2292ea5f221" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.05) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "65b106eba3e45f3dab72ea907f39f8b4" "Cartridge.Manufacturer" "Sparrow - HomeComputer Software, Dan Schafer, Glenn Stohel, Jon Tedesco" "Cartridge.ModelNo" "GCG 1001T" "Cartridge.Name" "Music Machine, The (1983) (Sparrow)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 45" "" "Cartridge.MD5" "65ba1a4c643d1ab44481bdddeb403827" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "876.013 4" "Cartridge.Name" "Katastrophen-Einsatz (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA M.A.S.H." "" "Cartridge.MD5" "65bd29e8ab1b847309775b0de6b2e4fe" "Cartridge.Manufacturer" "Coleco, Ed English" "Cartridge.ModelNo" "2667" "Cartridge.Name" "Roc 'n Rope (1984) (Coleco)" "" "Cartridge.MD5" "65c6406f5af934590097c8c032ebb482" "Cartridge.Name" "Three Hugger (Pave Demo) (20-12-2002) (Billy Eno)" "" "Cartridge.MD5" "6604f72a966ca6b2df6a94ee4a68eb82" "Cartridge.Name" "MegaMania (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "662eca7e3d89175ba0802e8e3425dedb" "Cartridge.Name" "Hangman Pac-Man Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "66362890eb78d6ea65301592cce65f5b" "Cartridge.Name" "Euchre (13-07-2001) (Eric Eid) (PD)" "" "Cartridge.MD5" "663ef22eb399504d5204c543b8a86bcd" "Cartridge.Manufacturer" "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner" "Cartridge.ModelNo" "4L1720, 4L1721, 4L1722, 4L2276" "Cartridge.Name" "Wizard of Wor (1982) (CBS Electronics) (PAL)" "Cartridge.Note" "Uses the Joystick Controllers (swapped)" "Console.SwapPorts" "YES" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6651e2791d38edc02c5a5fd7b47a1627" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart" "Cartridge.ModelNo" "PB5540" "Cartridge.Name" "Star Wars - The Arcade Game (04-05-1984) (Parker Bros) (Prototype) (8K)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "665b8f8ead0eef220ed53886fbd61ec9" "Cartridge.Manufacturer" "Telesys, Don Ruffcorn, Jack Woodman" "Cartridge.ModelNo" "1003" "Cartridge.Name" "Fast Food (1982) (Telesys)" "" "Cartridge.MD5" "66706459e62514d0c39c3797cbf73ff1" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-05" "Cartridge.Name" "Treasure Below (1983) (Video Gems) (PAL)" "Console.RightDifficulty" "A" "" "Cartridge.MD5" "6672de8f82c4f7b8f7f1ef8b6b4f614d" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP237" "Cartridge.Name" "Angeln I (Ariola) (PAL)" "Cartridge.Note" "AKA Fishing Derby" "" "Cartridge.MD5" "668dc528b7ea9345140f4fcfbecf7066" "Cartridge.Manufacturer" "Gakken" "Cartridge.ModelNo" "001" "Cartridge.Name" "Pooyan (1983) (Gakken) (PAL)" "" "Cartridge.MD5" "6697f177847c70505824422e76aad586" "Cartridge.Name" "Tennis (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "669840b0411bfbab5c05b786947d55d4" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Jeffrey Gusman, Dave Jolly, Suki Lee" "Cartridge.ModelNo" "CX26117" "Cartridge.Name" "Obelix (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "66b89ba44e7ae0b51f9ef000ebba1eb7" "Cartridge.Manufacturer" "Atari - CCW, Stephan R. Keith, Laura Scholl, Preston Stuart" "Cartridge.ModelNo" "CX26106" "Cartridge.Name" "Grover's Music Maker (01-18-1983) (Atari) (Prototype)" "Cartridge.Note" "Uses Keypad Controller" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "" "Cartridge.MD5" "66b92ede655b73b402ecd1f4d8cd9c50" "Cartridge.Manufacturer" "Activision, John Van Ryzin - Ariola" "Cartridge.ModelNo" "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720" "Cartridge.Name" "H.E.R.O. (1984) (Activision) (PAL) [a2]" "" "Cartridge.MD5" "66bc1bef269ea59033928bac2d1d81e6" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "AR-4300" "Cartridge.Name" "Fireball (Preview) (1982) (Arcadia)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "66c2380c71709efa7b166621e5bb4558" "Cartridge.Manufacturer" "Parker Brothers, Dave Engman, Dawn Stockbridge" "Cartridge.ModelNo" "931509" "Cartridge.Name" "Tutankham (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "66c4e0298d4120df333bc2f3e163657e" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (2 of 3) (1982) (Starpath) (PAL)" "" "Cartridge.MD5" "66fcf7643d554f5e15d4d06bab59fe70" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6706a00f9635508cfeda20639156e66e" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Michael Sierchio" "Cartridge.ModelNo" "CX2667" "Cartridge.Name" "RealSports Soccer (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "672012d40336b403edea4a98ce70c76d" "Cartridge.Name" "Spider Kong (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "675ae9c23fa1aae376cea86cad96f9a5" "Cartridge.Name" "Poker Squares (V0.25) (2001) (B. Watson)" "" "Cartridge.MD5" "67631ea5cfe44066a1e76ddcb6bcb512" "Cartridge.Name" "Termool (Unknown) (PAL)" "Cartridge.Note" "AKA Turmoil" "" "Cartridge.MD5" "67684a1d18c85ffa5d82dab48fd1cb51" "Cartridge.Manufacturer" "Tigervision, Warren Schwader - Teldec" "Cartridge.ModelNo" "7-003" "Cartridge.Name" "Threshold (1982) (Tigervision) (PAL)" "" "Cartridge.MD5" "678c1d71a1616d9d022f03d8545b64bb" "Cartridge.Name" "Demo Image Series #11 - Donald And Mario (28-02-2003) (AD)" "" "Cartridge.MD5" "67931b0d37dc99af250dd06f1c095e8d" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines" "Cartridge.ModelNo" "CM-004" "Cartridge.Name" "Room of Doom (1982) (CommaVid)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "679d30c7886b283cbe1db4e7dbe5f2a6" "Cartridge.Manufacturer" "Colin Hughes" "Cartridge.Name" "Puzzle (Colin Hughes) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "679e910b27406c6a2072f9569ae35fc8" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1002" "Cartridge.Name" "Warplock (1982) (Data Age)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 40" "Display.Phosphor" "YES" "" "Cartridge.MD5" "67bd3d4dc5ac6a42a99950b4245bdc81" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.11) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "67c05ae94bf8b83a666c3ae2c4bc14de" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "NFL Football (32 in 1) (1988) (Atari) (PAL) (4K)" "Cartridge.Note" "AKA Football" "" "Cartridge.MD5" "67cdde4176e0447fc45a71e0a1cdd288" "Cartridge.Manufacturer" "Telegames - VSS, Ed Salvo" "Cartridge.ModelNo" "5665 A016" "Cartridge.Name" "Glacier Patrol (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "67ce6cdf788d324935fd317d064ed842" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.09) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "67cf913d1df0bf2d7ae668060d0b6694" "Cartridge.Name" "Hangman Monkey 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6803fa7c2c094b428b859a58dc1dd06a" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (0.11) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6805734a0b7bcc8925d9305b071bf147" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP229" "Cartridge.Name" "Kung Fu (4 Game in One Dark Green) (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA Karate" "" "Cartridge.MD5" "681206a6bde73e71c19743607e96c4bb" "Cartridge.Name" "Casino (Unknown) (PAL)" "Controller.Left" "PADDLES" "Display.YStart" "49" "" "Cartridge.MD5" "683bb0d0f0c5df58557fba9dffc32c40" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "AR-4300" "Cartridge.Name" "Fireball (1982) (Arcadia) [a]" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "683dc64ef7316c13ba04ee4398e2b93a" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Edtris (1995) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "68449e4aaba677abcd7cde4264e02168" "Cartridge.Name" "Horizonal Color Bars Demo 2 (PD)" "" "Cartridge.MD5" "6847ce70819b74febcfd03e99610243b" "Cartridge.Name" "Ruby Runner 4A50" "Display.YStart" "27" "Display.Phosphor" "YES" "" "Cartridge.MD5" "68489e60268a5e6e052bad9c62681635" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG201" "Cartridge.Name" "Sea Monster (1982) (BitCorp) (PAL)" "Display.Height" "256" "" "Cartridge.MD5" "68597264c8e57ada93be3a5be4565096" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1005" "Cartridge.Name" "Bugs (1982) (Data Age)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "Uncommon" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 50" "" "Cartridge.MD5" "685e9668dc270b6deeb9cfbfd4d633c3" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines - Ariola" "Cartridge.ModelNo" "CM-004 - 712 004-720" "Cartridge.Name" "Room of Doom (1982) (CommaVid) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "68760b82fc5dcf3fedf84376a4944bf9" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-860" "Cartridge.Name" "Laser Gate (1983) (CCE)" "Cartridge.Note" "AKA Innerspace" "" "Cartridge.MD5" "687c23224e26f81c56e431c24faea36d" "Cartridge.Name" "Qb (Simple Background Animation) (2001) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "68878250e106eb6c7754bc2519d780a0" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-809" "Cartridge.Name" "Squirrel (1983) (CCE)" "Cartridge.Note" "AKA Snail Against Squirrel" "Display.Height" "220" "" "Cartridge.MD5" "68c80e7e1d30df98a0cf67ecbf39cc67" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - One Step Forward & Two Steps Back (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "68cd2adc6b1fc9a1f263ab4561112f30" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Boulderdash Demo (09-12-2002) (TJ)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "68feb6d6ff63e80df1302d8547979aec" "Cartridge.Name" "Starfield Demo 2 (20-12-2002) (CT)" "" "Cartridge.MD5" "690a6049db78b9400c13521646708e9c" "Cartridge.Manufacturer" "King Tripod Enterprise Co." "Cartridge.ModelNo" "SS - 007" "Cartridge.Name" "Space Raid (King Tripod) (PAL)" "Cartridge.Note" "AKA Challenge of.... Nexar, The" "" "Cartridge.MD5" "6913c90002636c1487538d4004f7cac2" "Cartridge.Manufacturer" "Atari - CCW" "Cartridge.ModelNo" "CX26131" "Cartridge.Name" "Monster Cise (1984) (Atari) (Prototype)" "Cartridge.Note" "Uses the Keypad Controllers (left only)" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "" "Cartridge.MD5" "691d67910b08b63de8631901d1887c1f" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (1983) (Arcadia) [a]" "Display.YStart" "30" "" "Cartridge.MD5" "692202772d8b38ccf85a90c8003a1324" "Cartridge.Name" "Zi - The Flie Buster (2002) (Fernando Mora) (PD)" "" "Cartridge.MD5" "693137592a7f5ccc9baae2d1041b7a85" "Cartridge.Name" "Qb (V2.02) (Stella) (2001) (Retroactive) [a1]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6979f30204149be3e227558cffe21c1d" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL) (4K)" "Cartridge.Note" "AKA Miniature Golf" "" "Cartridge.MD5" "6982854657a2cc87d712f718e402bf85" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Earth Attack (Zellers)" "Cartridge.Note" "AKA Defender" "" "Cartridge.MD5" "698f569eab5a9906eec3bc7c6b3e0980" "Cartridge.Manufacturer" "SpkLeader" "Cartridge.Name" "Demons! (2003) (SpkLeader) (Hack)" "Cartridge.Note" "Hack of Phoenix" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "69974dd5d6420b90898cde50aec5ef39" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009, AG-009-04" "Cartridge.Name" "Freeway (1981) (Activision) (16K)" "" "Cartridge.MD5" "69df0411d4d176e558017f961f5c5849" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-831" "Cartridge.Name" "Cosmic Ark (1983) (CCE) [a]" "" "Cartridge.MD5" "69e79b1352b9ee1754bbe63b4a7062c3" "Cartridge.Manufacturer" "Barry Laws Jr." "Cartridge.Name" "Pink Floyd - The Wall (2003) (Barry Laws Jr.) (Hack)" "Cartridge.Note" "Hack of Berzerk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "69ebf910ab9b63e5b8345f016095003b" "Cartridge.Name" "Maze Demo 1 (PD)" "" "Cartridge.MD5" "69fac82cd2312dd9ce5d90e22e2f070a" "Cartridge.Manufacturer" "Spectravision - Spectravideo - Quelle" "Cartridge.ModelNo" "SA-202 - 412.851 8" "Cartridge.Name" "Planet Patrol (1982) (Spectravision) (PAL)" "" "Cartridge.MD5" "6a03c28d505bab710bf20b954e14d521" "Cartridge.Name" "Pressure Gauge 2 Beta (Hozer Video Games)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "6a07836c382195dd5305ce61d992aaa6" "Cartridge.Manufacturer" "Apollo, Larry Martin" "Cartridge.ModelNo" "AP-2008" "Cartridge.Name" "Guardian (1982) (Apollo) (Prototype)" "Cartridge.Note" "Uses the Paddle Controller (left only)" "Cartridge.Rarity" "Prototype" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "6a091b8ffeacd0939850da2094b51564" "Cartridge.Name" "Vertically Scrolling Playfield (02-02-2003) (Aaron Bergstrom)" "" "Cartridge.MD5" "6a2c68f7a77736ba02c0f21a6ba0985b" "Cartridge.Manufacturer" "Atari, Larry Wagner, Bob Whitehead" "Cartridge.Name" "Computer Chess (07-07-1978) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6a3b0c33cf74b1e213a629e3c142b73c" "Cartridge.Manufacturer" "Cody Pittman" "Cartridge.Name" "Cory The Interviewer (Cody Pittman) (Hack)" "Cartridge.Note" "Hack of Ghostbusters" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6a76d5f0ed721639474aa9bbde69ebf0" "Cartridge.Name" "Play Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6a82b8ecc663f371b19076d99f46c598" "Cartridge.Manufacturer" "Activision, Larry Miller - Ariola" "Cartridge.ModelNo" "EAX-026, EAX-026-04B, EAX-026-04I - 711 026-725" "Cartridge.Name" "Enduro (1983) (Activision) (PAL)" "" "Cartridge.MD5" "6a882fb1413912d2ce5cf5fa62cf3875" "Cartridge.Manufacturer" "Video Game Cartridge - Ariola" "Cartridge.ModelNo" "TP-605" "Cartridge.Name" "Dragon Defender (Ariola) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6a8c6940d3be6fd01274363c4d4b298e" "Cartridge.Name" "Spy Hunter (Genesis)" "Cartridge.Note" "Genesis controller (C is oil/smoke)" "Cartridge.Rarity" "Hack of Spy Hunter" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "6a9b30ca46b0dba9e719f4cbd340e01c" "Cartridge.Name" "Frostbite (Unknown) (PAL) (Hack)" "Display.Height" "240" "" "Cartridge.MD5" "6a9e0c72fab92df70084eccd9061fdbd" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-835" "Cartridge.Name" "Beany Bopper (1983) (CCE)" "" "Cartridge.MD5" "6aa66e9c3eea76a0c40ef05513497c40" "Cartridge.Name" "Hangman Ghost Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6ac3fd31a51730358708c7fdc62487f8" "Cartridge.Manufacturer" "Matthias Jaap" "Cartridge.Name" "PC Invaders (Matthias Jaap) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6ae4dc6d7351dacd1012749ca82f9a56" "Cartridge.Manufacturer" "Atari - GCC, Jaques Hugon, Seth Lipkin" "Cartridge.ModelNo" "CX26125, CX26127" "Cartridge.Name" "Track and Field (1984) (Atari)" "Cartridge.Note" "Uses the Track & Field Controller" "" "Cartridge.MD5" "6b01a519b413f8cfa2f399f4d2841b42" "Cartridge.Name" "Aphex Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6b1fc959e28bd71aed7b89014574bdc2" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG203" "Cartridge.Name" "Phantom Tank (1982) (BitCorp) (PAL)" "Cartridge.Note" "AKA Tanks But No Tanks" "Display.YStart" "36" "" "Cartridge.MD5" "6b4eb5b3df80995b8d9117cb7e9aeb3c" "Cartridge.Manufacturer" "Gameworld, J. Ray Dettling" "Cartridge.ModelNo" "133-006" "Cartridge.Name" "Journey Escape (1983) (Gameworld) (PAL)" "Cartridge.Note" "AKA Rock 'n' Roll Escape" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6b683be69f92958abe0e2a9945157ad5" "Cartridge.Manufacturer" "U.S. Games Corporation - Western Technologies, Jeff Corsiglia, Paul Allen Newell, Steven B. Sidley, Tom Sloper" "Cartridge.ModelNo" "VC2007" "Cartridge.Name" "Entombed (1983) (U.S. Games)" "Cartridge.Note" "Released as Name That Game for a contest (winning name was Entombed)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6b6ca32228ae352b4267e4bd2cddf10c" "Cartridge.Name" "Pac-Man 4 (Pac-Man Hack)" "Display.YStart" "33" "" "Cartridge.MD5" "6b71f20c857574b732e7a8e840bd3cb2" "Cartridge.Name" "Frostbite (Unknown) (PAL)" "" "Cartridge.MD5" "6b72b691ea86f61438ed0d84c4d711de" "Cartridge.Name" "Fishing Derby (Unknown) (PAL) (4K) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6b75f8fa4fd011a6698c58315f83d2ac" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Sprintmaster DC (TJ)" "Cartridge.Note" "Uses the Driving Controllers, Hack of Sprintmaster (Atari)" "Cartridge.Rarity" "New Release (Hack)" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "Controller.MouseAxis" "45" "" "Cartridge.MD5" "6b7a56b6ac2ca4bf9254474bf6ed7d80" "Cartridge.Name" "Horizonal Color Bars Demo (PD)" "" "Cartridge.MD5" "6b7e1c11448c4d3f28160d2de884ebc8" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Fast Food (Zirok)" "" "Cartridge.MD5" "6b8fb021bb2e1f1e9bd7ee57f2a8e709" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "3-D Corridor (29-03-2003) (Paul Slocum) (PD) [a]" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "6bb09bc915a7411fe160d0b2e4d66047" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "UFO (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Space Jockey" "" "Cartridge.MD5" "6bb22efa892b89b69b9bf5ea547e62b8" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Megamania (1982) (Dynacom)" "" "Cartridge.MD5" "6bde3f6ac31aceef447ce57d4d2c2ec0" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Mondo Pong V1 (Piero Cavina) (PD)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "6c128bc950fcbdbcaf0d99935da70156" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Volleyball (1983) (Digitel)" "Cartridge.Note" "AKA RealSports Volleyball" "" "Cartridge.MD5" "6c1553ca90b413bf762dfc65f2b881c7" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "343.073 3" "Cartridge.Name" "Winterjagd (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Ski Hunt" "" "Cartridge.MD5" "6c1f3f2e359dbf55df462ccbcdd2f6bf" "Cartridge.Manufacturer" "Activision, Garry Kitchen - Ariola" "Cartridge.ModelNo" "EAX-025, EAX-025-04I - 711 025-725" "Cartridge.Name" "Keystone Kapers (1983) (Activision) (PAL)" "" "Cartridge.MD5" "6c25f58fd184632ca76020f589bb3767" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Beat 'Em & Eat 'Em (1983) (Dynacom)" "Cartridge.Note" "Uses the Paddle Controller (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 45" "" "Cartridge.MD5" "6c449db9bbbd90972ad1932d6af87330" "Cartridge.Name" "20 Sprites at Once Demo 3 (PD)" "" "Cartridge.MD5" "6c658b52d03e01828b9d2d4718a998ac" "Cartridge.Name" "Hangman Invader Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6c76fe09aa8b39ee52035e0da6d0808b" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.ModelNo" "CX2622, CX2622P" "Cartridge.Name" "Breakout (1978) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 60" "" "Cartridge.MD5" "6c85098518d3f94f7622c42fd1d819ac" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-028" "Cartridge.Name" "Firebug (Suntek) (PAL)" "Cartridge.Note" "AKA Spinning Fireball" "" "Cartridge.MD5" "6c91ac51421cb9fc72c9833c4f440d65" "Cartridge.Manufacturer" "ITT Family Games" "Cartridge.ModelNo" "554-33 375" "Cartridge.Name" "Cosmic Town (1983) (ITT Family Games) (PAL)" "Cartridge.Note" "AKA Base Attack (Perry Rhodan-Serie)" "" "Cartridge.MD5" "6c9a32ad83bcfde3774536e52be1cce7" "Cartridge.Name" "Space Treat (NTSC) (13-08-2002) (Fabrizio Zavagli)" "" "Cartridge.MD5" "6cbe945e16d9f827d0d295546ac11b22" "Cartridge.Name" "Gunfight 2600 - AI (MP)" "" "Cartridge.MD5" "6ccd8ca17a0e4429b446cdcb66327bf1" "Cartridge.Name" "RPG Engine (12-05-2003) (Paul Slocum) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6cd1dc960e3e8d5c5e0fbe67ab49087a" "Cartridge.Name" "Vertical Playfield Demo 1 (PD)" "" "Cartridge.MD5" "6cd506509e8fd5627f55603780e862a8" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (SuperCharger) (Greg Troutman) (PD)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6ce2110ac5dd89ab398d9452891752ab" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Persian Gulf War (Funvision)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "6cea35ded079863a846159c3a1101cc7" "Cartridge.Name" "Atlantis (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6ceb7d6a54e9a5e62d26874d1cc88dbc" "Cartridge.Manufacturer" "Video Soft" "Cartridge.Name" "Atom Smasher (1984) (Video Soft) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6cf054cd23a02e09298d2c6f787eb21d" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart" "Cartridge.ModelNo" "PB5540" "Cartridge.Name" "Star Wars - The Arcade Game (1984) (Parker Bros) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6d218dafbf5a691045cdc1f67ceb6a8f" "Cartridge.Manufacturer" "Robin Harbron" "Cartridge.Name" "6 Digit Score Display (1998) (Robin Harbron) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "6d475019ea30d0b29f695e9dcfd8f730" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (Alpha 2) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "6d74ebaba914a5cfc868de9dd1a5c434" "Cartridge.Name" "Fortress (Smooth Version) (20-04-2003) (CT)" "" "Cartridge.MD5" "6d842c96d5a01967be9680080dd5be54" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AB-035-04" "Cartridge.Name" "Pitfall II (1984) (Activision)" "" "Cartridge.MD5" "6d8a04ee15951480cb7c466e5951eee0" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Kanguru (1983) (Zirok)" "Cartridge.Note" "AKA Kangaroo" "" "Cartridge.MD5" "6d9afd70e9369c2a6bff96c4964413b7" "Cartridge.Name" "Time Warp (Unknown) (PAL)" "" "Cartridge.MD5" "6dda84fb8e442ecf34241ac0d1d91d69" "Cartridge.Manufacturer" "Atari - GCC, Douglas B. Macrae" "Cartridge.ModelNo" "CX2677" "Cartridge.Name" "Dig Dug (1983) (Atari)" "" "Cartridge.MD5" "6de924c2297c8733524952448d54a33c" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1006" "Cartridge.Name" "Moon Patrol (1983) (CCE)" "" "Cartridge.MD5" "6dfad2dd2c7c16ac0fa257b6ce0be2f0" "Cartridge.Manufacturer" "Parker Brothers, Larry Gelberg" "Cartridge.ModelNo" "PB5065" "Cartridge.Name" "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6e179eee3d4631a7434d40cf7aeea6e8" "Cartridge.Manufacturer" "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin" "Cartridge.ModelNo" "007" "Cartridge.Name" "Halloween (1983) (Wizard Video Games) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6e19428387686a77d8c8d2f731cb09e0" "Cartridge.Name" "Purple Cross Demo (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "6e372f076fb9586aff416144f5cfe1cb" "Cartridge.Manufacturer" "Atari, Tod Frye - Sears" "Cartridge.ModelNo" "CX2646 - 49-75185" "Cartridge.Name" "Pac-Man (1982) (Atari)" "" "Cartridge.MD5" "6e4521989a60a0ddf4ff1fc6e6e5fc3d" "Cartridge.Name" "Star Fire (01-05-2002) (MP)" "" "Cartridge.MD5" "6e59dd52f88c00d5060eac56c1a0b0d3" "Cartridge.Manufacturer" "Atari, Bob Smith" "Cartridge.ModelNo" "CX2648" "Cartridge.Name" "Video Pinball (1981) (Atari) (PAL)" "" "Cartridge.MD5" "6e5d5ba193d2540aec2e847aafb2a5fb" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.14) (Retroactive) (NTSC)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6e7ed74082f39ad4166c823765a59909" "Cartridge.Name" "Poker Squares (V0.14) (2001) (B. Watson)" "" "Cartridge.MD5" "6ed5012793f5ddf4353a48c11ea9b8d3" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix - Down on the Line (3 of 3) (1983) (Arcadia)" "Cartridge.Note" "Uses Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 70" "" "Cartridge.MD5" "6ed6bda5c42b2eb7a21c54e5b3ace3e3" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Ice Hockey (Canal 3)" "" "Cartridge.MD5" "6efe876168e2d45d4719b6a61355e5fe" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG207" "Cartridge.Name" "Mission 3,000 A.D. (1983) (BitCorp) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6f084daf265599f65422ef4173b69bc7" "Cartridge.Name" "Music Kit (V2.0) - Song Player (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "6f2aaffaaf53d23a28bf6677b86ac0e3" "Cartridge.Manufacturer" "U.S. Games Corporation - Vidtec - JWDA, Garry Kitchen" "Cartridge.ModelNo" "VC1001" "Cartridge.Name" "Space Jockey (1982) (U.S. Games)" "" "Cartridge.MD5" "6f3e3306da2aa6e74a5e046ff43bf028" "Cartridge.Name" "Defender Arcade (Genesis)" "Cartridge.Note" "Genesis controller (C is smartbomb)" "Cartridge.Rarity" "Hack of Defender 2" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "6f74ed915ffe73b524ef0f63819e2a1d" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "An Exercise In Minimalism (V2) (1999) (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "6f75d72e4cf996100ccdd163d57bdac2" "Cartridge.Name" "Star Fire (200203) (MP)" "" "Cartridge.MD5" "6fa0ac6943e33637d8e77df14962fbfc" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.Name" "Cubicolor (1982) (Imagic) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "6fac680fc9a72e0e54255567c72afe34" "Cartridge.Name" "Superman (Unknown) (PAL)" "" "Cartridge.MD5" "6fbd05b0ad65b2a261fa154b34328a7f" "Cartridge.Name" "Boardgame Demo (20-12-2002) (CT)" "" "Cartridge.MD5" "6fc0176ccf53d7bce249aeb56d59d414" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-004" "Cartridge.Name" "Pyramid War (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Chopper Command" "" "Cartridge.MD5" "6fc27a9233fc69d28d3f190b4ff80f03" "Cartridge.Name" "UFO #6 (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Pepsi Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "6fc394dbf21cf541a60e3b3631b817f1" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "720020-2A, IA3611P" "Cartridge.Name" "Dragonfire (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "6fd7c7057eeab273b29c7aafc7429a96" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-018, AX-018-04" "Cartridge.Name" "Pitfall! (1982) (Activision) (16K)" "" "Cartridge.MD5" "6fe67f525c39200a798985e419431805" "Cartridge.Manufacturer" "Atari - GCC, Kevin Osborn" "Cartridge.ModelNo" "CX2689, CX2689P" "Cartridge.Name" "Kangaroo (1983) (Atari) (PAL)" "" "Cartridge.MD5" "6ff4156d10b357f61f09820d03c0f852" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2612 - 99804, 49-75103" "Cartridge.Name" "Street Racer (1977) (Atari) (4K)" "Cartridge.Note" "Uses the Paddle Controllers (swapped)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 60" "" "Cartridge.MD5" "6ffc95108e5add6f9b8abcaf330be835" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "TP Bug (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "700a786471c8a91ec09e2f8e47f14a04" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Hard-Head (1983) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "703d32062436e4c20c48313dff30e257" "Cartridge.Name" "Moving Maze Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "703f0f7af350b0fa29dfe5fbf45d0d75" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "P460" "Cartridge.Name" "4 Game in One Dark Green (1983) (BitCorp) (PAL)" "Cartridge.Note" "Rodeo Champ, Bobby is Going Home, Open Sesame, Festival" "Cartridge.Type" "4IN1" "" "Cartridge.MD5" "705fe719179e65b0af328644f3a04900" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2653 - 6-99823, 49-75111" "Cartridge.Name" "Slot Machine (1979) (Atari) (4K) [a]" "" "Cartridge.MD5" "706e3cc4931f984447213b92d1417aff" "Cartridge.Name" "Joustpong (06-07-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "707ecd80030e85751ef311ced66220bc" "Cartridge.Name" "Double-Height 6-Digit Score Display (Background Color Change) (2001) (AD)" "" "Cartridge.MD5" "7096a198531d3f16a99d518ac0d7519a" "Cartridge.Manufacturer" "Telesys, Jim Rupp" "Cartridge.ModelNo" "1004" "Cartridge.Name" "Ram It (1983) (Telesys)" "" "Cartridge.MD5" "709910c2e83361bc4bf8cd0c20c34fbf" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-006" "Cartridge.Name" "Netmaker (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Amidar" "" "Cartridge.MD5" "70a8480cfaf08776e5420365732159d2" "Cartridge.Manufacturer" "Rob Kudla" "Cartridge.Name" "Horizontally Scrolling Playfield Thing (Rob Kudla) (PD)" "" "Cartridge.MD5" "70ce036e59be92821c4c7fd735ec6f68" "Cartridge.Manufacturer" "Activision, Steve Cartwright - Ariola" "Cartridge.ModelNo" "EAX-031, EAX-031-04B - 711 031-717" "Cartridge.Name" "Frostbite (1983) (Activision) (PAL) (16K)" "" "Cartridge.MD5" "70d14c66c319683b4c19abbe0e3db57c" "Cartridge.Name" "Oystron (V2.82) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "710497df2caab69cdcc45e919c69e13f" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "5 AR-4200" "Cartridge.Name" "Labyrinth (Escape from the Mindmaster Beta) (1982) (Arcadia) [a]" "" "Cartridge.MD5" "713fde2af865b6ec464dfd72e2ebb83e" "Cartridge.Name" "Challenge (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "71464c54da46adae9447926fdbfc1abe" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Bruce Pedersen - INTV" "Cartridge.ModelNo" "MT5663" "Cartridge.Name" "Lock 'n' Chase (1982) (M Network)" "" "Cartridge.MD5" "714e13c08508ee9a7785ceac908ae831" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83123" "Cartridge.Name" "Parachute (1983) (Home Vision) (PAL)" "" "Cartridge.MD5" "715dbf2e39ba8a52c5fe5cdd927b37e0" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.ModelNo" "3135" "Cartridge.Name" "S.A.C. Alert (1983) (Amiga) (Prototype)" "Cartridge.Note" "Uses Joyboard" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "715dd9e0240638d441a3add49316c018" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "128-in-1 Junior Console (Chip 2 of 4) (1991) (Atari) (PAL)" "Cartridge.Note" "Actually contains only 16 games, not 32" "Cartridge.Type" "16IN1" "" "Cartridge.MD5" "7187118674ff3c0bb932e049d9dbb379" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Keystone Keypers (1983) (Zirok)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "718ae62c70af4e5fd8e932fee216948a" "Cartridge.Manufacturer" "Data Age, J. Ray Dettling" "Cartridge.ModelNo" "112-006" "Cartridge.Name" "Journey Escape (1983) (Data Age)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "718ee85ea7ec27d5bea60d11f6d40030" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Ghostbusters II (1992) (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7197b6cbde6ecd10376155e6b848e80d" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Multi-Sprite Game V2.1 (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "71b193f46c88fb234329855452dfac5b" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Atlantis (1983) (Digitel)" "" "Cartridge.MD5" "71d005b60cf6e608d04efb99a37362c3" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2643" "Cartridge.Name" "Codebreaker (1978) (Atari) (PAL) (4K) [a]" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.YStart" "57" "" "Cartridge.MD5" "71f09f128e76eb14e244be8f44848759" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Time Race (Funvision) (PAL)" "Cartridge.Note" "AKA Time Warp" "" "Cartridge.MD5" "71f8bacfbdca019113f3f0801849057e" "Cartridge.Manufacturer" "Atari, Dan Hitchens" "Cartridge.ModelNo" "CX26126" "Cartridge.Name" "Elevator Action (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "72097e9dc366900ba2da73a47e3e80f5" "Cartridge.Name" "Euchre (15-06-2001) (Eric Eid) (PD)" "" "Cartridge.MD5" "721a5567f76856f6b50a6707aa8f8316" "Cartridge.Manufacturer" "Activision, David Crane, Dan Kitchen" "Cartridge.ModelNo" "EAG-108-04, EAZ-108-04B" "Cartridge.Name" "Ghostbusters (1985) (Activision) (PAL) [a]" "" "Cartridge.MD5" "72305c997f2cec414fe6f8c946172f83" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4000, AR-4100" "Cartridge.Name" "Phaser Patrol (1982) (Arcadia) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "724613effaf7743cbcd695fab469c2a8" "Cartridge.Name" "Super-Ferrari (Unknown)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "728152f5ae6fdd0d3a9b88709bee6c7a" "Cartridge.Manufacturer" "Spectravideo, Mark Turmell" "Cartridge.ModelNo" "SA-217" "Cartridge.Name" "Gas Hog (1983) (Spectravideo)" "" "Cartridge.MD5" "72876fd7c7435f41d571f1101fc456ea" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "688.383 9" "Cartridge.Name" "Die Ente und der Wolf (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Pooyan" "Display.YStart" "26" "Display.Height" "256" "" "Cartridge.MD5" "72a46e0c21f825518b7261c267ab886e" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Computer Magic" "Cartridge.ModelNo" "99005, 6220, 6250" "Cartridge.Name" "Robin Hood (1983) (Xonox)" "Display.YStart" "31" "Display.Height" "220" "" "Cartridge.MD5" "72a5b5052272ac785fa076709d16cef4" "Cartridge.Name" "KC Munckin (29-01-2003) (J. Parlee)" "" "Cartridge.MD5" "72bda70c75dfa2365b3f8894bace9e6a" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Atlantis (TJ) (Hack)" "Cartridge.Note" "Hack of Atlantis" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "72d0acb5de0db662de0360a6fc59334d" "Cartridge.Name" "Cosmic Ark (Unknown) (PAL)" "" "Cartridge.MD5" "72db1194b1cc7d45b242f25eb1c148d3" "Cartridge.Name" "Pac-Man (1981) (Atari) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "72fd08deed1d6195942e0c6f392e9848" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "0701-406" "Cartridge.Name" "2 Pak Special - Wall Defender, Planet Patrol (1990) (HES) (PAL)" "" "Cartridge.MD5" "72ffbef6504b75e69ee1045af9075f66" "Cartridge.Manufacturer" "Atari, Richard Maurer - Sears" "Cartridge.ModelNo" "CX2632 - 49-75153" "Cartridge.Name" "Space Invaders (1980) (Atari)" "" "Cartridge.MD5" "73158ea51d77bf521e1369311d26c27b" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Challenge (Zellers)" "Display.YStart" "25" "" "Cartridge.MD5" "73521c6b9fed6a243d9b7b161a0fb793" "Cartridge.Manufacturer" "Atari, Tom Reuterdahl" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Miniaturer Golf (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Miniature Golf" "" "Cartridge.MD5" "736388d73198552d77d423962000006f" "Cartridge.Manufacturer" "Dactari" "Cartridge.Name" "Tennis (Dactari) (4K)" "" "Cartridge.MD5" "73a710e621d44e97039d640071908aef" "Cartridge.Name" "Barber Pole Demo (PD)" "" "Cartridge.MD5" "73aa02458b413091ac940c0489301710" "Cartridge.Manufacturer" "Quelle - Otto Versand" "Cartridge.ModelNo" "463.574 4 - 781393, 986153" "Cartridge.Name" "Kampf dem Steinfresser (1983) (Quelle) (PAL)" "Cartridge.Note" "Boom Bang (AKA Crackpots)" "" "Cartridge.MD5" "73b4e8f8b04515d91937510e680214bc" "Cartridge.Name" "Rubik's Cube Demo 3 (24-12-2002) (CT)" "" "Cartridge.MD5" "73c545db2afd5783d37c46004e4024c2" "Cartridge.Manufacturer" "CBS Electronics - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV" "Cartridge.ModelNo" "4L1767, 4L1768, 4L1769, 4L1770" "Cartridge.Name" "Smurf - Schtroumpfs (1983) (CBS Electronics) (PAL)" "Cartridge.Note" "Pitufo" "" "Cartridge.MD5" "73c839aff6a055643044d2ce16b3aaf7" "Cartridge.Manufacturer" "Activision, Alan Miller - Ariola" "Cartridge.ModelNo" "EAX-016, PAX-016 - 711 016-725" "Cartridge.Name" "StarMaster (1982) (Activision) (PAL)" "Cartridge.Note" "Use Color/BW switch to change between galactic chart and front views" "" "Cartridge.MD5" "73cb1f1666f3fd30b52b4f3d760c928f" "Cartridge.Name" "Mines of Minos (Unknown) (PAL)" "Display.Height" "225" "Display.Phosphor" "YES" "" "Cartridge.MD5" "73e66e82ac22b305eb4d9578e866236e" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Unknown Datatech Game (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "73efa9f3cbe197f26e0fb87132829232" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-858" "Cartridge.Name" "Tennis (1983) (CCE) (4K)" "" "Cartridge.MD5" "74023e0f2e739fc5a9ba7caaeeee8b6b" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Fishing Derby (Jone Yuan) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "740a7fa80f52cc7287ba37677afb6b21" "Cartridge.Name" "Double Dragon (PAL) (Genesis)" "Cartridge.Note" "Genesis controller (C is jumpkick)" "Cartridge.Rarity" "Hack of Double Dragon" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "740b47df422372fbef700b42cea4e0bf" "Cartridge.Name" "Dizzy Wiz (2001) (B. Watson)" "" "Cartridge.MD5" "740f39e71104e90416c29a73560b9c6b" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "TE016643" "Cartridge.Name" "Diagnostic Test Cartridge 2.6P (1982) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "742de93b8d849220f266b627fbabba82" "Cartridge.Name" "SCSIcide (25-02-2001) (Chris Wilkson) (PD)" "" "Cartridge.MD5" "7450ae4e10ba8380c55b259d7c2b13e8" "Cartridge.Name" "Register Twiddler Demo 2 (PD)" "" "Cartridge.MD5" "7454786af7126ccc7a0c31fcf5af40f1" "Cartridge.Name" "Tanks But No Tanks (Unknown) (PAL)" "" "Cartridge.MD5" "7465b06b6e25a4a6c6d77d02242af6d6" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26193" "Cartridge.Name" "8 in 1 (01-16-92) (Atari) (Prototype)" "Cartridge.Note" "Game 2 is Centipede, but doesn't work" "Cartridge.Rarity" "Prototype" "Cartridge.Type" "8IN1" "" "Cartridge.MD5" "7481f0771bff13885b2ff2570cf90d7b" "Cartridge.Manufacturer" "Arcadia Corporation, Brian McGhie" "Cartridge.ModelNo" "AR-4104" "Cartridge.Name" "Rabbit Transit (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "749fec9918160921576f850b2375b516" "Cartridge.Manufacturer" "Spectravision - Spectravideo" "Cartridge.ModelNo" "SA-205" "Cartridge.Name" "China Syndrome (1982) (Spectravision)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "74ca9bdc91ee387a5bd929b73aec5c2c" "Cartridge.Name" "Star Fire - New Shields (03-04-2003) (MP)" "" "Cartridge.MD5" "74d072e8a34560c36cacbc57b2462360" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC002" "Cartridge.Name" "Seahawk (1982) (Sancho) (PAL)" "" "Cartridge.MD5" "74ebaca101cc428cf219f15dda84b6f8" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-007, CAG-007" "Cartridge.Name" "Tennis (1981) (Activision) (8K)" "" "Cartridge.MD5" "74f623833429d35341b7a84bc09793c0" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Radar (Zellers)" "Cartridge.Note" "AKA Exocet" "" "Cartridge.MD5" "75028162bfc4cc8e74b04e320f9e6a3f" "Cartridge.Manufacturer" "Atari, Greg Easter, Mimi Nyden" "Cartridge.ModelNo" "CX26107" "Cartridge.Name" "Snow White (02-09-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7511c34518a9a124ea773f5b0b5c9a48" "Cartridge.Name" "Donkey Kong (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "75169c08b56e4e6c36681e599c4d8cc5" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Hal Finney - INTV" "Cartridge.ModelNo" "MT5666" "Cartridge.Name" "Astroblast (1982) (M Network)" "Cartridge.Note" "Can also use left joystick" "Cartridge.Rarity" "Uncommon" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 55" "" "Cartridge.MD5" "753375d183c713cfa0aa7298d1f3067b" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4102" "Cartridge.Name" "Suicide Mission (1982) (Arcadia) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7550b821ee56fb5833dca2be88622d5a" "Cartridge.Name" "Multiple Moving Objects Demo (B. Watson)" "" "Cartridge.MD5" "75511bb694662301c9e71df645f4b5a7" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAG-011, PAG-011 - 711 011-715" "Cartridge.Name" "Stampede (1981) (Activision) (PAL)" "" "Cartridge.MD5" "755fed16b48e81de05130708a905d00d" "Cartridge.Manufacturer" "SnailSoft" "Cartridge.Name" "Comitoid beta 3 (SnailSoft)" "" "Cartridge.MD5" "756ca07a65a4fbbedeb5f0ddfc04d0be" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX2629, CX2629P" "Cartridge.Name" "Sky Diver (1979) (Atari) (PAL)" "" "Cartridge.MD5" "7574480ae2ab0d282c887e9015fdb54c" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (1984) (Atari)" "" "Cartridge.MD5" "7576dd46c2f8d8ab159d97e3a3f2052f" "Cartridge.Manufacturer" "Goliath - Hot Shot" "Cartridge.ModelNo" "83-112" "Cartridge.Name" "Time Machine (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Asteroid Fire" "" "Cartridge.MD5" "757f529026696e13838364dea382a4ed" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAX-014, PAX-014, EAX-014-04B, EAX-014-04I - 711 014-720" "Cartridge.Name" "Grand Prix (1982) (Activision) (PAL)" "" "Cartridge.MD5" "75a303fd46ad12457ed8e853016815a0" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "715-111 - GN-060" "Cartridge.Name" "Immies & Aggies (1983) (ZiMAG) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "75b22fdf632d76e246433db1ebccd3c4" "Cartridge.Name" "Skeleton+ (05-05-2003) (Eric Ball) (PAL)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "75b557be7f08db84ec5b242207b9f241" "Cartridge.Name" "Space Treat (30-12-2002) (Fabrizio Zavagli) [a1]" "" "Cartridge.MD5" "75e276ba12dc4504659481c31345703a" "Cartridge.Manufacturer" "Arcadia Corporation, Kevin Norman" "Cartridge.ModelNo" "AR-4103" "Cartridge.Name" "Killer Satellites (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "75e8d8b9e9c5c67c2226dbfd77dcfa7d" "Cartridge.Name" "2600 Digital Clock (V b1) (PD)" "" "Cartridge.MD5" "75ea128ba96ac6db8edf54b071027c4e" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Slot Machine (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "75ea60884c05ba496473c23a58edf12f" "Cartridge.Manufacturer" "Atari, Howard Scott Warshaw - Sears" "Cartridge.ModelNo" "CX2655 - 49-75167" "Cartridge.Name" "Yars' Revenge (1982) (Atari) (PAL) [a]" "Cartridge.Note" "ROM must be started in bank 0" "Display.Phosphor" "YES" "" "Cartridge.MD5" "75ee371ccfc4f43e7d9b8f24e1266b55" "Cartridge.Manufacturer" "Atari, Greg Easter, Mimi Nyden" "Cartridge.ModelNo" "CX26107" "Cartridge.Name" "Snow White (11-09-1982) (Atari) (Prototype)" "Cartridge.Note" "ROM must be started in bank 0" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7608abdfd9b26f4a0ecec18b232bea54" "Cartridge.Manufacturer" "Atari, Bob Whitehead" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "NFL Football (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Football" "" "Cartridge.MD5" "7623a639a6fffdb246775fe2eabc8d01" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-005, CAG-005, AG-005-04" "Cartridge.Name" "Skiing (1980) (Activision) (8K)" "" "Cartridge.MD5" "7628d3cadeee0fd2e41e68b3b8fbe229" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fishing Derby (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "7648e72a5b5899076688df18a1ddcf72" "Cartridge.Manufacturer" "CBS Electronics, Richard K. Balaska Jr., Andy Frank, Stuart Ross" "Cartridge.ModelNo" "4L 2520 5000" "Cartridge.Name" "Tunnel Runner (1983) (CBS Electronics) (Prototype)" "Cartridge.Note" "Black Box" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "76809eb1ee0db8a318308a5cdda0f4e2" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (1983) (Atari) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "769ddc995dbb9edb8167efcea9f34a7c" "Cartridge.Name" "H.E.R.O. (Genesis)" "Cartridge.Note" "Genesis controller (B is laser, C is dynamite)" "Cartridge.Rarity" "Hack of H.E.R.0." "Controller.Left" "GENESIS" "" "Cartridge.MD5" "76a9bf05a6de8418a3ebc7fc254b71b4" "Cartridge.Manufacturer" "VideoSoft, Jerry Lawson, Dan McElroy" "Cartridge.ModelNo" "VS1008" "Cartridge.Name" "Color Bar Generator (1984) (VideoSoft)" "" "Cartridge.MD5" "76c685d1a60c0107aa54a772113a2972" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (3 of 3) (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "76c88341017eae660efc6e49c4b6ab40" "Cartridge.Name" "Indiana Pitfall (Hack)" "Cartridge.Note" "Hack of Pitfall!" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "76ee917d817ef9a654bc4783e0273ac4" "Cartridge.Manufacturer" "Otto Versand" "Cartridge.ModelNo" "311377" "Cartridge.Name" "Fox & Goat (Double-Game Package) (1983) (Otto Versand) (PAL)" "Cartridge.Note" "AKA Nuts" "Display.YStart" "45" "Display.Height" "256" "" "Cartridge.MD5" "76f53abbbf39a0063f24036d6ee0968a" "Cartridge.Manufacturer" "M Network, David Akers, Joe 'Ferreira' King, Patricia Lewis Du Long, Jeff Ratcliff - INTV" "Cartridge.ModelNo" "MT7045" "Cartridge.Name" "Bump 'n' Jump (1983) (M Network)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "76f66ce3b83d7a104a899b4b3354a2f2" "Cartridge.Manufacturer" "UA Limited" "Cartridge.Name" "Cat Trax (1983) (UA Limited) (1)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "77057d9d14b99e465ea9e29783af0ae3" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-001" "Cartridge.Name" "Dragster (1980) (Activision)" "Cartridge.Note" "AKA Drag Strip" "Display.YStart" "20" "" "Cartridge.MD5" "7732e4e4cc2644f163d6650ddcc9d9df" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-333" "Cartridge.Name" "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL)" "" "Cartridge.MD5" "7778ac65d775a079f537e97cbdad541c" "Cartridge.Name" "Spider Fighter (Unknown) (PAL)" "" "Cartridge.MD5" "777aece98d7373998ffb8bc0b5eff1a2" "Cartridge.Name" "2600 Collison Demo 2 (Piero Cavina) (PD)" "" "Cartridge.MD5" "77887e4192a6b0a781530e6cf9be7199" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX2604" "Cartridge.Name" "Space War (1978) (Atari) [b1]" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "77be57d872e3f5b7ecf8d19d97f73281" "Cartridge.Name" "Basketball (208 in 1) (Unknown) (PAL)" "Cartridge.Note" "Console ports are swapped" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "77cd9a9dd810ce8042bdb9d40e256dfe" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "Evil Dead (2003) (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Haunted House" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "77d0a577636e1c9212aeccde9d0baa4b" "Cartridge.Manufacturer" "Atari, Joe Decuir" "Cartridge.ModelNo" "CX2621, CX2621P" "Cartridge.Name" "Video Olympics (1977) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXDR" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 60" "" "Cartridge.MD5" "78297db7f416af3052dd793b53ff014e" "Cartridge.Name" "Poker Squares (V0.17) (2001) (B. Watson)" "" "Cartridge.MD5" "7836794b79e8060c2b8326a2db74eef0" "Cartridge.Name" "RIOT RAM Test (26-11-2002) (Dennis Debro)" "" "Cartridge.MD5" "784176346e9422733d55c427230e5bad" "Cartridge.Manufacturer" "Activision, Alex DeMeo" "Cartridge.Name" "Title Match Pro Wrestling (1989) (Activision)" "" "Cartridge.MD5" "7860716fa5dbc0fffab93fb9a4cb4132" "Cartridge.Name" "Hangman Monkey Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "7867ee819b53d69cfcfe740f7ddca574" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "1 AR-4000, AR-4100" "Cartridge.Name" "Phaser Patrol (1982) (Arcadia) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "787ebc2609a31eb5c57c4a18837d1aee" "Cartridge.Manufacturer" "Prescott" "Cartridge.Name" "Vault Assault (19xx) (Prescott)" "" "Cartridge.MD5" "78821ef76ebc3934850d1bc1b9e4f4b0" "Cartridge.Manufacturer" "HES - Activision" "Cartridge.ModelNo" "542" "Cartridge.Name" "Hot Action Pak - Ghostbusters, Tennis, Plaque Attack (1990) (HES) (PAL)" "" "Cartridge.MD5" "78963290052fd17c6c7998305ab3a6a0" "Cartridge.Name" "Push (V0.08) (2001) (AD)" "" "Cartridge.MD5" "78b84cfb1c57b0488d674d2374e656e6" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (1 of 3) (1982) (Starpath)" "" "Cartridge.MD5" "78c2de58e42cd1faac2ea7df783eaeb3" "Cartridge.Name" "Fu Kung! (V0.07) (25-01-2003) (AD)" "" "Cartridge.MD5" "79004f84bdeee78d142e445057883169" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-830" "Cartridge.Name" "Planet Patrol (1983) (CCE)" "" "Cartridge.MD5" "791bc8aceb6b0f4d9990d6062b30adfa" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAX-018, EAX-018-04B, EAX-018-04I - 711 018-725" "Cartridge.Name" "Pitfall! (1982) (Activision) (PAL)" "Cartridge.Note" "Abenteuer im Urwald (Jungle Runner)" "" "Cartridge.MD5" "7926083ad423ed685de3b3a04a914315" "Cartridge.Manufacturer" "Barry Laws Jr." "Cartridge.Name" "Face Invaders 2 (Barry Laws Jr.) (Hack)" "Cartridge.Note" "Hack of Astroblast" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "792b1d93eb1d8045260c840b0688ec8f" "Cartridge.Manufacturer" "Kroko" "Cartridge.Name" "3E Bankswitch Test (TIA @ $00)" "" "Cartridge.MD5" "7972e5101fa548b952d852db24ad6060" "Cartridge.Manufacturer" "Atari - Sears" "Cartridge.ModelNo" "CX2627 - 6-99841" "Cartridge.Name" "Human Cannonball (1979) (Atari)" "Cartridge.Note" "AKA Cannon Man" "" "Cartridge.MD5" "798b8921276eec9e332dfcb47a2dbb17" "Cartridge.Manufacturer" "Atari - CCW, Gary Stark" "Cartridge.ModelNo" "CX26102" "Cartridge.Name" "Cookie Monster Munch (1983) (Atari) (PAL) [a]" "Cartridge.Note" "Uses Kids/Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "798cc114f1623c14085868cd3494fe8e" "Cartridge.Name" "Pins Revenge (Atari Freak 1)" "" "Cartridge.MD5" "7991e1797e5e9f311fd957e62d889dff" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide (v1.1) (2001) (Joe Grand)" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "AUTO 65" "" "Cartridge.MD5" "7996b8d07462a19259baa4c811c2b4b4" "Cartridge.Name" "Math Gran Prix (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "79ab4123a83dc11d468fb2108ea09e2e" "Cartridge.Manufacturer" "Activision - Cheshire Engineering, David Rolfe, Larry Zwick" "Cartridge.ModelNo" "AZ-037-04" "Cartridge.Name" "Beamrider (1984) (Activision)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "79b649fb812c50b4347d12e7ddbb8400" "Cartridge.Name" "Red Pong Number 2 Demo 2 (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "79c27f90591e3fdc7d2ed020ecbedeb3" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-815" "Cartridge.Name" "Seaquest (1983) (CCE) [a]" "" "Cartridge.MD5" "79d4af56036ec28f298cad964a2e2494" "Cartridge.Name" "Hangman Pac-Man Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "79d6f61da3c64688ac8e075667f8a39f" "Cartridge.Name" "Tie-Fighters (MP)" "" "Cartridge.MD5" "79e5338dbfa6b64008bb0d72a3179d3c" "Cartridge.Manufacturer" "M Network, David Akers, Patricia Lewis Du Long - INTV" "Cartridge.ModelNo" "MT4313" "Cartridge.Name" "Star Strike (1983) (M Network)" "" "Cartridge.MD5" "79fcdee6d71f23f6cf3d01258236c3b9" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Mracek" "Cartridge.ModelNo" "CX2673, CX2673P" "Cartridge.Name" "Phoenix (1983) (Atari) (PAL)" "" "Cartridge.MD5" "7a09299f473105ae1ef3ad6f9f2cd807" "Cartridge.Manufacturer" "Atari, Steve Wright" "Cartridge.ModelNo" "CX2616P" "Cartridge.Name" "Pele's Soccer (1981) (Atari) (PAL)" "Cartridge.Note" "AKA Pele's Championship Soccer" "" "Cartridge.MD5" "7a2af383014f5d810ad26d322823549d" "Cartridge.Name" "FlickerSort Demo (20-04-2002) (MP)" "" "Cartridge.MD5" "7a5463545dfb2dcfdafa6074b2f2c15e" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius Software, Mark Turmell" "Cartridge.ModelNo" "11007" "Cartridge.Name" "Turmoil (1982) (20th Century Fox)" "" "Cartridge.MD5" "7a63d7ea3f2851bcf04f0bb4ba1a3929" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (3 of 4) (1982) (Arcadia)" "" "Cartridge.MD5" "7a64a8b727c8215d945e37d565ca95a5" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX2606" "Cartridge.Name" "Slot Racers (1978) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "7a64b5a6e90619c6aacf244cdd7502f8" "Cartridge.Manufacturer" "Baroque Gaming (Brian Eno)" "Cartridge.Name" "Warring Worms (Beta 1) (2002) (Baroque Gaming)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7a7f6ab9215a3a6b5940b8737f116359" "Cartridge.Manufacturer" "Arcadia Corporation, Kevin Norman" "Cartridge.ModelNo" "AR-4103" "Cartridge.Name" "Killer Satellites (1983) (Arcadia)" "" "Cartridge.MD5" "7a93d0c029eaa72236523eedc3f19645" "Cartridge.Name" "20 Sprites at Once Demo 2 (PD)" "" "Cartridge.MD5" "7ab0917107b6ec768a5ebaadf28c497a" "Cartridge.Name" "Santa's Helper (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "7ab210f448de518fa61a5924120ba872" "Cartridge.Name" "Fortress (20-04-2003) (CT)" "" "Cartridge.MD5" "7ab2f190d4e59e8742e76a6e870b567e" "Cartridge.Manufacturer" "Apollo, Larry Martin" "Cartridge.ModelNo" "AP-2008" "Cartridge.Name" "Guardian (1982) (Apollo)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 65" "" "Cartridge.MD5" "7ac4f4fb425db38288fa07fb8ff4b21d" "Cartridge.Manufacturer" "Goliath" "Cartridge.ModelNo" "83-213" "Cartridge.Name" "Space Eagle (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Exocet" "" "Cartridge.MD5" "7ad257833190bc60277c1ca475057051" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Robert Zdybel" "Cartridge.ModelNo" "CX2668" "Cartridge.Name" "RealSports Football (1982) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7ad782952e5147b88b65a25cadcdf9e0" "Cartridge.Manufacturer" "Imagic, Dave Johnson" "Cartridge.ModelNo" "720119-1A, 03211" "Cartridge.Name" "Kwibble (1983) (Imagic) (Prototype)" "Cartridge.Note" "AKA Quick Step! Beta" "" "Cartridge.MD5" "7adbcf78399b19596671edbffc3d34aa" "Cartridge.Manufacturer" "Atari, Mimi Nyden, Joseph Tung" "Cartridge.ModelNo" "CX26152" "Cartridge.Name" "Super Baseball (1988) (Atari)" "" "Cartridge.MD5" "7af40c1485ce9f29b1a7b069a2eb04a7" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.ModelNo" "3120" "Cartridge.Name" "Mogul Maniac (1983) (Amiga)" "Cartridge.Note" "Uses the Amiga Joyboard" "" "Cartridge.MD5" "7b24bfe1b61864e758ada1fe9adaa098" "Cartridge.Manufacturer" "Atari, Chris Crawford" "Cartridge.Name" "Wizard (1980) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7b33407b2b198af74906b936ce1eecbb" "Cartridge.Manufacturer" "King Atari" "Cartridge.Name" "Ghostbuster 2 (King Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7b3cf0256e1fa0fdc538caf3d5d86337" "Cartridge.Manufacturer" "CommaVid, Joseph Biel" "Cartridge.ModelNo" "CM-009" "Cartridge.Name" "Stronghold (1983) (CommaVid)" "" "Cartridge.MD5" "7b43c32e3d4ff5932f39afcb4c551627" "Cartridge.Manufacturer" "Syncro, Daniel Wolf" "Cartridge.Name" "Kamikaze Saucers (1983) (Syncro) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Height" "222" "" "Cartridge.MD5" "7b5207e68ee85b16998bea861987c690" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "3-D Tic-Tac-Toe (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "7b6f3348dbf71ada88db0fdaf7feefe0" "Cartridge.Name" "3-D Corridor (Pink Spiral) (31-03-2003) (AD)" "" "Cartridge.MD5" "7b79beb378d1b4471def90ceccf413de" "Cartridge.Name" "Pitfall Cupcake (Hack)" "Cartridge.Note" "Hack of Pitfall" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "7b7b4ac05232490c28f9b680c72998f9" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Freeway (Zellers)" "" "Cartridge.MD5" "7b8a481e0c5aa78150b5555dff01f64e" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692" "Cartridge.Name" "Moon Patrol (05-16-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7b938c7ddf18e8362949b62c7eaa660a" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2603 - 99803, 49-75601" "Cartridge.Name" "Star Ship (1977) (Atari) (4K)" "" "Cartridge.MD5" "7ba07d4ea18bf3b3245c374d8720ad30" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (Preview) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "7bb286cb659d146af3966d699b51f509" "Cartridge.Manufacturer" "Atari - Axlon, Tod Frye" "Cartridge.ModelNo" "CX26178" "Cartridge.Name" "Save Mary! (04-03-1989) (Atari) (Prototype)" "Cartridge.Note" "AKA Saving Mary" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7bc4fd254ec8c0a25a13f02fd3f762ff" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V1.00) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7c00e7a205d3fda98eb20da7c9c50a55" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo" "Cartridge.ModelNo" "AP-2004" "Cartridge.Name" "Lost Luggage (1982) (Apollo)" "Cartridge.Note" "AKA Airport Mayhem" "" "Cartridge.MD5" "7c4a499d343fca0cef2d59dd16af621a" "Cartridge.Name" "Poker Card Demo (PD)" "" "Cartridge.MD5" "7c757bb151269b2a626c907a22f5dae7" "Cartridge.Manufacturer" "TNT Games - Sculptured Software, Adam Clayton" "Cartridge.ModelNo" "26192" "Cartridge.Name" "BMX Air Master (1989) (TNT Games) (PAL)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "7c7a4a2d505c2d0c75337c44711d8d54" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.Name" "Elf Adventure (04-22-83) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7c9b3b8b25acf2fe3b8da834f69629c6" "Cartridge.Name" "I Robot (1984) (Atari) (Prototype) [!]" "" "Cartridge.MD5" "7ca7a471d70305c673fedd08174a81e8" "Cartridge.Manufacturer" "Tim Snider" "Cartridge.Name" "Venture II (2001) (Tim Snider)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7cc77f6745e1f2b20df4a4327d350545" "Cartridge.Manufacturer" "Atari, Richard Maurer" "Cartridge.ModelNo" "CX2632, CX2632P" "Cartridge.Name" "Space Invaders (1980) (Atari) (PAL) [fixed]" "" "Cartridge.MD5" "7ccf350354ee15cd9b85564a2014b08c" "Cartridge.Name" "Big Dig (13-04-2003) (CT)" "Display.Height" "220" "" "Cartridge.MD5" "7cd379da92c93679f3b6d2548617746a" "Cartridge.Name" "Demo Image Series #5 - Clown (19-02-2003) (AD)" "" "Cartridge.MD5" "7cd900e9eccbb240fe9c37fa28f917b5" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Bi! Bi! (Jone Yuan) (PAL)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "7ced6709f091e79a2ab9575d3516a4ac" "Cartridge.Manufacturer" "Activision, Steve Cartwright - Ariola" "Cartridge.ModelNo" "EAX-027 - 711 027-722" "Cartridge.Name" "Plaque Attack (1983) (Activision) (PAL)" "" "Cartridge.MD5" "7cedffa0db65d610568b90aeca705ac6" "Cartridge.Manufacturer" "Atari, Rob Fulop - Sears" "Cartridge.ModelNo" "CX2638 - 49-75166" "Cartridge.Name" "Missile Command (1981) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7d0b49ea4fe3a5f1e119a6d14843db17" "Cartridge.Manufacturer" "Gameworld, J. Ray Dettling" "Cartridge.ModelNo" "133-008" "Cartridge.Name" "Frankenstein's Monster (1983) (Gameworld) (PAL)" "" "Cartridge.MD5" "7d1034bcb38c9b746ea2c0ae37d9dff2" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.Name" "Morse Code Tutor (1979) (Atari)" "" "Cartridge.MD5" "7d3cdde63b16fa637c4484e716839c94" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Road Runner (CCE)" "" "Cartridge.MD5" "7d483b702c44ee65cd2df22cbcc8b7ed" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.Name" "Elf Adventure (05-25-83) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7d5c3b7b908752b98e30690e2a3322c2" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Freeway (Dactari - Milmar)" "" "Cartridge.MD5" "7d726fa494f706784bafeb1b50d87f23" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (07-27-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7d903411807704e725cf3fafbeb97255" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.ModelNo" "720104-1A, 720104-1B, IA3204" "Cartridge.Name" "Cosmic Ark (Reaction) (1982) (Imagic) [selectable starfield]" "" "Cartridge.MD5" "7d93071b3e3616093a6b5a98b0315751" "Cartridge.Name" "Gunfight 2600 - Music & Bugfixes 2 (2001) (MP)" "" "Cartridge.MD5" "7d940d749e55b96b7b746519fa06f2de" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix (Preview) (1983) (Arcadia) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "" "Cartridge.MD5" "7d9c96b215d1941e87b6fb412eb9204f" "Cartridge.Name" "Othello (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "7da9de8d62fcdd3a2c545b2e720c2a61" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-001" "Cartridge.Name" "MagiCard (1981) (CommaVid) (4K)" "Cartridge.Note" "Uses the Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.YStart" "24" "" "Cartridge.MD5" "7dbc8fa2e488e3f6b87fbe0f76c5b89f" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Sound X (1996) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "7dc03a1f56d0e6a8aae3e3e50d654a08" "Cartridge.Name" "Hozer Video Demo (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "7dcbfd2acc013e817f011309c7504daa" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4000, AR-4100" "Cartridge.Name" "Phaser Patrol (1982) (Arcadia)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7dd9c5284422f729066ab22a284c8283" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-833" "Cartridge.Name" "Target Practice (1983) (CCE) [a]" "Cartridge.Note" "AKA Carnival" "Display.Height" "214" "" "Cartridge.MD5" "7dfd100bda9abb0f3744361bc7112681" "Cartridge.Manufacturer" "Telesys, Don Ruffcorn" "Cartridge.ModelNo" "1006" "Cartridge.Name" "Demolition Herby (1983) (Telesys) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7e2fe40a788e56765fe56a3576019968" "Cartridge.Manufacturer" "Activision - Imagineering, Dan Kitchen" "Cartridge.ModelNo" "AK-050-04" "Cartridge.Name" "Double Dragon (1989) (Activision)" "" "Cartridge.MD5" "7e464186ba384069582d9f0c141f7491" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "206" "Cartridge.Name" "General Re-Treat (1982) (PlayAround) (PAL)" "Cartridge.Note" "AKA Custer's Revenge" "" "Cartridge.MD5" "7e4783a59972ae2cd8384f231757ea0b" "Cartridge.Manufacturer" "Atari - Imagineering, Dan Kichen" "Cartridge.ModelNo" "CX26139P" "Cartridge.Name" "Crossbow (1988) (Atari) (PAL)" "" "Cartridge.MD5" "7e51a58de2c0db7d33715f518893b0db" "Cartridge.Manufacturer" "CBS Electronics, E.F. Dreyer, Ed Salvo" "Cartridge.ModelNo" "4L 2738 0000" "Cartridge.Name" "Mountain King (1983) (CBS Electronics) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7e52a95074a66640fcfde124fffd491a" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Mracek" "Cartridge.ModelNo" "CX2673" "Cartridge.Name" "Phoenix (1983) (Atari)" "" "Cartridge.MD5" "7e7c4c59d55494e66eef5e04ec1c6157" "Cartridge.Manufacturer" "Baroque Gaming (Brian Eno)" "Cartridge.Name" "Warring Worms (2002) (Baroque Gaming)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "7e8aa18bc9502eb57daaf5e7c1e94da7" "Cartridge.Manufacturer" "CBS Electronics - Roklan, Joe Hellesen, Joe Wagner" "Cartridge.ModelNo" "M8774, M8794" "Cartridge.Name" "Wizard of Wor (1982) (CBS Electronics)" "Cartridge.Note" "Uses the Joystick Controllers (swapped)" "Console.SwapPorts" "YES" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7e9da5cb84d5bc869854938fe3e85ffa" "Cartridge.Manufacturer" "Atari, Ian Shepard - Sears" "Cartridge.ModelNo" "CX2604 - 6-99812, 49-75106" "Cartridge.Name" "Space War (1978) (Atari) (4K)" "" "Cartridge.MD5" "7eab0284a0cd1043461d446a08d08cec" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Basic Math (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "7ead257e8b5a44cac538f5f54c7a0023" "Cartridge.Manufacturer" "Xonox, Anthony R. Henderson" "Cartridge.ModelNo" "99006, 6220" "Cartridge.Name" "Sir Lancelot (1983) (Xonox) [a1]" "" "Cartridge.MD5" "7eaf009a892f03d90682dc1e67e85f07" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Bounce! (18-03-2003) (Fabrizio Zavagli)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7eafc9827e8d5b1336905939e097aae7" "Cartridge.Manufacturer" "Atari, Mark R. Hahn" "Cartridge.Name" "Elk Attack (1987) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7eba20c2291a982214cc7cbe8d0b47cd" "Cartridge.Manufacturer" "Imagic, Dave Johnson" "Cartridge.ModelNo" "720119-1A, 03211" "Cartridge.Name" "Quick Step! (1983) (Imagic)" "" "Cartridge.MD5" "7ed61a18cebdeca0a93be1f5461731e5" "Cartridge.Manufacturer" "Dactari" "Cartridge.Name" "Skiing (Dactari) (4K)" "" "Cartridge.MD5" "7ed7130a6e4020161836414332b11983" "Cartridge.Name" "Fu Kung! (V0.05 Cuttle Card Compatible) (13-01-2003) (AD)" "" "Cartridge.MD5" "7edc8fcb319b3fb61cac87614afd4ffa" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-003" "Cartridge.Name" "Checkers (1980) (Activision) (4K)" "" "Cartridge.MD5" "7ef3ca08abde439c6ccca84693839c57" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix (1983) (Arcadia) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "7ef74879d7cb9fa0ef161b91ad55b3bb" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Vanguard (CCE)" "" "Cartridge.MD5" "7f0209cfcc3d181715463f4d6451cecf" "Cartridge.Manufacturer" "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko" "Cartridge.ModelNo" "CX2694" "Cartridge.Name" "Pole Position (05-15-1983) (Atari) (Prototype)" "Cartridge.Note" "AKA RealSports Driving" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "7f07cd2e89dda5a3a90d3ab064bfd1f6" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP234" "Cartridge.Name" "Boxen (Ariola) (PAL)" "Cartridge.Note" "AKA Boxing" "" "Cartridge.MD5" "7f430c33044e0354815392b53a9a772d" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "773-891" "Cartridge.Name" "2 Pak Special - Cavern Blaster, City War (1992) (HES) (PAL)" "" "Cartridge.MD5" "7f525b07bc98080cc8950f7284e52ede" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "128-in-1 Junior Console (Chip 4 of 4) (1991) (Atari) (PAL)" "Cartridge.Note" "Actually contains only 16 games, not 32" "Cartridge.Type" "16IN1" "" "Cartridge.MD5" "7f54fa6aa824001af415503c313262f2" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "Boom Bang (HES) (PAL)" "Cartridge.Note" "AKA Crackpots" "" "Cartridge.MD5" "7f6533386644c7d6358f871666c86e79" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines" "Cartridge.ModelNo" "CM-008" "Cartridge.Name" "Cakewalk (1983) (CommaVid)" "" "Cartridge.MD5" "7f73ac39e5e3e13e40fd8ad885561a0f" "Cartridge.Name" "Star Fire - Warping Star (13-04-2003) (MP)" "" "Cartridge.MD5" "7f790939f7eaa8c47a246c4283981f84" "Cartridge.Name" "This Planet Sucks Demo 3 (Greg Troutman) (PD)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7f819454734ddf93f83fefcffcd3e212" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Outlaw (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "7f9fbe3e00a21ea06e6ae5e0e5db2143" "Cartridge.Name" "Skate Boardin' (2002) (Skyworks)" "" "Cartridge.MD5" "7fcd1766de75c614a3ccc31b25dd5b7a" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "203" "Cartridge.Name" "Knight on the Town (1982) (PlayAround)" "Display.Height" "216" "Display.Phosphor" "YES" "" "Cartridge.MD5" "7fcd5fb59e88fc7b8473c641f44226c3" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-807" "Cartridge.Name" "Space Tunnel (1983) (CCE)" "Cartridge.Note" "AKA Cosmic Corridor, O Tunel Espacial" "Display.YStart" "32" "Display.Height" "215" "" "Cartridge.MD5" "7ff53f6922708119e7bf478d7d618c86" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-032" "Cartridge.Name" "Walker (Suntek) (PAL)" "" "Cartridge.MD5" "7ffc2d80fd49a124808315306d19868e" "Cartridge.Manufacturer" "Ishido" "Cartridge.Name" "Domino (Ishido) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "801ba40f3290fc413e8c816c467c765c" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Westward Ho! (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "803393ed29a9e9346569dd1bf209907b" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Tom Calderwood, Glenn Parker" "Cartridge.ModelNo" "CX2684" "Cartridge.Name" "Galaxian (02-04-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "804ed85eadf1ce3e93721547cbea7592" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Fishing Derby (CCE) (4K)" "" "Cartridge.MD5" "8055b9c2622136fd91edfea6df642daf" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game #1 (1983) (Activision) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "805f9a32ef97ac25f999a25014dc5c23" "Cartridge.Manufacturer" "SnailSoft" "Cartridge.Name" "Balthazar (SnailSoft)" "Cartridge.Note" "AKA Babylon 5" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8068e07b484dfd661158b3771d6621ca" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Peter Engelbrite" "Cartridge.ModelNo" "80561-00286" "Cartridge.Name" "California Games (1988) (Epyx) (PAL)" "" "Cartridge.MD5" "807841df228ee8aab0a06ee639ce5a8a" "Cartridge.Manufacturer" "Coleco - Project Guild - GMA, Michael Green, Anthony R. Henderson, Gary Littleton" "Cartridge.ModelNo" "2455" "Cartridge.Name" "Turbo (1982) (Coleco) (Prototype)" "Cartridge.Note" "Prototype" "" "Cartridge.MD5" "807a8ff6216b00d52aba2dfea5d8d860" "Cartridge.Manufacturer" "John Payson" "Cartridge.Name" "Strat-O-Gems Deluxe (2005) (J. Payson)" "Cartridge.Note" "Uses the AtariVox controller" "Cartridge.Rarity" "Homebrew" "Controller.Right" "ATARIVOX" "" "Cartridge.MD5" "808c3b1e60ee0e7c65205fa4bd772221" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Defender (CCE)" "" "Cartridge.MD5" "80cd42881e670e4b74a9ccd10d0d7b2e" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius, Ed Hodapp" "Cartridge.ModelNo" "11004" "Cartridge.Name" "Deadly Duck (1982) (20th Century Fox) [a]" "" "Cartridge.MD5" "80cec82239913cb8c4016eb13749de44" "Cartridge.Manufacturer" "David Marli" "Cartridge.Name" "Invaders from Space by David Marli (Space Invaders Hack)" "Cartridge.Note" "Hack of Space Invaders (Atari)" "Cartridge.Rarity" "New Release (Hack)" "" "Cartridge.MD5" "80e1410ec98089e0733cc09e584dba4b" "Cartridge.Manufacturer" "Dynamics" "Cartridge.ModelNo" "DY-293005" "Cartridge.Name" "Jumping Jack (1983) (Dynamics) (PAL)" "Cartridge.Note" "AKA Bobby Is Going Home" "" "Cartridge.MD5" "80e52315919bd8a8b82a407ccd9bb13f" "Cartridge.Name" "Euchre (Jul 28) (2002) (Eric Eid) (PD)" "" "Cartridge.MD5" "80e5400470ac788143e6db9bc8dd88cf" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (06-XX-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "8101efafcf0af32fedda4579c941e6f4" "Cartridge.Name" "Okie Dokie (4K) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "81073d0377a2badef8d5e74fc44fc323" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Sadoom (TJ) (PAL60) (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "Display.Format" "PAL60" "" "Cartridge.MD5" "8108162bc88b5a14adc3e031cf4175ad" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "719.941 7" "Cartridge.Name" "Vom Himmel durch die Hoelle (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Parachute" "" "Cartridge.MD5" "8108ad2679bd055afec0a35a1dca46a4" "Cartridge.Name" "Maze Craze (Unknown)" "Display.Format" "NTSC" "" "Cartridge.MD5" "810d8952af5a6036fca8d0c4e1b23db6" "Cartridge.Manufacturer" "Tiger Vision - Eram" "Cartridge.Name" "Keystone (Tiger Vision)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "81254ebce88fa46c4ff5a2f4d2bad538" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2653 - 6-99823, 49-75111" "Cartridge.Name" "Slot Machine (1979) (Atari) (4K)" "" "Cartridge.MD5" "81341f00b61ab37d19d1529f483d496d" "Cartridge.Name" "Fu Kung! (V0.04) (10-01-2003) (AD)" "" "Cartridge.MD5" "813985a940aa739cc28df19e0edd4722" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "720000-201, 720102-1B, IA3201" "Cartridge.Name" "Star Voyager (1982) (Imagic)" "" "Cartridge.MD5" "81414174f1816d5c1e583af427ac89fc" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Treasure Below (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.Height" "220" "" "Cartridge.MD5" "814210c0e121f7dbc25661b93c06311c" "Cartridge.Name" "Joustpong (16-09-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "81591a221419024060b890665beb0fb8" "Cartridge.Manufacturer" "Atari, Carla Meninsky, Ed Riddle" "Cartridge.ModelNo" "CX2611, CX2611P" "Cartridge.Name" "Indy 500 (1977) (Atari) (PAL)" "Cartridge.Note" "Uses the Driving Controllers" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "Controller.MouseAxis" "45" "" "Cartridge.MD5" "8190b403d67bf9792fe22fa5d22f3556" "Cartridge.Name" "Sky Diver (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "819aeeb9a2e11deb54e6de334f843894" "Cartridge.Manufacturer" "Atari, Gary Palmer" "Cartridge.ModelNo" "CX2661" "Cartridge.Name" "Fun with Numbers (1980) (Atari)" "Cartridge.Note" "AKA Basic Math" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "81a010abdba1a640f7adf7f84e13d307" "Cartridge.Manufacturer" "Telegames - VSS" "Cartridge.ModelNo" "7062 A305" "Cartridge.Name" "Universal Chaos (1988) (Telegames)" "Cartridge.Note" "AKA Targ" "" "Cartridge.MD5" "81b3bf17cf01039d311b4cd738ae608e" "Cartridge.Manufacturer" "CBS Electronics - Roklan, Joe Gaucher, Alex Leavens" "Cartridge.ModelNo" "M8776, M8793" "Cartridge.Name" "Gorf (1982) (CBS Electronics)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "81f4f0285f651399a12ff2e2f35bab77" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (1982) (Arcadia)" "" "Cartridge.MD5" "822a950f27ff0122870558a89a49cad3" "Cartridge.Name" "Space Jockey (Unknown) (PAL)" "" "Cartridge.MD5" "82337e5fe0f418ca9484ca851dfc226a" "Cartridge.Name" "Robot City (V1.0) (Alpha) (TJ)" "" "Cartridge.MD5" "826481f6fc53ea47c9f272f7050eedf7" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "720103-1A, IA3203" "Cartridge.Name" "Atlantis II (1982) (Imagic)" "" "Cartridge.MD5" "827a22b9dffee24e93ed0df09ff8414a" "Cartridge.Manufacturer" "CBS Electronics, Stuart Ross" "Cartridge.Name" "Wings (10-10-1983) (CBS Electronics) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8290daea8391f96d7c8e1482e184d19c" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Frame Timed Sound Effects (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "82bf0dff20cee6a1ed4bb834b00074e6" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-035" "Cartridge.Name" "Panda (Quest) (Suntek) (PAL)" "Cartridge.Note" "AKA Panda Chase" "Display.Height" "256" "" "Cartridge.MD5" "82c25d1c35e6ac6f893d1d7c2fc2f9c8" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2628, CX2628P" "Cartridge.Name" "Bowling (1979) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "82de957d155fc041fc6afb8315a28550" "Cartridge.Manufacturer" "Coleco, Joseph Biel" "Cartridge.ModelNo" "2457" "Cartridge.Name" "Venture (1982) (Coleco) (Prototype)" "Cartridge.Note" "2K" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "82e7aab602c378cffdd8186a099e807e" "Cartridge.Name" "Space Robot (Unknown)" "" "Cartridge.MD5" "82efe7984783e23a7c55266a5125c68e" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-837" "Cartridge.Name" "Pizza Chef (1983) (CCE)" "" "Cartridge.MD5" "834a2273e97aec3181ee127917b4b269" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "043.151 0, 874.382 5" "Cartridge.Name" "Die hungrigen Froesche (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Frogs and Flies" "" "Cartridge.MD5" "835759ff95c2cdc2324d7c1e7c5fa237" "Cartridge.Manufacturer" "20th Century Fox Video Games, Frank Cohen, Douglas 'Dallas North' Neubauer" "Cartridge.ModelNo" "11011" "Cartridge.Name" "M.A.S.H (1983) (20th Century Fox)" "" "Cartridge.MD5" "8372eec01a08c60dbed063c5524cdfb1" "Cartridge.Name" "Cross Force (Unknown) (PAL)" "" "Cartridge.MD5" "8388d6fe59c38c0b3a6ab2c58420036a" "Cartridge.Manufacturer" "Atari, Frank Hausman, Mimi Nyden, Steve Woita" "Cartridge.ModelNo" "CX2686" "Cartridge.Name" "Quadrun (12-06-1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "83b8c01c72306d60dd9b753332ebd276" "Cartridge.Name" "Bank Heist (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "83bdc819980db99bf89a7f2ed6a2de59" "Cartridge.Manufacturer" "Atari, Carla Meninsky - Sears" "Cartridge.ModelNo" "CX2637 - 49-75158" "Cartridge.Name" "Dodge 'Em (1980) (Atari) [fixed]" "" "Cartridge.MD5" "83d15fb9843d9f84aa3710538403f434" "Cartridge.Name" "Gunfight 2600 - Release Candidate (2001) (MP) (PAL)" "" "Cartridge.MD5" "83f05ececae8be59ba1e51135f4bdcbf" "Cartridge.Name" "Demo Image Series #13 - Mario (4K Interleaved Chronocolour) (05-03-2003) (AD)" "" "Cartridge.MD5" "83f50fa0fbae545e4b88bb53b788c341" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2643 - 6-99815" "Cartridge.Name" "Codebreaker (1978) (Atari) (4K)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "83fafd7bd12e3335166c6314b3bde528" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite" "Cartridge.ModelNo" "80561-00251" "Cartridge.Name" "Winter Games (1987) (Epyx)" "" "Cartridge.MD5" "840a5a2eaea24d95d289f514fd12f9bb" "Cartridge.Name" "GBImprov (Hack)" "Cartridge.Note" "Hack of Ghostbusters" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "841057f83ce3731e6bbfda1707cbca58" "Cartridge.Manufacturer" "Champ Games" "Cartridge.ModelNo" "CG-04-N" "Cartridge.Name" "Super Cobra Arcade (NTSC)" "Cartridge.Note" "Compatible with Genesis controller" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "841b7bc1cad05f5408302308777d49dc" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game (10-22-1982) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "84290e333ff7567c2380f179430083b8" "Cartridge.Manufacturer" "Imagic, Dave Johnson" "Cartridge.ModelNo" "13211, EIX-004-04I" "Cartridge.Name" "Quick Step! (1983) (Imagic) (PAL) [a]" "" "Cartridge.MD5" "843435eb360ed72085f7ab9374f9749a" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide (1.31) (Joe Grand)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "AUTO 65" "" "Cartridge.MD5" "84535afb9a69712ec0af4947329e08b8" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-868" "Cartridge.Name" "Bingo (1983) (CCE) (PAL)" "Cartridge.Note" "AKA Dice Puzzle" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8454ed9787c9d8211748ccddb673e920" "Cartridge.Manufacturer" "Froggo" "Cartridge.ModelNo" "FG1002" "Cartridge.Name" "Spiderdroid (1987) (Froggo)" "Cartridge.Note" "AKA Amidar" "" "Cartridge.MD5" "8490e1014c2baa0d3a3a08854e5d68b3" "Cartridge.Manufacturer" "Xonox, Anthony R. Henderson" "Cartridge.ModelNo" "99006, 6220" "Cartridge.Name" "Sir Lancelot (1983) (Xonox) [a2]" "" "Cartridge.MD5" "84db818cd4111542a15c2a795369a256" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "850ffd5849c911946b24544ea1e60496" "Cartridge.Name" "Invasion (07-10-2002) (CT)" "" "Cartridge.MD5" "851cc1f3c64eaedd10361ea26345acea" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009, AG-009-04" "Cartridge.Name" "Freeway (1981) (Activision) (4K)" "" "Cartridge.MD5" "85227160f37aaa29f5e3a6c7a3219f54" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-004" "Cartridge.Name" "Fishing Derby (1980) (Activision) (4K)" "" "Cartridge.MD5" "8530caaaf40acbdcd118c282b5f8a37a" "Cartridge.Name" "This Planet Sucks Demo 2 (Greg Troutman) (PD)" "Cartridge.Rarity" "New Release" "Display.YStart" "36" "" "Cartridge.MD5" "8538c5e3ee83267774480649f83fa8d6" "Cartridge.Name" "Escape Demo (PD)" "" "Cartridge.MD5" "853c11c4d07050c22ef3e0721533e0c5" "Cartridge.Name" "Oink! (Unknown) (PAL)" "" "Cartridge.MD5" "85470dcb7989e5e856f36b962d815537" "Cartridge.Manufacturer" "Atari - Sculptured Software, Inc., Steve Aguirre" "Cartridge.ModelNo" "CX26162" "Cartridge.Name" "Fatal Run (1989) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "85478bb289dfa5c63726b9153992a920" "Cartridge.Name" "Candi (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "854b68b93e7123a3be42b5a2a41f75d7" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX2618, CX2618P" "Cartridge.Name" "3-D Tic-Tac-Toe (1980) (Atari) (PAL) (4K)" "Display.YStart" "44" "" "Cartridge.MD5" "85502d69fe46b7f54ef2598225678b47" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Super-Ferrari (Jone Yuan)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "85564dd0665aa0a1359037aef1a48d58" "Cartridge.Manufacturer" "ITT Family Games" "Cartridge.ModelNo" "554-33 367" "Cartridge.Name" "Laser Base (1983) (ITT Family Games) (PAL) [a]" "Cartridge.Note" "AKA The End of the World (Perry Rhodan-Serie)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8556b42aa05f94bc29ff39c39b11bff4" "Cartridge.Manufacturer" "Atari, Craig Nelson - Sears" "Cartridge.ModelNo" "CX2617 - 49-75183" "Cartridge.Name" "Backgammon (1979) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "Extremely Rare" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "AUTO 80" "" "Cartridge.MD5" "855a42078b14714bcfd490d2cf57e68d" "Cartridge.Manufacturer" "Atari, Suki Lee" "Cartridge.ModelNo" "CX26113" "Cartridge.Name" "Miss Piggy's Wedding (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "24" "" "Cartridge.MD5" "85a4133f6dcf4180e36e70ad0fca0921" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-827" "Cartridge.Name" "Chopper Command (1983) (CCE)" "" "Cartridge.MD5" "85b1bca93e69f13905107cc802a02470" "Cartridge.Manufacturer" "Atari, Craig Nelson" "Cartridge.ModelNo" "CX2617, CX2617P" "Cartridge.Name" "Backgammon (1979) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "Extremely Rare" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "AUTO 80" "" "Cartridge.MD5" "85bbefb90e16bf386b304c1e9a1f6084" "Cartridge.Manufacturer" "Champ Games" "Cartridge.ModelNo" "CG-02-P" "Cartridge.Name" "Conquest Of Mars (PAL60)" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "Cartridge.MD5" "85e48d68c8d802e3ba9d494a47d6e016" "Cartridge.Name" "Ship Demo (V 15) (PD)" "" "Cartridge.MD5" "85e564dae5687e431955056fbda10978" "Cartridge.Manufacturer" "Milton Bradley Company - Renaissance Technology, Ty Roberts" "Cartridge.ModelNo" "4362" "Cartridge.Name" "Survival Run (1983) (Milton Bradley)" "Cartridge.Note" "AKA Cosmic Commander" "Display.Height" "225" "Display.Phosphor" "YES" "" "Cartridge.MD5" "86128001e69ab049937f265911ce7e8a" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Steve Stringfellow" "Cartridge.ModelNo" "AP-2005" "Cartridge.Name" "Lochjaw (1982) (Apollo)" "Display.YStart" "28" "" "Cartridge.MD5" "862cf669cbced78f9ed31a5d375b2ebe" "Cartridge.Name" "Gunfight 2600 - Flicker acceptance (2001) (MP)" "" "Cartridge.MD5" "8644352b806985efde499ae6fc7b0fec" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-801" "Cartridge.Name" "Mr. Postman (1983) (CCE)" "" "Cartridge.MD5" "8654d7f0fb351960016e06646f639b02" "Cartridge.Manufacturer" "Home Vision, R.J.P.G. - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83106" "Cartridge.Name" "Ski Hunt (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Skiiing Hunt" "" "Cartridge.MD5" "866e5150c995c4ae5172e5207ba948c7" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Stampede (Canal 3) (16K)" "" "Cartridge.MD5" "869abe0426e6e9fcb6d75a3c2d6e05d1" "Cartridge.Name" "Stampede (Unknown) (PAL)" "" "Cartridge.MD5" "86b4aa76bbeb70e1a4f9211a9880ba8e" "Cartridge.Name" "Incoming (1 Player Version) (05-11-2002) (Ben Larson)" "" "Cartridge.MD5" "86f5e55ca9a9bde7338a157570828e79" "Cartridge.Name" "Star Fire - Creating a Universe (09-09-2002) (MP) [a1]" "" "Cartridge.MD5" "8712cceec5644aacc2c21203d9ebe2ec" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.10) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8726c17ee7b559cb7bf2330d20972ad0" "Cartridge.Name" "Cave Demo (21-04-2003) (CT)" "" "Cartridge.MD5" "873fb75a7788ba0f4ae715229a05545e" "Cartridge.Name" "Euchre (Improved Colors) (PAL) (26-09-2002) (Erik Eid)" "" "Cartridge.MD5" "8747ba79cd39fa83a529bb26010db21b" "Cartridge.Manufacturer" "Atari, Richard Maurer" "Cartridge.ModelNo" "CX2632, CX2632P" "Cartridge.Name" "Space Invaders (1980) (Atari) (PAL) [different speed and colors]" "" "Cartridge.MD5" "8749a0d088df25218c149dc325abc7ca" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype) [a5]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "874c76726f68c166fcfac48ce78eef95" "Cartridge.Name" "Red Pong Number 2 Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8764462d7d19a33b0717af22b99fc88f" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Sky Jinks (CCE) (4K)" "" "Cartridge.MD5" "87662815bc4f3c3c86071dc994e3f30e" "Cartridge.Manufacturer" "Intellivision Productions - M Network, Patricia Lewis Du Long, Stephen Tatsumi" "Cartridge.Name" "Swordfight (1983) (Intellivision)" "" "Cartridge.MD5" "876a953daae0e946620cf05ed41989f4" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.08) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "877a5397f3f205bf6750398c98f33de1" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Beta) (PAL) (12-09-2002) (Erik Eid)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "8786c1e56ef221d946c64f6b65b697e9" "Cartridge.Manufacturer" "20th Century Fox Video Games, David Lubar" "Cartridge.ModelNo" "11015" "Cartridge.Name" "AKA Space Adventure" "" "Cartridge.MD5" "8786f229b974c393222874f73a9f3206" "Cartridge.Manufacturer" "Activision, Larry Miller - Ariola" "Cartridge.ModelNo" "EAX-021, EAX-021-04I - 711 021-720" "Cartridge.Name" "Spider Fighter (1983) (Activision) (PAL)" "" "Cartridge.MD5" "8786f4609a66fbea2cd9aa48ca7aa11c" "Cartridge.Manufacturer" "Goliath" "Cartridge.ModelNo" "5" "Cartridge.Name" "Open Sesame (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA I Want My Mommy" "Display.YStart" "34" "Display.Phosphor" "YES" "" "Cartridge.MD5" "87b460df21b7bbcfc57b1c082c6794b0" "Cartridge.Manufacturer" "Dennis Debro" "Cartridge.Name" "Climber 5 (20-03-2003) (Dennis Debro)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "87b6a17132fc32f576bc49ea18729506" "Cartridge.Manufacturer" "Atari, Andrew Fuchs, Courtney Granner, Jeffrey Gusman, Mark R. Hahn" "Cartridge.ModelNo" "CX2690" "Cartridge.Name" "Pengo (1984) (Atari) (PAL)" "" "Cartridge.MD5" "87bea777a34278d29b3b6029833c5422" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Polaris (1983) (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "87e79cd41ce136fd4f72cc6e2c161bee" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2675" "Cartridge.Name" "Ms. Pac-Man (1983) (Atari)" "" "Cartridge.MD5" "87f020daa98d0132e98e43db7d8fea7e" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius, David Lubar" "Cartridge.ModelNo" "11001" "Cartridge.Name" "Worm War I (1982) (20th Century Fox)" "" "Cartridge.MD5" "883258dcd68cefc6cd4d40b1185116dc" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAZ-030, EAZ-030-04B, EAZ-030-04I - 711 030-725" "Cartridge.Name" "Decathlon (1983) (Activision) (PAL)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "8874b68751fd2ba6d3306a263ae57a7d" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (Alpha 1) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "8885d0ce11c5b40c3a8a8d9ed28cefef" "Cartridge.Manufacturer" "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner - Sears" "Cartridge.ModelNo" "CX2608 - 49-75165" "Cartridge.Name" "Super Breakout (1982 - 1981) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 45" "" "Cartridge.MD5" "888debb162d7d1ae71025b4ab794257f" "Cartridge.Name" "Interleaved ChronoColour - Nude Art (17-04-2003) (AD)" "" "Cartridge.MD5" "88a6c9c88cb329ee5fa7d168bd6c7c63" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1007" "Cartridge.Name" "Jungle Hunt (1983) (CCE)" "" "Cartridge.MD5" "88d300a38bdd7cab9edad271c18cd02b" "Cartridge.Manufacturer" "Funvision - Fund. Int'l Co." "Cartridge.Name" "Pac Kong (Funvision) (PAL)" "Cartridge.Note" "AKA Inca Gold" "" "Cartridge.MD5" "88d7b6b3967de0db24cdae1c7f7181bd" "Cartridge.Manufacturer" "Atari - GCC, Dave Payne" "Cartridge.ModelNo" "CX2669" "Cartridge.Name" "Vanguard (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "88d8a1accab58cf1abb043613cf185e9" "Cartridge.Manufacturer" "Ultravison" "Cartridge.Name" "Sabotage (Ultravison)" "" "Cartridge.MD5" "88dce4037471424bb38ab6841aaa8cab" "Cartridge.Name" "Double-Height 6-Digit Score Display (Two Background Color Change) (2001) (AD)" "" "Cartridge.MD5" "88ed87c011f699dd27321dbe404db6c8" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AX-029" "Cartridge.Name" "Crackpots (1983) (Activision) (16K)" "" "Cartridge.MD5" "88f74ec75ef696e7294b7b6ac5ca465f" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-002, CAG-002, AG-002-04" "Cartridge.Name" "Boxing (1980) (Activision) (16K)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "8905d54f48b8024fc718ed643e9033f7" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (05-24-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "890c13590e0d8d5d6149737d930e4d95" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2605 - 6-99822, 49-75109" "Cartridge.Name" "Outlaw (1978) (Atari)" "" "Cartridge.MD5" "8917f7c1ac5eb05b82331cf01c495af2" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (BitCorp) (PAL) [a]" "Display.Height" "256" "" "Cartridge.MD5" "8933976f2029c0d8492ebd8f4eb21492" "Cartridge.Name" "Synthcart Plus (09-02-2003) (Paul Slocum)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "8953bc11352d794431d3303e31d3b892" "Cartridge.Manufacturer" "Tigervision, Robert H. O'Neil" "Cartridge.ModelNo" "7-007" "Cartridge.Name" "Polaris (02-17-1983) (Tigervision) (Prototype) (4K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "896ec58f26e930e02f5e4f046602c3a1" "Cartridge.Name" "Synthcart (Beta) (2002) (Paul Slocum)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.Phosphor" "YES" "" "Cartridge.MD5" "898143773824663efe88d0a3a0bb1ba4" "Cartridge.Manufacturer" "Activision - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen" "Cartridge.ModelNo" "AZ-033, AZ-033-04" "Cartridge.Name" "Space Shuttle (1983) (Activision) [FE]" "Cartridge.Note" "A Journey Into Space" "" "Cartridge.MD5" "898748d5eaac3164b0391a64ae1e0e32" "Cartridge.Name" "Hangman Man 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "898b5467551d32af48a604802407b6e8" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG208" "Cartridge.Name" "Snail Against Squirrel (1983) (BitCorp) (PAL)" "" "Cartridge.MD5" "89a65b83203980d5d4d60f52a584a5b8" "Cartridge.Name" "Marble Craze (PAL) (02-02-2003) (Paul Slocum)" "" "Cartridge.MD5" "89a68746eff7f266bbf08de2483abe55" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2696" "Cartridge.Name" "Asterix (1984) (Atari)" "Cartridge.Note" "AKA Taz" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "89afff4a10807093c105740c73e9b544" "Cartridge.Name" "Pooyan (Unknown) (PAL)" "" "Cartridge.MD5" "89eaba47a59cbfd26e74aad32f553cd7" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2001" "Cartridge.Name" "Spacechase (1982) (Apollo) (PAL)" "" "Cartridge.MD5" "8a159ee58b2f0a54805162984b0f07e5" "Cartridge.Manufacturer" "Atari - Sculptured Software, Inc., Steve Aguirre" "Cartridge.ModelNo" "CX26162" "Cartridge.Name" "Fatal Run (1989) (Atari) (PAL) [a]" "" "Cartridge.MD5" "8a183b6357987db5170c5cf9f4a113e5" "Cartridge.Manufacturer" "Atari - Roklan, Joe Gaucher" "Cartridge.ModelNo" "CX2679" "Cartridge.Name" "RealSports Basketball (1983) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "8a42e2c7266439d8997a55d0124c912c" "Cartridge.Name" "Hangman Invader Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "8a49cf1785e3dea2012d331a3ad476e1" "Cartridge.Name" "Boulderdash (10 Blocks Wide) (02-04-2003) (AD)" "" "Cartridge.MD5" "8a6c84f481acf42abcb78ba5064ad755" "Cartridge.Manufacturer" "128-in-1 Junior Console" "Cartridge.Name" "Street Racer (128-in-1 Junior Console) (PAL) (4K)" "Cartridge.Note" "Uses the Paddle Controllers (swapped)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 75" "" "Cartridge.MD5" "8a8e401369e2b63a13e18a4d685387c6" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAG-008, PAG-008, EAG-008-04I - 711 008-720" "Cartridge.Name" "Laser Blast (1981) (Activision) (PAL)" "" "Cartridge.MD5" "8a9d874a38608964f33ec0c35cab618d" "Cartridge.Manufacturer" "Chris Cracknell" "Cartridge.Name" "Rescue Bira Bira (Chris Cracknell)" "Cartridge.Note" "Hack of Jungle Fever" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8a9d953ac3db52a313a90d6a9b139c76" "Cartridge.Name" "Hangman Invader Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "8aad33da907bed78b76b87fceaa838c1" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Air-Sea Battle (32 in 1) (1988) (Atari) (PAL)" "Display.Height" "256" "" "Cartridge.MD5" "8ac18076d01a6b63acf6e2cab4968940" "Cartridge.Manufacturer" "Atari, Dan Hitchens, Mimi Nyden" "Cartridge.ModelNo" "CX2685" "Cartridge.Name" "Gravitar (1983) (Atari)" "" "Cartridge.MD5" "8af58a9b90b25907da0251ec0facf3b8" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Cosmic Swarm (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8b04e9d132b8e30d447acaa6bd049c32" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (1982) (Starpath) (PAL)" "" "Cartridge.MD5" "8b40a9ca1cfcd14822e2547eaa9df5c1" "Cartridge.Manufacturer" "Parker Brothers - Western Technologies, Dave Hampton, Tom Sloper" "Cartridge.ModelNo" "931517" "Cartridge.Name" "Q-bert (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "8b504b417c8626167a7e02f44229f0e7" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V1.00) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8b556c3d9ca8e5e6e665bd759b93ffae" "Cartridge.Name" "Synthcart (2002) (Paul Slocum) (PAL) [!]" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8b5b1e3a434ebbdc2c2a49dc68f46360" "Cartridge.Manufacturer" "CBS Electronics - Woodside Design Associates - Imaginative Systems Software, Dan Kitchen, Garry Kitchen" "Cartridge.ModelNo" "4L1700, 4L1701, 4L1702, 4L1802, 4L2274" "Cartridge.Name" "Donkey Kong (1983) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "8b7ca29a55432f886cee3d452fb00481" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum, Jon Leupp" "Cartridge.ModelNo" "11 AR-4201" "Cartridge.Name" "Sword of Saros (1983) (Starpath) (PAL)" "" "Cartridge.MD5" "8b8152d6081f31365406cb716bd95567" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX2626, CX2626P" "Cartridge.Name" "Miniature Golf (1979) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "8b8789c6669a4cee86c579a65332f852" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Plaque Attack (Digivision)" "" "Cartridge.MD5" "8bbfd951c89cc09c148bfabdefa08bec" "Cartridge.Manufacturer" "UA Limited" "Cartridge.Name" "Pleiades (1983) (UA Limited) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8bc0d2052b4f259e7a50a7c771b45241" "Cartridge.Manufacturer" "Xonox - K-Tel Software, Anthony R. Henderson" "Cartridge.ModelNo" "99007, 6240" "Cartridge.Name" "Tomarc the Barbarian (1983) (Xonox) [a]" "Cartridge.Note" "AKA Thundarr the Barbarian" "Display.YStart" "24" "" "Cartridge.MD5" "8bd8f65377023bdb7c5fcf46ddda5d31" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-019" "Cartridge.Name" "Sky Jinks (1982) (Activision) (4K)" "" "Cartridge.MD5" "8bebac614571135933116045204f0f00" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (Trakball) (2002) (TJ) (PAL)" "Cartridge.Note" "Uses the Trakball Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "TRAKBALL" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8c103a79b007a2fd5af602334937b4e1" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Laser Base (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.Height" "240" "" "Cartridge.MD5" "8c136e97c0a4af66da4a249561ed17db" "Cartridge.Name" "Poker Squares (V0.27) (2001) (B. Watson)" "" "Cartridge.MD5" "8c2fa33048f055f38358d51eefe417db" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83137" "Cartridge.Name" "Teddy Apple (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA I Want My Mommy" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8c36ed2352801031516695d1eeefe617" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Tod Frye, Peter Engelbrite" "Cartridge.ModelNo" "80561-00251" "Cartridge.Name" "Winter Games (1987) (Epyx) (PAL)" "" "Cartridge.MD5" "8c7e5e2329f4f4e06cbcc994a30fd352" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1004" "Cartridge.Name" "Airlock (1982) (Data Age) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "8c8a26ed57870daba8e13162d497bad1" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "2 Pak Special - Dolphin, Oink (1990) (HES) (PAL)" "" "Cartridge.MD5" "8c8b15b3259e60757987ed13cdd74d41" "Cartridge.Manufacturer" "Supergame" "Cartridge.ModelNo" "71" "Cartridge.Name" "River Raid (1984) (Supergame)" "" "Cartridge.MD5" "8c941fa32c7718a10061d8c328909577" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "River Raid (Digivision)" "" "Cartridge.MD5" "8ccaa442d26b09139685f5b22bf189c4" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V1.01) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8cd26dcf249456fe4aeb8db42d49df74" "Cartridge.Manufacturer" "Atari - Imagineering, Dan Kichen" "Cartridge.ModelNo" "CX26139" "Cartridge.Name" "Crossbow (1988) (Atari)" "" "Cartridge.MD5" "8ce9126066f2ddd5173e9f1f9ce1494e" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (Trakball) (2002) (TJ)" "Cartridge.Note" "Uses the Trakball Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "TRAKBALL" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8cf0d333bbe85b9549b1e6b1e2390b8d" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.ModelNo" "CX2649, CX2649P" "Cartridge.Name" "Asteroids (1981) (Atari) (PAL)" "Cartridge.Rarity" "Common" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8d00a38f4c8f8800f1c237215ac243fc" "Cartridge.Name" "3-D Corridor (Green) (30-03-2003) (AD)" "" "Cartridge.MD5" "8d1e2a6d2885966e6d86717180938f87" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (Amiga Mouse) (2002) (TJ)" "Cartridge.Note" "Uses Amiga Mouse Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "AMIGAMOUSE" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8d8b7d7b983f75debbdaac651e814768" "Cartridge.Name" "Demo Image Series #15 - Three Marios (PAL) (06-03-2003) (AD)" "" "Cartridge.MD5" "8d9a06101ebb0f147936356e645309b8" "Cartridge.Name" "Grid Pattern Demo 2 (20-12-2002) (CT)" "" "Cartridge.MD5" "8da51e0c4b6b46f7619425119c7d018e" "Cartridge.Manufacturer" "Atari - Imagineering, David Lubar" "Cartridge.ModelNo" "CX26183" "Cartridge.Name" "Sentinel (1991) (Atari)" "Cartridge.Note" "Uses the Light Gun Controller (left only)" "" "Cartridge.MD5" "8db152458abaef3cfa7a4e420ddbda59" "Cartridge.Name" "Keystone Kapers (Unknown)" "" "Cartridge.MD5" "8df4be9ddc54ac363b13dc57ceaf161a" "Cartridge.Manufacturer" "Scott Stilphen" "Cartridge.Name" "Asteroids SS (Scott Stilphen) (Hack)" "Cartridge.Note" "Hack of Asteroids" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8e0ab801b1705a740b476b7f588c6d16" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-009, AG-009-04" "Cartridge.Name" "Freeway (1981) (Activision)" "" "Cartridge.MD5" "8e42674972d6805068fc653e014370fd" "Cartridge.Name" "Skeleton (PAL) (15-10-2002) (Eric Ball)" "" "Cartridge.MD5" "8e48ea6ea53709b98e6f4bd8aa018908" "Cartridge.Manufacturer" "CBS Electronics, Stuart Ross" "Cartridge.Name" "Wings (06-03-1983) (CBS Electronics) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8e4cd60d93fcde8065c1a2b972a26377" "Cartridge.Manufacturer" "Imagic, Dan Oliver" "Cartridge.ModelNo" "720118-2A, 13208, EIX-007-04I" "Cartridge.Name" "Laser Gates (1983) (Imagic) (PAL)" "Cartridge.Note" "AKA Innerspace" "" "Cartridge.MD5" "8e4fa8c6ad8d8dce0db8c991c166cdaa" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel" "Cartridge.ModelNo" "CX26114" "Cartridge.Name" "Pigs in Space (1983) (Atari)" "" "Cartridge.MD5" "8e512ad4506800458f99dec084fc2c64" "Cartridge.Manufacturer" "Bob Montgomery, Nathan Strum" "Cartridge.Name" "Reindeer Rescue (2005)" "Cartridge.Note" "2005 AtariAge Holiday Cart" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "8e7241bfc8380aac3c0ef1b6881cdded" "Cartridge.Manufacturer" "Atari, Howard Scott Warshaw - Sears" "Cartridge.ModelNo" "CX2655 - 49-75167" "Cartridge.Name" "Yars' Revenge (09-01-81) (Atari) (Prototype)" "Cartridge.Note" "Time Freeze" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8e737a88a566cc94bd50174c2d019593" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "343.173 1" "Cartridge.Name" "Feuerwehr im Einsatz (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Fire Fighter" "" "Cartridge.MD5" "8e822b39a71c84ac875f0107fb61d6f0" "Cartridge.Name" "Hangman Ghost Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "8e879aa58db41edb67cbf318b77766c4" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Cosmic Commuter (Thomas Jentzsch) (PAL60)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Hack" "Display.Format" "PAL60" "" "Cartridge.MD5" "8e887d1ba5f3a71ae8a0ea16a4af9fc9" "Cartridge.Name" "Skeleton (V1.1) (PAL) (24-10-2002) (Eric Ball)" "" "Cartridge.MD5" "8ed5a746c59571feb255eaa7d6d0cf98" "Cartridge.Name" "Carnival (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "8ed73106e2f42f91447fb90b6f0ea4a4" "Cartridge.Manufacturer" "Spectravision - Spectravideo" "Cartridge.ModelNo" "SA-204" "Cartridge.Name" "Tapeworm (1982) (Spectravision) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8ee3f64dc0f349adc893fe93df5245d8" "Cartridge.Name" "Euchre (20-07-2001) (Eric Eid) (PD)" "" "Cartridge.MD5" "8f33bce5ba1053dcf4cea9c1c69981e4" "Cartridge.Name" "Jawbreaker (Unknown) (PAL) [a]" "" "Cartridge.MD5" "8f53a3b925f0fd961d9b8c4d46ee6755" "Cartridge.Name" "Astrowar (Unknown)" "" "Cartridge.MD5" "8f5ac5139419c5d49bacc296e342a247" "Cartridge.Manufacturer" "Atari - CCW, Michael Callahan, Preston Stuart" "Cartridge.ModelNo" "CX26103" "Cartridge.Name" "Alpha Beam with Ernie (12-22-1983) (Atari) (Prototype)" "Cartridge.Note" "Uses Keypad Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "8f60551db6d1535ef0030f155018c738" "Cartridge.Name" "Space War (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "8f613ea7c32a587d6741790e32872ddd" "Cartridge.Name" "Troll Demo (PD)" "" "Cartridge.MD5" "8f88309afad108936ca70f8b2b084718" "Cartridge.Manufacturer" "Spectravision - Spectravideo - Quelle" "Cartridge.ModelNo" "SA-203 - 413.223 9" "Cartridge.Name" "Cross Force (1982) (Spectravision) (PAL)" "Cartridge.Note" "AKA Kreuzfeuer (Cross Fire)" "" "Cartridge.MD5" "8f90590dba143d783df5a6cff2000e4d" "Cartridge.Name" "Gopher (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "8f98519a91dbbf4864f135a10050d9ed" "Cartridge.Manufacturer" "Silvio Mogno" "Cartridge.Name" "Rainbow Invaders (non-playable demo) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "8fa47e5242776e841df7e708b12eb998" "Cartridge.Name" "Sea Hawk (Genesis)" "Cartridge.Note" "Genesis controller (C drops bomb)" "Cartridge.Rarity" "Hack of Sea Hawk" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "8fbabaa87941cdf3a377c15e95bdb0f3" "Cartridge.Name" "Meteor Smasher (SnailSoft)" "" "Cartridge.MD5" "8fe00172e7fff4c1878dabcf11bb8dce" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "689.302 8" "Cartridge.Name" "Hili Ball (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Racquetball" "Display.Phosphor" "YES" "" "Cartridge.MD5" "8febdd9142960d084ab6eeb1d3e88969" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX2674" "Cartridge.Name" "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL)" "" "Cartridge.MD5" "8fffc8f15bb2e6d24e211884a5479aa5" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V1.00) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9048ccb7e0802cd8fa5bfc2609f292d8" "Cartridge.Manufacturer" "Tigervision, Robert H. O'Neil" "Cartridge.ModelNo" "7-007" "Cartridge.Name" "Polaris (1983) (Tigervision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9057694dce8449521e6164d263702185" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-011" "Cartridge.Name" "Stampede (1981) (Activision) (16K)" "" "Cartridge.MD5" "90578a63441de4520be5324e8f015352" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP204" "Cartridge.Name" "Open Sesame (4 Game in One) (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA I Want My Mommy" "Display.YStart" "34" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9072c142728a3a3d994956d03bfacba2" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Crash Dive (Fabrizio Zavagli) (PAL60)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Hack" "Display.Format" "PAL60" "Display.YStart" "30" "" "Cartridge.MD5" "90b1799dddb8bf748ee286d22e609480" "Cartridge.Name" "Ship Demo (PD)" "" "Cartridge.MD5" "90b647bfb6b18af35fcf613573ad2eec" "Cartridge.Manufacturer" "AtariAge (Chris Walton)" "Cartridge.Name" "Juno First (2009)" "Cartridge.Note" "AtariVox supported" "Cartridge.Rarity" "Homebrew" "Controller.Right" "ATARIVOX" "Display.Phosphor" "YES" "" "Cartridge.MD5" "90ccf4f30a5ad8c801090b388ddd5613" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (1982) (Starpath)" "" "Cartridge.MD5" "90d77e966793754ab4312c47b42900b1" "Cartridge.Manufacturer" "Imagic, Brad Stewart" "Cartridge.ModelNo" "720105-2A, IA3400P, EIX-005-04I" "Cartridge.Name" "Fire Fighter (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "90f502cbf4438a95f69f848cef36eb64" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "River Raid II (1985) (Digitel)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "910dd9bf98cc5bc080943e5128b15bf5" "Cartridge.Name" "Gunfight 2600 - Improved AI (MP)" "" "Cartridge.MD5" "911d385ee0805ff5b8f96c5a63da7de5" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Jammed (V0.1) (Demo) (2001) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "913d5d959b5021f879033c89797bab5e" "Cartridge.Name" "Robot Player Graphic (1996) (J.V. Matthews) (PD)" "" "Cartridge.MD5" "914a8feaf6d0a1bbed9eb61d33817679" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Freeway Chicken (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Freeway" "" "Cartridge.MD5" "91925abce3a29e33b6a8b81482f4f5af" "Cartridge.Manufacturer" "Activision, Garry Kitchen - Ariola" "Cartridge.ModelNo" "EAX-025, EAX-025-04I - 711 025-725" "Cartridge.Name" "Keystone Kapers (1983) (Activision) (PAL) (8K)" "" "Cartridge.MD5" "9193b6fff6897d43274741d4f9855b6d" "Cartridge.Name" "M.A.S.H (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "91a3749ff7b7e72b7fa09e05396a0e7b" "Cartridge.Name" "Gunfight 2600 - Final Run Part 2 (2002) (MP)" "" "Cartridge.MD5" "91b007f33f9b790be64f57220ec52e80" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise" "Cartridge.Name" "Laser Blast (Jone Yuan) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "91c2098e88a6b13f977af8c003e0bca5" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2676" "Cartridge.Name" "Centipede (1983) (Atari)" "" "Cartridge.MD5" "91d1c82ceaf8af2add3973a3c34bc0cb" "Cartridge.Name" "Starfield Demo 1 (20-12-2002) (CT)" "" "Cartridge.MD5" "91f0a708eeb93c133e9672ad2c8e0429" "Cartridge.Name" "Oystron (V2.9) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "91fdb6541f70c40b16aabf8308123be8" "Cartridge.Name" "Interlacing Game (19-08-2002) (Billy Eno)" "" "Cartridge.MD5" "9222b25a0875022b412e8da37e7f6887" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "106" "Cartridge.Name" "Dice Puzzle (1983) (Panda)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9245a84e9851565d565cb6c9fac5802b" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA282" "Cartridge.Name" "Great Escape (1983) (Bomb)" "Cartridge.Note" "AKA Asteroid Fire" "" "Cartridge.MD5" "927d422d6335018da469a9a07cd80390" "Cartridge.Manufacturer" "Activision, Carol Shaw - Ariola" "Cartridge.ModelNo" "EAX-020, EAX-020-04B, EAX-020-04I - 711 020-720" "Cartridge.Name" "River Raid (1982) (Activision) (PAL)" "" "Cartridge.MD5" "9281eccd7f6ef4b3ebdcfd2204c9763a" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.15) (Retroactive) (PAL)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9295570a141cdec18074c55dc7229d08" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "7045 A015" "Cartridge.Name" "Bump 'n' Jump (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "929e8a84ed50601d9af8c49b0425c7ea" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG205" "Cartridge.Name" "Dancing Plate (1982) (BitCorp) (PAL)" "Cartridge.Note" "AKA Dishaster, Dancing Plates, Tanzende Teller" "Display.Phosphor" "YES" "" "Cartridge.MD5" "92a1a605b7ad56d863a56373a866761b" "Cartridge.Manufacturer" "U.S. Games Corporation - Western Technologies, Dave Hampton" "Cartridge.ModelNo" "VC2006" "Cartridge.Name" "Raft Rider (1983) (U.S. Games)" "" "Cartridge.MD5" "92c5abb7a8bb1c3fc66c92ba353a3d21" "Cartridge.Name" "Star Fire - Sorting Fixed (MP)" "" "Cartridge.MD5" "92d1f6ac179ebe5963868d6bc1bdda8d" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "498" "Cartridge.Name" "Smash Hit Pak - Frogger, Boxing, Seaquest, Skiing, Stampede (HES) (PAL)" "" "Cartridge.MD5" "92e72f7cc569584c44c9530d645ae04e" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Spider Fighter (Canal 3)" "" "Cartridge.MD5" "92ede72ed8f61d255bc58d2f166dc6b6" "Cartridge.Name" "Star Fire - Shootable (26-09-2002) (MP)" "" "Cartridge.MD5" "931b91a8ea2d39fe4dca1a23832b591a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-008" "Cartridge.Name" "Laser Blast (1981) (Activision)" "" "Cartridge.MD5" "9333172e3c4992ecf548d3ac1f2553eb" "Cartridge.Manufacturer" "Konami" "Cartridge.ModelNo" "RC 101-X 02" "Cartridge.Name" "Strategy X (1983) (Konami)" "" "Cartridge.MD5" "93420cc4cb1af1f2175c63e52ec18332" "Cartridge.Manufacturer" "Tim Snider" "Cartridge.Name" "Blair Witch Project (Tim Snider) (Hack)" "Cartridge.Note" "Hack of Haunted House" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9364ad51c321e0f15c96a8c0aff47ceb" "Cartridge.Manufacturer" "Atari, Rob Fulop" "Cartridge.ModelNo" "CX2638" "Cartridge.Name" "Missile Command (1981) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "936ef1d6f8a57b9ff575dc195ee36b80" "Cartridge.Name" "Pac Kong (Unknown)" "Cartridge.Note" "AKA Inca Gold" "" "Cartridge.MD5" "936f555b4b1a2cd061b659ff63f4f5f2" "Cartridge.Manufacturer" "HES, David Lubar" "Cartridge.ModelNo" "535" "Cartridge.Name" "My Golf (1990) (HES) (PAL) [a1]" "" "Cartridge.MD5" "937736d899337036de818391a87271e0" "Cartridge.Manufacturer" "Atari, Peter C. Niday" "Cartridge.ModelNo" "CX26108" "Cartridge.Name" "Donald Duck's Speedboat (04-12-1983) (Atari) (Prototype)" "Cartridge.Note" "AKA Donald Duck's Regatta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "939ce554f5c0e74cc6e4e62810ec2111" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "711-111 - GN-020" "Cartridge.Name" "Dishaster (1983) (ZiMAG)" "Cartridge.Note" "AKA Dancing Plate" "Display.Phosphor" "YES" "" "Cartridge.MD5" "93acd5020ae8eb5673601e2edecbc158" "Cartridge.Manufacturer" "Chris Cracknell" "Cartridge.Name" "Video Time Machine (Chris Cracknell)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "93b9229fc0ea4fb959d604f83f8f603c" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Amidar DS (Fast Enemies) (2003) (TJ) (Hack)" "Cartridge.Note" "Hack of Amidar" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "93c52141d3c4e1b5574d072f1afde6cd" "Cartridge.Manufacturer" "Imagic, Mark Klein" "Cartridge.ModelNo" "720112-1A, 03213" "Cartridge.Name" "Subterranea (1983) (Imagic)" "" "Cartridge.MD5" "93c8d9d24f9c5f1f570694848d087df7" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Galaxian (Digivision)" "" "Cartridge.MD5" "93c9f9239a4e5c956663dd7affa70da2" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "626.610 0" "Cartridge.Name" "Billard (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Trick Shot" "Display.Phosphor" "YES" "" "Cartridge.MD5" "93dc15d15e77a7b23162467f95a5f22d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Sky Jinks (CCE)" "" "Cartridge.MD5" "93eb1795c8b1065b1b3d62bb9ec0ccdc" "Cartridge.Manufacturer" "JSK" "Cartridge.Name" "Custer's Viagra (JSK) (Hack)" "Cartridge.Note" "Hack of Custer's Revenge" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "94102febc53b4a78342d11b645342ed4" "Cartridge.Name" "Joustpong (14-07-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "9436b7ad131b5a1f7753ce4309ba3dee" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "War of The Worlds (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Defender" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9469d18238345d87768e8965f9f4a6b2" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Ms. Pac-Man (CCE)" "" "Cartridge.MD5" "947317a89af38a49c4864d6bdd6a91fb" "Cartridge.Manufacturer" "CBS Electronics, Bob Curtiss" "Cartridge.ModelNo" "4L 2487 5000" "Cartridge.Name" "Solar Fox (1983) (CBS Electronics)" "" "Cartridge.MD5" "94b92a882f6dbaa6993a46e2dcc58402" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-026, AX-026-04" "Cartridge.Name" "Enduro (1983) (Activision)" "" "Cartridge.MD5" "94d90f63678e086f6b6d5e1bc6c4c8c2" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Seaquest (Digivision)" "" "Cartridge.MD5" "94e3fbc19107a169909e274187247a9d" "Cartridge.ModelNo" "2402-044-01" "Cartridge.Name" "2-in-1 Freeway and Tennis (Unknown)" "Cartridge.Type" "2IN1" "" "Cartridge.MD5" "94e4c9b924286038527f49cdc20fda69" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.12) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "94e7cc6342d11e508e7e8b2ddf53c255" "Cartridge.Name" "Missile Command (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "94ff6b7489ed401dcaaf952fece10f67" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692" "Cartridge.Name" "Moon Patrol (07-31-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "951e8cec7a1a1d6c01fd649e7ff7743a" "Cartridge.Manufacturer" "Atari - Sculptured Software, Adam Clayton" "Cartridge.ModelNo" "CX26151, CX26151P" "Cartridge.Name" "Dark Chambers (1988) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9526e3db3bdfbc27989a9cbfd0ee34bf" "Cartridge.Name" "Atari Logo Demo 6 (PD)" "" "Cartridge.MD5" "95351b46fa9c45471d852d28b9b4e00b" "Cartridge.Manufacturer" "Atari, Tom Rudadahl" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Golf (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "955c408265ad6994f61f9b66657bbae9" "Cartridge.Name" "Quadrun (Video Conversion) (Fabrizio Zavagli)" "" "Cartridge.MD5" "956496f81775de0b69a116a0d1ad41cc" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Alien (CCE)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "956b99511c0f47b3a11d18e8b7ac8d47" "Cartridge.Name" "Bones (Arcade Golf Hack)" "" "Cartridge.MD5" "95956108289a917f80667eccd3ce98a9" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw" "Cartridge.ModelNo" "CX2639, CX2639P" "Cartridge.Name" "Othello (1981) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "95a69cf8c08ef1522b050529464f0bca" "Cartridge.Name" "Grid Pattern Demo 1 (20-12-2002) (CT)" "" "Cartridge.MD5" "95a89d1bf767d7cc9d0d5093d579ba61" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "204" "Cartridge.Name" "Lady in Wading (1982) (PlayAround)" "Display.Height" "216" "Display.Phosphor" "YES" "" "Cartridge.MD5" "95e1d834c57cdd525dd0bd6048a57f7b" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel" "Cartridge.ModelNo" "CX26114" "Cartridge.Name" "Pigs in Space (1983) (Atari) (PAL)" "" "Cartridge.MD5" "95e542a7467c94b1e4ab24a3ebe907f1" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "719.252 9" "Cartridge.Name" "Im Schutz der Drachen (1983) (Quelle) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "95fd6097dc27c20666f039cfe34f7c69" "Cartridge.Name" "Oh No! (Version 1) (17-01-2003) (AD)" "" "Cartridge.MD5" "961112b74a920a5242e233480326c356" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-007, CAG-007" "Cartridge.Name" "Tennis (1981) (Activision) (16K)" "" "Cartridge.MD5" "962ffd3eaf865230a7a312b80e6c5cfd" "Cartridge.Manufacturer" "Imagic, Wilfredo 'Willy' Aguilar, Michael Becker, Rob Fulop" "Cartridge.ModelNo" "13205" "Cartridge.Name" "Fathom (1983) (Imagic) (PAL) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "96670d0bf3610da2afcabd8e21d8eabf" "Cartridge.Name" "Boring Pitfall (Hack)" "Cartridge.Note" "Hack of Pitfall!" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "966b11d3c147d894dd9e4ebb971ea309" "Cartridge.Name" "Marble Craze Song (Paul Slocum) (PD)" "" "Cartridge.MD5" "9671b658286e276cc4a3d02aa25931d2" "Cartridge.Name" "Hangman Ghost Wordlist (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "968efc79d500dce52a906870a97358ab" "Cartridge.Manufacturer" "TNT Games - Sculptured Software, Adam Clayton" "Cartridge.ModelNo" "26192" "Cartridge.Name" "BMX Air Master (1989) (TNT Games)" "" "Cartridge.MD5" "969b968383d9f0e9d8ffd1056bcaef49" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2628, CX2628P" "Cartridge.Name" "Bowling (1979) (Atari) (PAL)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "96bcb3d97ce4ff7586326d183ac338a2" "Cartridge.Name" "Revenge of the Apes (Hack) [h2]" "Cartridge.Note" "Hack of Planet of the Apes" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "96e798995af6ed9d8601166d4350f276" "Cartridge.Manufacturer" "20th Century Fox Video Games - Videa, David Ross" "Cartridge.ModelNo" "11029" "Cartridge.Name" "Meltdown (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "96eccc2277043508a6c481ea432d7dd9" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Command (Atari Mouse) (2002) (TJ) (PAL)" "Cartridge.Note" "Uses Atari ST Mouse Controller" "Cartridge.Rarity" "Homebrew" "Controller.Left" "ATARIMOUSE" "Display.Phosphor" "YES" "" "Cartridge.MD5" "96f806fc62005205d851e758d050dfca" "Cartridge.Name" "Push (V0.05) (2001) (AD)" "" "Cartridge.MD5" "97184b263722748757cfdc41107ca5c0" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "PB5820" "Cartridge.Name" "Mr. Do!'s Castle (1984) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9718b85ac5a55cbc7348963c63ffa35a" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Demon Attack (Robby)" "" "Cartridge.MD5" "972486110933623039a3581db308fda6" "Cartridge.Name" "Xeno Plus (Hack)" "Cartridge.Note" "Hack of Xenophobe" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "97327d6962f8c64e6f926f79cd01c6b9" "Cartridge.Name" "Jawbreaker (Unknown) (PAL)" "" "Cartridge.MD5" "977294ae6526c31c7f9a166ee00964ad" "Cartridge.Manufacturer" "Atari - GCC, Douglas B. Macrae" "Cartridge.ModelNo" "CX2677, CX2677P" "Cartridge.Name" "Dig Dug (1983) (Atari) (PAL)" "" "Cartridge.MD5" "97842fe847e8eb71263d6f92f7e122bd" "Cartridge.Manufacturer" "Imagic, Wilfredo Aguilar, Michael Becker, Dennis Koble" "Cartridge.ModelNo" "720113-1A, 03206" "Cartridge.Name" "Solar Storm (1983) (Imagic)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 45" "" "Cartridge.MD5" "97933c9f20873446e4c1f8a4da21575f" "Cartridge.Name" "Racquetball (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "97a9bb5c3679d67f5c2cd17f30b85d95" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Colors (1980) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "97cd63c483fe3c68b7ce939ab8f7a318" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Robot City (V0.21) (15-09-2002) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "97d0151beb84acbe82aa6db18cd91b98" "Cartridge.Manufacturer" "Steve Engelhardt" "Cartridge.Name" "Lunar Attack (2002) (Steve Engelhardt) (Hack)" "Cartridge.Note" "Hack of Z-Tack" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "97d079315c09796ff6d95a06e4b70171" "Cartridge.Manufacturer" "Activision, Garry Kitchen" "Cartridge.ModelNo" "AZ-032" "Cartridge.Name" "Pressure Cooker (1983) (Activision)" "" "Cartridge.MD5" "9813b9e4b8a6fd919c86a40c6bda8c93" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26177" "Cartridge.Name" "Ikari Warriors (1989) (Atari) (PAL) [a]" "" "Cartridge.MD5" "9831efc7f4cb8ffb4df0082bab2f07a3" "Cartridge.Manufacturer" "Activision, Steve Cartwright - Ariola" "Cartridge.ModelNo" "EAX-031, EAX-031-04B - 711 031-717" "Cartridge.Name" "Frostbite (1983) (Activision) (PAL) (8K)" "" "Cartridge.MD5" "9848b5ef7a0c02fe808b920a2ac566d2" "Cartridge.Manufacturer" "Skyworks Technology Inc." "Cartridge.Name" "Baseball (2002) (Skyworks)" "" "Cartridge.MD5" "9853089672116117258097dbbdb939b7" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Cowboy Hair (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "98555b95cb38e0e0b22b482b2b60a5b6" "Cartridge.Name" "Spinning Fireball (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "98ba601a60172cb46c5bf9a962fd5b1f" "Cartridge.Name" "Gorilla Kong (Hack)" "Cartridge.Note" "Hack of Donkey Kong" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "98ccd15345b1aee6caf51e05955f0261" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.03) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "98e5e4d5c4dd9a986d30fd62bd2f75ae" "Cartridge.Name" "Air-Sea Battle (Unknown) (Hack) (4K)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "98e6e34af45a0664597972c3bb31180f" "Cartridge.Name" "Space Instigators (V1.7) (17-10-2002) (CT)" "" "Cartridge.MD5" "98e7caaab8ec237558378d2776c66616" "Cartridge.Manufacturer" "Bradford W. Mott" "Cartridge.Name" "HMOVE Test (Bradford W. Mott) (1998) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "98ea10c47c13f1b3306c7b13db304865" "Cartridge.Name" "Jam Demo 1 (PD)" "" "Cartridge.MD5" "98ec0fa4199b9c01f7b8fa3732e43372" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-018, AX-018-04" "Cartridge.Name" "Pitfall! (1982) (Activision) (8K)" "" "Cartridge.MD5" "98ef1593624b409b9fb83a1c272a0aa7" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-831" "Cartridge.Name" "Cosmic Ark (1983) (CCE)" "" "Cartridge.MD5" "98f63949e656ff309cefa672146dc1b8" "Cartridge.Manufacturer" "Atari - Axlon, John Vifian" "Cartridge.ModelNo" "CX26168" "Cartridge.Name" "Off the Wall (1989) (Atari)" "" "Cartridge.MD5" "98fa3ad778a668a79449350de4b3b95b" "Cartridge.Name" "Thrust (V1.1) (2000) (TJ)" "" "Cartridge.MD5" "9905f9f4706223dadee84f6867ede8e3" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "Challenge (HES) (PAL)" "Cartridge.Note" "ROM must be started in bank 1 (Surfer's Paradise if right difficulty = 'A')" "" "Cartridge.MD5" "9912d06eea42200a198dd3e2be18c601" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "IA3312" "Cartridge.Name" "No Escape! (1982) (Imagic) [a]" "" "Cartridge.MD5" "991d57bbcd529ad62925098e0aec1241" "Cartridge.Name" "Gunfight 2600 - The Final Kernel (MP) [a1]" "" "Cartridge.MD5" "9945a22f60bbaf6d04a8d73b3cf3db75" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "EAX-039-04B, EAX-039-04I" "Cartridge.Name" "Kung-Fu Master (1987) (Activision) (PAL) [a]" "" "Cartridge.MD5" "9947f1ebabb56fd075a96c6d37351efa" "Cartridge.Manufacturer" "CBS Electronics" "Cartridge.ModelNo" "4L 2737 0000" "Cartridge.Name" "Omega Race (1983) (CBS Electronics)" "Cartridge.Note" "Set right difficulty to 'A' for BoosterGrip in both ports" "Console.RightDifficulty" "A" "Controller.Left" "BOOSTERGRIP" "Controller.Right" "BOOSTERGRIP" "" "Cartridge.MD5" "9962034ea7b3d4a905d0991804670087" "Cartridge.Name" "Grid Demo (PD)" "" "Cartridge.MD5" "9989f974c3cf9c641db6c8a70a2a2267" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Colours Selector (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "99a24d7bb31d49b720b422550b32c35f" "Cartridge.Name" "Hangman Ghost Biglist1 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "99f7c6c26046bbe95f1c604b25da8360" "Cartridge.Manufacturer" "SnailSoft" "Cartridge.Name" "Comitoid beta 2 (SnailSoft)" "" "Cartridge.MD5" "9a01115206f32eb0b539c7e5a47ccafa" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (07-15-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9a165c39af3f050fdee6583fdfcdc9be" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Mario Bros. (Zirok)" "" "Cartridge.MD5" "9a21fba9ee9794e0fadd7c7eb6be4e12" "Cartridge.Manufacturer" "Atari - Imagineering, Dan Kitchen" "Cartridge.ModelNo" "CX26177" "Cartridge.Name" "Ikari Warriors (1991) (Atari)" "" "Cartridge.MD5" "9a25b3cfe2bbb847b66a97282200cca2" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2622 - 6-99813, 49-75107" "Cartridge.Name" "Breakout (1978) (Atari) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 60" "" "Cartridge.MD5" "9a4274409216ff09ecde799f2a56ac73" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-801" "Cartridge.Name" "Mr. Postman (1983) (CCE) [a]" "" "Cartridge.MD5" "9ab72d3fd2cc1a0c9adb504502579037" "Cartridge.Manufacturer" "Epyx, Steven A. Baker, Peter Engelbrite" "Cartridge.ModelNo" "80561-00286" "Cartridge.Name" "California Games (1988) (Epyx)" "" "Cartridge.MD5" "9ad362179c2eea4ea115c7640b4b003e" "Cartridge.Name" "Barnstorming (Unknown) (PAL)" "Display.Format" "NTSC50" "" "Cartridge.MD5" "9ad36e699ef6f45d9eb6c4cf90475c9f" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "720103-1A, 720103-1B, IA3203, IX-010-04" "Cartridge.Name" "Atlantis (1982) (Imagic)" "Cartridge.Note" "AKA Lost City of Atlantis" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "9aeb5206c5bf974892a9cc59f1478db3" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-013" "Cartridge.Name" "Barnstorming (1982) (Activision) (8K)" "" "Cartridge.MD5" "9af615951e9719df2244bc77fc50cb95" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Defender (Dactari - Milmar)" "" "Cartridge.MD5" "9afdfe1cff7f37f1c971fe3f0c900606" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Plug Attack (Funvision)" "Cartridge.Note" "AKA Plaque Attack" "" "Cartridge.MD5" "9b150a42fc788960fbb4cbe250259ee2" "Cartridge.Manufacturer" "Kroko" "Cartridge.Name" "3E Bankswitch Test (TIA @ $40)" "" "Cartridge.MD5" "9b21d8fc78cc4308990d99a4d906ec52" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-838" "Cartridge.Name" "Immies & Aggies (1983) (CCE)" "Display.YStart" "18" "Display.Height" "223" "" "Cartridge.MD5" "9b246683f44c963a50e41d6b485bee77" "Cartridge.Name" "Boring (PAL) (AD)" "" "Cartridge.MD5" "9bb136b62521c67ac893213e01dd338f" "Cartridge.Manufacturer" "Xonox - Beck-Tech" "Cartridge.ModelNo" "6210, 7210, 06003. 99001" "Cartridge.Name" "Spike's Peak (1983) (Xonox) (PAL) [a]" "" "Cartridge.MD5" "9bd4e0d5f28ba6da417c26649171f8e4" "Cartridge.Name" "Hangman Pac-Man Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9be58a14e055b0e7581fc4d6c2f6b31d" "Cartridge.Name" "Adventure (Color Scrolling) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9c27ef3bd01c611cdb80182a59463a82" "Cartridge.Manufacturer" "Arcadia Corporation, Kevin Norman" "Cartridge.ModelNo" "AR-4103" "Cartridge.Name" "Killer Satellites (1983) (Arcadia) [a]" "" "Cartridge.MD5" "9c40bf810f761ffc9c1b69c4647a8b84" "Cartridge.Name" "2 in 1 - Frostbite, River Raid (Unknown)" "Cartridge.Type" "2IN1" "" "Cartridge.MD5" "9c6d65bd3b477aace0376f705b354d68" "Cartridge.Name" "RPG Kernal (18-04-2003) (Paul Slocum) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9c6faa4ff7f2ae549bbcb14f582b70e4" "Cartridge.Manufacturer" "U.S. Games Corporation, Garry Kitchen, Paul Willson - Vidtec" "Cartridge.ModelNo" "VC1002" "Cartridge.Name" "Sneak 'n Peek (1982) (U.S. Games)" "Cartridge.Note" "AKA Hide 'n Seek" "Display.Height" "215" "" "Cartridge.MD5" "9c6fd6ed3599978ab7b6f900484b9be6" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Laseresal 2002 (PAL60) (PD)" "Cartridge.Rarity" "New Release" "Display.Format" "PAL60" "" "Cartridge.MD5" "9c729017dd2f9ccbadcb511187f80e6b" "Cartridge.Name" "J-Pac (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9c7fa3cfcaaafb4e6daf1e2517d43d88" "Cartridge.Name" "PIEROXM Demo (PD)" "" "Cartridge.MD5" "9ca2deb61318eba4fb784d4bf7441d8b" "Cartridge.Name" "Purple Bar Demo 2 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "9cbb07f1993a027bc2f87d5205457ec9" "Cartridge.Name" "Eckhard Stolberg's Scrolling Text Demo 1 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "9d0befa555f003069a21d2f6847ad962" "Cartridge.Manufacturer" "Atari - GCC, Dave Payne" "Cartridge.ModelNo" "CX2669" "Cartridge.Name" "Vanguard (1982) (Atari) (PAL) [a]" "" "Cartridge.MD5" "9d1556ae5890398be7e3d57449774b40" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-001" "Cartridge.Name" "Dragster (1980) (Activision) (8K)" "Display.YStart" "27" "" "Cartridge.MD5" "9d2938eb2b17bb73e9a79bbc06053506" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "EIZ-002-04I" "Cartridge.Name" "Wing War (1983) (Imagic) (PAL) [a]" "" "Cartridge.MD5" "9d2f05d0fe8b2dfcf770b02eda066fc1" "Cartridge.Name" "Push (V0.06) (2001) (AD)" "" "Cartridge.MD5" "9d33d31fb1de58c5460d8a67b57b36da" "Cartridge.Name" "Star Voyager (Genesis)" "Cartridge.Note" "Genesis controller (C is secondary lasers)" "Cartridge.Rarity" "Hack of Star Voyager" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "9d37a1be4a6e898026414b8fee2fc826" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, David Rolfe - INTV" "Cartridge.ModelNo" "MT5665" "Cartridge.Name" "Super Challenge Baseball (1982) (M Network)" "Cartridge.Note" "AKA Big League Baseball" "" "Cartridge.MD5" "9d4bc7c6fe9a7c8c4aa24a237c340adb" "Cartridge.Manufacturer" "Dennis Debro" "Cartridge.Name" "Climber 5 (16-04-2003) (Dennis Debro)" "Cartridge.Note" "For Philly Classic 4" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "9d522a3759aa855668e75962c84546f7" "Cartridge.Manufacturer" "Atari, Tom Rudadahl" "Cartridge.ModelNo" "CX2634, CX2634P" "Cartridge.Name" "Golf (1980) (Atari) (PAL)" "" "Cartridge.MD5" "9d7f04618bb4043f531d087e3aaa7ac8" "Cartridge.Manufacturer" "Parker Brothers, Larry Gelberg, Gary Goltz" "Cartridge.ModelNo" "PB5065" "Cartridge.Name" "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype) (PAL) (16K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9de0d45731f90a0a922ab09228510393" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius, Mark Turmell" "Cartridge.ModelNo" "11003" "Cartridge.Name" "Fast Eddie (1982) (20th Century Fox)" "" "Cartridge.MD5" "9dec0be14d899e1aac4337acef5ab94a" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-003" "Cartridge.Name" "Cosmic Swarm (1982) (CommaVid) (4K)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9e01f7f95cb8596765e03b9a36e8e33c" "Cartridge.Manufacturer" "Atari - CCW, Michael Callahan, Preston Stuart" "Cartridge.ModelNo" "CX26103" "Cartridge.Name" "Alpha Beam with Ernie (1983) (Atari)" "Cartridge.Note" "Uses Keypad Controllers" "Cartridge.Rarity" "Rare" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "9e192601829f5f5c2d3b51f8ae25dbe5" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "201" "Cartridge.Name" "Cathouse Blues (1982) (PlayAround)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9e2c7299c69b602443d327c7dad51cbf" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "Xaxyrax Road (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Freeway" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9e437229136f1c5e6ef4c5f36178ed18" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Grand Prize (Funvision)" "Cartridge.Note" "AKA Enduro" "" "Cartridge.MD5" "9e5007131695621d06902ab3c960622a" "Cartridge.Manufacturer" "Sega" "Cartridge.Name" "Tac Scan (1983) (Sega) [h1]" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 60" "Display.Height" "215" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9e6fa031ece07919c816fba5dc8de43e" "Cartridge.Name" "Star Fire - Meteor Dance (13-11-2002) (MP)" "" "Cartridge.MD5" "9e792a59f8795664cbaaff1ba152d731" "Cartridge.Name" "Bullet Demo (20-12-2002) (CT)" "" "Cartridge.MD5" "9e904e2eaa471c050c491289b8b80f60" "Cartridge.Name" "How to Draw a Playfield II (1997) (Erik Mooney) (PD)" "" "Cartridge.MD5" "9ea8ed9dec03082973244a080941e58a" "Cartridge.Manufacturer" "Eric Mooney, Piero Cavina" "Cartridge.Name" "INV+" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "9ec1b259a1bcffa63042a3c2b3b90f0a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-008" "Cartridge.Name" "Laser Blast (1981) (Activision) (16K)" "" "Cartridge.MD5" "9eca521db1959156a115dee85a405194" "Cartridge.Name" "Fu Kung! (V0.08) (2003) (AD)" "" "Cartridge.MD5" "9ed0f2aa226c34d4f55f661442e8f22a" "Cartridge.Name" "Nuts (Unknown) (PAL)" "Display.YStart" "45" "" "Cartridge.MD5" "9eeb40f04a27efb1c68ba1d25e606607" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "Rambo II (2003) (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Double Dragon" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "9efa877a98dd5a075e058214da428abb" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "SCSIcide (1.32) (Hozer Video Games)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "New Release" "Controller.Left" "PADDLES_IAXDR" "Controller.MouseAxis" "AUTO 65" "" "Cartridge.MD5" "9efb4e1a15a6cdd286e4bcd7cd94b7b8" "Cartridge.Manufacturer" "20th Century Fox Video Games, John W.S. Marvin" "Cartridge.Name" "Planet of the Apes (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9f2d58dce1b81c6ba201ed103507c025" "Cartridge.Name" "Fu Kung! (V0.02) (2003) (AD)" "" "Cartridge.MD5" "9f48eeb47836cf145a15771775f0767a" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX2620" "Cartridge.Name" "Basic Programming (1979) (Atari)" "Cartridge.Note" "Uses Keypad Controllers" "Cartridge.Rarity" "Rare" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9f5096a6f1a5049df87798eb59707583" "Cartridge.Manufacturer" "20th Century Fox Video Games, Mark Klein" "Cartridge.ModelNo" "11036" "Cartridge.Name" "Entity, The (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "9f59eddf9ba91a7d93bce7ee4b7693bc" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Montezuma's Revenge (Thomas Jentzsch) (PAL60)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "Cartridge.MD5" "9f8fad4badcd7be61bbd2bcaeef3c58f" "Cartridge.Manufacturer" "Parker Brothers, Charlie Heath" "Cartridge.ModelNo" "PB5330" "Cartridge.Name" "Reactor (1983) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "9f901509f0474bf9760e6ebd80e629cd" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2623 - 6-99819, 49-75108, 49-75125" "Cartridge.Name" "Home Run (1978) (Atari) (4K)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "9f93734c68f6479eb022cab40814142e" "Cartridge.Name" "Push (V0.07) (2001) (AD)" "" "Cartridge.MD5" "9f9ee0f60c119c831e80694b6678ca1a" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 8 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "9fa0c664b157a0c27d10319dbbca812c" "Cartridge.Manufacturer" "Chris Walton, Justin Hairgrove, Tony Morse" "Cartridge.Name" "Hunchy II (2005)" "Cartridge.Note" "Homebrew" "" "Cartridge.MD5" "9fc2d1627dcdd8925f4c042e38eb0bc9" "Cartridge.Manufacturer" "Atari - GCC, John Allred, Mike Feinstein" "Cartridge.ModelNo" "CX2688, CX2688P" "Cartridge.Name" "Jungle Hunt (1983) (Atari) (PAL)" "" "Cartridge.MD5" "E68E28752D3C54EDD3CCDA42C27E320C" "Cartridge.Manufacturer" "Xonox - K-Tel Software, Anthony R. Henderson" "Cartridge.ModelNo" "99007, 6240" "Cartridge.Name" "Tomarc the Barbarian (1983) (Xonox)" "Cartridge.Note" "Genesis controller (B is jump and throw, C switches between players)" "Cartridge.Rarity" "Hack of Tomarc the Barbarian" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "a0028f057d496f22b549fd8deecc6f78" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 6 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "a00ec89d22fcc0c1a85bb542ddcb1178" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1012" "Cartridge.Name" "Phoenix (1983) (CCE)" "" "Cartridge.MD5" "a00ee0aed5c8979add4c170f5322c706" "Cartridge.Manufacturer" "Barry Laws Jr." "Cartridge.Name" "Egghead (Barry Laws Jr.) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "a0185c06297b2818f786d11a3f9e42c3" "Cartridge.Name" "International Soccer (Unknown) (PAL)" "" "Cartridge.MD5" "a025a8f83a42a4d6d46c4887e799bfac" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Descissions had to be made (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "a0297c4788f9e91d43e522f4c561b4ad" "Cartridge.Manufacturer" "Atari - CCW, Gary Stark" "Cartridge.ModelNo" "CX26102" "Cartridge.Name" "Cookie Monster Munch (1983) (Atari) (PAL)" "Cartridge.Note" "Uses Kids/Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "a0563dd6d8215c38c488fbbd61435626" "Cartridge.Name" "Ship Demo (V 1501) (PD)" "" "Cartridge.MD5" "a0675883f9b09a3595ddd66a6f5d3498" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "6057 A227" "Cartridge.Name" "Quest for Quintana Roo (1988) (Telegames)" "" "Cartridge.MD5" "a075ad332942740c386f4c3814925ece" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (2 of 4) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "a0d502dc8b90b1d7daa5f6effb10d349" "Cartridge.Name" "Demo Image Series #5 - Sam (19-02-2003) (AD)" "" "Cartridge.MD5" "a0e2d310e3e98646268200c8f0f08f46" "Cartridge.Manufacturer" "Atari, Ed Logg, Carol Shaw" "Cartridge.ModelNo" "CX2639, CX2639P" "Cartridge.Name" "Othello (1981) (Atari) (PAL)" "" "Cartridge.MD5" "a100eff2d7ae61ca2b8e65baf7e2aae8" "Cartridge.Manufacturer" "David Marli" "Cartridge.Name" "Muncher (David Marli) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "a11099b6ec24e4b00b8795744fb12005" "Cartridge.Manufacturer" "Activision - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "EAK-049-04B" "Cartridge.Name" "Rampage! (1989) (Activision) (PAL)" "" "Cartridge.MD5" "a1403fef01641dcd3980cac9f24d63f9" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Atlantis (Dactari - Milmar)" "" "Cartridge.MD5" "a14d8a388083c60283e00592b18d4c6c" "Cartridge.Name" "Tunnel Demo (28-03-2003) (AD)" "" "Cartridge.MD5" "a15b5831a1fab52e4c416068c85ec011" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - The Good, The Bad, The Ugly (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "a174cece06b3abc0aec3516913cdf9cc" "Cartridge.Manufacturer" "Sears Tele-Games, Jim Huether" "Cartridge.ModelNo" "CX2614 - 49-75126" "Cartridge.Name" "Steeplechase (1980) (Sears) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "Controller.Right" "PADDLES" "" "Cartridge.MD5" "a1770ef47146ab7b12e2c4beccd68806" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Kaystone Kapers (1983) (Digitel)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "a184846d8904396830951217b47d13d9" "Cartridge.Manufacturer" "Activision, Dan Kitchen" "Cartridge.ModelNo" "AX-029" "Cartridge.Name" "Crackpots (1983) (Activision)" "" "Cartridge.MD5" "a189f280521f4e5224d345efb4e75506" "Cartridge.Manufacturer" "Atari - Thomas Jentzsch" "Cartridge.Name" "Obelix (1983) (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "a1bcbe0bfe6570da2661fc4de2f74e8a" "Cartridge.Manufacturer" "Imagic - Advanced Program Technology, Rob Fulop" "Cartridge.Name" "Actionauts (Microbots) (1984-2008) (Imagic)" "" "Cartridge.MD5" "a1ca372388b6465a693e4626cc98b865" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "176.543 7" "Cartridge.Name" "Der Vielfrass (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Fast Food" "" "Cartridge.MD5" "a1ead9c181d67859aa93c44e40f1709c" "Cartridge.Manufacturer" "American Videogame - Dunhill Electronics, Darrell Wagner, Todd Clark Holm, John Simonds" "Cartridge.Name" "Tax Avoiders (1986) (American Videogame)" "" "Cartridge.MD5" "a1f9159121142d42e63e6fb807d337aa" "Cartridge.Manufacturer" "Quelle - Otto Versand" "Cartridge.ModelNo" "700.223 1 - 781627" "Cartridge.Name" "Der moderne Ritter (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Fast Eddie" "" "Cartridge.MD5" "a204cd4fb1944c86e800120706512a64" "Cartridge.Manufacturer" "Coleco" "Cartridge.ModelNo" "2511" "Cartridge.Name" "Smurfs Save the Day (1983) (Coleco)" "Cartridge.Note" "Uses the Kid Vid Controller" "Controller.Right" "KIDVID" "" "Cartridge.MD5" "a20b7abbcdf90fbc29ac0fafa195bd12" "Cartridge.Manufacturer" "Quelle - Otto Versand" "Cartridge.ModelNo" "719.383 2 - 649635, 781393, 781784, 986404" "Cartridge.Name" "Motocross (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Motorcross" "" "Cartridge.MD5" "a20d931a8fddcd6f6116ed21ff5c4832" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2003" "Cartridge.Name" "Racquetball (1982) (Apollo)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a2170318a8ef4b50a1b1d38567c220d6" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.ModelNo" "3125" "Cartridge.Name" "Surf's Up (1983) (Amiga) (Prototype) [a1]" "Cartridge.Note" "Uses the Joyboard controller" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "a23ffc86804240ce77134a1c91926685" "Cartridge.Name" "Star Fire - Paulstar WIP (MP)" "" "Cartridge.MD5" "a2424c1a0c783d7585d701b1c71b5fdc" "Cartridge.Name" "Video Pinball (Unknown) (PAL)" "" "Cartridge.MD5" "a25bb76e9e773117e567fd4300b1bb23" "Cartridge.Name" "Interleaved ChronoColour Demo (NTSC) (05-03-2003) (AD)" "" "Cartridge.MD5" "a28d872fc50fa6b64eb35981d0f4bb8d" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2628 - 6-99842, 49-75117" "Cartridge.Name" "Bowling (1979) (Atari) (4K)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "a29df35557f31dfea2e2ae4609c6ebb7" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Circus Atari (1980) (Atari) (Joystick)" "" "Cartridge.MD5" "a29fc854838e08c247553a7d883dd65b" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-013" "Cartridge.Name" "Barnstorming (1982) (Activision) (16K)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "a2aae759e4e76f85c8afec3b86529317" "Cartridge.Name" "Boom Bang (Unknown)" "Cartridge.Note" "AKA Crackpots" "" "Cartridge.MD5" "a2de0fc85548871279ed2a3c1325c13e" "Cartridge.Manufacturer" "George Veeder" "Cartridge.Name" "Cat and Mouse (George Veeder) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "32" "" "Cartridge.MD5" "a2eb84cfeed55acd7fece7fefdc83fbb" "Cartridge.Name" "Kool Aid Man (Fixed) (15-11-2002) (CT)" "Cartridge.Note" "HMOVE handling fixed in this version" "" "Cartridge.MD5" "a2f296ea2d6d4b59979bac5dfbf4edf0" "Cartridge.Name" "Warring Worms (28-01-2002) (Billy Eno)" "" "Cartridge.MD5" "a302b922a8dbec47743f28b7f91d4cd8" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (Preview) (1982) (Starpath)" "" "Cartridge.MD5" "a30ece6dc4787e474fbc4090512838dc" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Circus (Zellers)" "Cartridge.Note" "AKA Circus Atari" "" "Cartridge.MD5" "a310494ad5ba2b5b221a30d7180a0336" "Cartridge.Name" "Demo Image Series #6 - Mario (19-02-2003) (AD)" "" "Cartridge.MD5" "a336beac1f0a835614200ecd9c41fd70" "Cartridge.Manufacturer" "Atari, Christopher H. Omarzu, Robert Vieira" "Cartridge.ModelNo" "CX26121" "Cartridge.Name" "Zoo Keeper Sounds (1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "a34560841e0878c7b14cc65f79f6967d" "Cartridge.Manufacturer" "Multivision, Michael Case" "Cartridge.Name" "Harem (1982) (Multivision)" "" "Cartridge.MD5" "a3486c0b8110d9d4b1db5d8a280723c6" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Robert C. Polaro" "Cartridge.ModelNo" "CX26100" "Cartridge.Name" "Bugs Bunny (08-04-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "a35d47898b2b16ec641d1dfa8a45c2b7" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-017, AX-017-04" "Cartridge.Name" "MegaMania (1982) (Activision) (16K)" "" "Cartridge.MD5" "a3873d7c544af459f40d58dfcfb78887" "Cartridge.Name" "Tennis (Unknown)" "" "Cartridge.MD5" "a3b9d2be822eab07e7f4b10593fb5eaa" "Cartridge.Name" "GREGXM Demo (PD)" "" "Cartridge.MD5" "a3c1c70024d7aabb41381adbfb6d3b25" "Cartridge.Manufacturer" "Telesys, Alex Leavens" "Cartridge.ModelNo" "1005" "Cartridge.Name" "Stargunner (1983) (Telesys)" "" "Cartridge.MD5" "a3d7c299fbcd7b637898ee0fdcfc47fc" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "AR-4300" "Cartridge.Name" "Fireball (Preview) (1982) (Arcadia) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "a3f2a0fcf74bbc5fa763b0ee979b05b1" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "873.790 0" "Cartridge.Name" "Eishockey-Fieber (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Ice Hockey" "" "Cartridge.MD5" "a3f8aebb38182749cb8da85cfbc63d7c" "Cartridge.Name" "Tennis (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a3fee8ce15525ea00d45a06f04c215d1" "Cartridge.Manufacturer" "Aaron Curtis" "Cartridge.Name" "AStar (PAL60)" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "Cartridge.MD5" "a406d2f6d84e61d842f4cb13b2b1cfa7" "Cartridge.Manufacturer" "Tigervision, John Harris - Teldec" "Cartridge.ModelNo" "7-002" "Cartridge.Name" "Jawbreaker (1982) (Tigervision) (PAL)" "" "Cartridge.MD5" "a412c8577b2d57b09185ae51739ac54f" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4000" "Cartridge.Name" "Phaser Patrol (1982) (Arcadia) [a]" "Display.YStart" "24" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a41450333f8dd0e96e5e9f0af3770ae9" "Cartridge.Name" "Basic Math (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "a422194290c64ef9d444da9d6a207807" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Hal Finney" "Cartridge.ModelNo" "MT5667" "Cartridge.Name" "Dark Cavern (1982) (M Network)" "" "Cartridge.MD5" "a443d8557d712845c8cd3699363a42e6" "Cartridge.Name" "Star Fire (07-01-2003) (MP)" "" "Cartridge.MD5" "a47878a760f5fa3aa99f95c3fdc70a0b" "Cartridge.Name" "Demo Image Series #5 - Baboon (19-02-2003) (AD)" "" "Cartridge.MD5" "a4790224bd5afabd53cbe93e46a7f241" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-019" "Cartridge.Name" "Sky Jinks (1982) (Activision) (8K)" "" "Cartridge.MD5" "a47e26096de6f6487bf5dd2d1cced294" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX2643" "Cartridge.Name" "Codebreaker (1978) (Atari) (PAL)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "a499d720e7ee35c62424de882a3351b6" "Cartridge.Manufacturer" "Sega - Beck-Tech, Steve Beck, Phat Ho" "Cartridge.ModelNo" "009-01" "Cartridge.Name" "Up 'n Down (1984) (Sega)" "" "Cartridge.MD5" "a4aa7630e4c0ad7ebb9837d2d81de801" "Cartridge.Name" "Atari 2600 Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a4ab331e8768eafdc20ce8b0411ff77a" "Cartridge.Name" "Demo Image Series #1 - Sam (19-02-2003) (AD)" "" "Cartridge.MD5" "a4b9423877a0b86ca35b52ca3c994ac5" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-805" "Cartridge.Name" "Sea Monster (1983) (CCE)" "Cartridge.Note" "O Monstro Marinho" "Display.Height" "220" "" "Cartridge.MD5" "a4b99aa5ed85cfdb7d101923147de035" "Cartridge.Manufacturer" "Jim Goebel" "Cartridge.Name" "Pac-Law (Jim Goebel) (Hack)" "Cartridge.Note" "Hack of Outlaw" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a4c08c4994eb9d24fb78be1793e82e26" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AX-012, CAX-012, AX-012-04" "Cartridge.Name" "Ice Hockey (1981) (Activision)" "" "Cartridge.MD5" "a4d026a5c200ef98518ebb77719fe8dc" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "SpongeBob SquarePants (2003) (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Revenge of the Beefsteak Tomatoes" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a4e885726af9d97b12bb5a36792eab63" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Beck-Tech, Steve Beck" "Cartridge.ModelNo" "6210, 7210, 06003. 99001" "Cartridge.Name" "Spike's Peak (1983) (Xonox)" "Display.YStart" "28" "Display.Height" "223" "" "Cartridge.MD5" "a4ecb54f877cd94515527b11e698608c" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX26119" "Cartridge.Name" "Saboteur (12-20-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "a4f1cea2c8479284e2a2292f8d51b5fa" "Cartridge.Name" "Gunfight 2600 - The Final Kernel Part 2 (MP)" "" "Cartridge.MD5" "a4ff39d513b993159911efe01ac12eba" "Cartridge.Manufacturer" "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko" "Cartridge.ModelNo" "CX2694" "Cartridge.Name" "Pole Position (1983) (Atari)" "Cartridge.Note" "AKA RealSports Driving" "" "Cartridge.MD5" "a511f7ee13e4b35512f9217a677b4028" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX2674" "Cartridge.Name" "E.T. - The Extra-Terrestrial (1982) (Atari) (PAL) [a]" "" "Cartridge.MD5" "a5262fe6d01d6a1253692682a47f79dd" "Cartridge.Name" "JKH Text Scrolling Demo (PD)" "" "Cartridge.MD5" "a537879d8e82e1061d3ad800479d3b84" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Brooni (2001) (Andrew Wallace) (PD) (PAL)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "a539b9fd1ba57e46442b3e9351e6383b" "Cartridge.Name" "River Raid (208 in 1) (Unknown) (PAL) (Hack) [a]" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a56b642a3d3ab9bbeee63cd44eb73216" "Cartridge.Manufacturer" "Carrere Video - JWDA, Sylvia Day, Todd Marshall, Robin McDaniel, Henry Will IV - Teldec - Prism" "Cartridge.ModelNo" "USC2001" "Cartridge.Name" "Gopher (1983) (Carrere Video) (PAL)" "Cartridge.Note" "AKA Vossicht Whlmaus!" "" "Cartridge.MD5" "a5855d73d304d83ef07dde03e379619f" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.Name" "Boggle (08-07-1978) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Height" "215" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a58b11148c18d85e4c2aef4ff46ade67" "Cartridge.Name" "Video Chess (Unknown) (PAL)" "" "Cartridge.MD5" "a591b5e8587aae0d984a0f6fe2cc7d1c" "Cartridge.Name" "Globe Trotter Demo (24-03-2003) (Weston)" "" "Cartridge.MD5" "a5b7f420ca6cc1384da0fed523920d8e" "Cartridge.Name" "Adventure (New Graphics) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a5c96b046d5f8b7c96daaa12f925bef8" "Cartridge.Manufacturer" "Activision, Alan Miller - Ariola" "Cartridge.ModelNo" "EAG-007, EAG-007-04I, PAG-007 - 711 007-720" "Cartridge.Name" "Tennis (1981) (Activision) (PAL)" "" "Cartridge.MD5" "a5e9ed3033fb2836e80aa7a420376788" "Cartridge.Manufacturer" "Atari, Carla Meninsky" "Cartridge.ModelNo" "CX2637, CX2637P" "Cartridge.Name" "Dodge 'Em (1980) (Atari) (PAL)" "" "Cartridge.MD5" "a60598ad7ee9c5ccad42d5b0df1570a1" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Surround (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "a6127f470306eed359d85eb4a9cf3c96" "Cartridge.Manufacturer" "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26110" "Cartridge.Name" "Crystal Castles (1984) (Atari) [a]" "" "Cartridge.MD5" "a62e3e19280ff958407e05ca0a2d5ec7" "Cartridge.Name" "Hangman Ghost Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a6737c81542a99ee71cb5f5ff14703d9" "Cartridge.Name" "Scrolling Playfield 3 (Junkosoft) (PD)" "" "Cartridge.MD5" "a69f5b1761a8a11c98e706ec7204937f" "Cartridge.Name" "Pharaoh's Curse (Unknown) (PAL)" "Display.YStart" "34" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a74689a08746a667a299b0507e1e6dd9" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "9 AR-4105" "Cartridge.Name" "Official Frogger, The (1983) (Starpath) (PAL)" "" "Cartridge.MD5" "a7523db9a33e9417637be0e71fa4377c" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP238" "Cartridge.Name" "Gangster (Ariola) (PAL)" "Cartridge.Note" "AKA Outlaw" "" "Cartridge.MD5" "a7673809068062106db8e9d10b56a5b3" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Andrew Fuchs, Dave Staugas, Robert Vieira" "Cartridge.ModelNo" "CX26118, CX26118P" "Cartridge.Name" "Millipede (1984) (Atari) (PAL)" "" "Cartridge.MD5" "a779b9fa02c62d00d7c31ed51268f18a" "Cartridge.Manufacturer" "Arcadia Corporation, Brian McGhie" "Cartridge.ModelNo" "AR-4104" "Cartridge.Name" "Rabbit Transit (1983) (Arcadia) [a]" "" "Cartridge.MD5" "a7a58e9291aefa1064e933071f60d4ef" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "1 AR-4000, AR-4100" "Cartridge.Name" "Phaser Patrol (1982) (Arcadia) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a7b584937911d60c120677fe0d47f36f" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Hal Finney - INTV" "Cartridge.ModelNo" "MT5661" "Cartridge.Name" "Armor Ambush (1982) (M Network)" "Cartridge.Note" "AKA Tank Battle" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "a7b96a8150600b3e800a4689c3ec60a2" "Cartridge.Manufacturer" "Atari, Mike Lorenzen - Sears" "Cartridge.ModelNo" "CX2630 - 49-75122" "Cartridge.Name" "Circus Atari (1980) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 55" "" "Cartridge.MD5" "a7cf2b9afdbb3a161bf418dbcf0321dc" "Cartridge.Manufacturer" "Barry Laws Jr." "Cartridge.Name" "Attack Of The Mutant Space Urchins (2002) (Barry Laws Jr.) (Hack)" "Cartridge.Note" "Hack of Alien" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a7ed7dc5cbc901388afa59030fb11d26" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX2606, CX2606P" "Cartridge.Name" "Slot Racers (1978) (Atari) (PAL)" "" "Cartridge.MD5" "a7ef44ccb5b9000caf02df3e6da71a92" "Cartridge.Manufacturer" "Atari, Ian Shepard - Sears" "Cartridge.ModelNo" "CX2604 - 6-99812, 49-75106" "Cartridge.Name" "Space War (1978) (Atari)" "" "Cartridge.MD5" "a8101cb667e50a46165c6fb48c608b6b" "Cartridge.Name" "Kung Fu Sprite Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a81697b0c8bbc338ae4d0046ede0646b" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Gravitar (CCE)" "" "Cartridge.MD5" "a81b29177f258494b499fbac69789cef" "Cartridge.Manufacturer" "Greg Thompson" "Cartridge.Name" "Console Wars (Greg Thompson) (Hack)" "Cartridge.Note" "Hack of Space Jockey" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a83b070b485cf1fb4d5a48da153fdf1a" "Cartridge.Manufacturer" "Apollo" "Cartridge.ModelNo" "AP-2011" "Cartridge.Name" "Pompeii (1983) (Apollo) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "a8435ec570141de5d833c4abec499e55" "Cartridge.Name" "Happy Birthday Demo (2001) (Dennis Debro) (PD)" "" "Cartridge.MD5" "a8633050a686270fcf6c0cc4dcbad630" "Cartridge.Manufacturer" "Zirok" "Cartridge.Name" "Phoenix (Zirok)" "" "Cartridge.MD5" "a867b76098786c4091dba2fcee5084c3" "Cartridge.Name" "Dragrace (Hack)" "Cartridge.Note" "Hack of Dragster" "Cartridge.Rarity" "Hack" "Display.YStart" "20" "" "Cartridge.MD5" "a875f0a919129b4f1b5103ddd200d2fe" "Cartridge.Manufacturer" "Atari, Dan Hitchens. Mimi Nyden" "Cartridge.ModelNo" "CX2656" "Cartridge.Name" "SwordQuest - EarthWorld (1982) (Atari) (PAL)" "Cartridge.Note" "AKA Adventure I, SwordQuest I - EarthWorld" "" "Cartridge.MD5" "a8916734ff8c64ec3342f4c73fd5b57d" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "Stand Alone Test Cart (1982) (Atari) [a]" "" "Cartridge.MD5" "a89a3e0547d6887279c34aba4b17a560" "Cartridge.Manufacturer" "M Network, Steve Crandall, Patricia Lewis Du Long" "Cartridge.ModelNo" "MT4646" "Cartridge.Name" "Rocky & Bullwinkle (1983) (Mattel) (Prototype)" "Cartridge.Rarity" "Prototype" "Cartridge.Type" "4K" "" "Cartridge.MD5" "a8a703e073183a89c94d4d99b9661b7f" "Cartridge.Manufacturer" "Franklin Cruz" "Cartridge.Name" "Spice Invaders (Franklin Cruz) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "a8b3ea6836b99bea77c8f603cf1ea187" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-861" "Cartridge.Name" "Boxing (1983) (CCE)" "" "Cartridge.MD5" "a8c48b4e0bf35fe97cc84fdd2c507f78" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG201" "Cartridge.Name" "Seamonster (1982) (Puzzy)" "Display.Height" "220" "" "Cartridge.MD5" "a8d0a4a77cd71ac601bd71df5a060e4c" "Cartridge.Name" "Space Shuttle (1983) (Activision) [t2] (Fuel)" "" "Cartridge.MD5" "a8d4a9500b18b0a067a1f272f869e094" "Cartridge.Name" "Red And White Checkerboard Demo (PD)" "" "Cartridge.MD5" "a8e49d7e24ce293629ca29614862821b" "Cartridge.Name" "Enduro (Genesis)" "Cartridge.Note" "Genesis controller (B is acceleration, C is brakes)" "Cartridge.Rarity" "Hack of Enduro" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "a91d0858a52de3a2e6468437212d93e8" "Cartridge.Name" "Q-bert (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "a936d80083e99d48752ad15c2b5f7c96" "Cartridge.Name" "Room of Doom (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a93e8ea1f565c3c1e86b708cf0dc2fa9" "Cartridge.Manufacturer" "Jess Ragan" "Cartridge.Name" "Kabul! (Jess Ragan) (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "a94528ae05dd051894e945d4d2349b3b" "Cartridge.Manufacturer" "Genus" "Cartridge.Name" "River Raid (Genus)" "" "Cartridge.MD5" "a94b8ca630f467b574b614808d813919" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "773-883" "Cartridge.Name" "2 Pak Special - Space Voyage, Fire Alert (1992) (HES) (PAL)" "" "Cartridge.MD5" "a9531c763077464307086ec9a1fd057d" "Cartridge.Manufacturer" "Atari, John Dunn - Sears" "Cartridge.ModelNo" "CX2631 - 49-75152" "Cartridge.Name" "Superman (1979) (Atari)" "" "Cartridge.MD5" "a957dbe7d85ea89133346ad56fbda03f" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.ModelNo" "CX2649, CX2649P" "Cartridge.Name" "Asteroids (1981) (Atari) (PAL) [a1]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "a97733b0852ee3096300102cb0689175" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-834" "Cartridge.Name" "Fast Eddie (1983) (CCE)" "" "Cartridge.MD5" "a9784c24cddb33bd0d14442b97784f3d" "Cartridge.Name" "Omega Race DC (2003) (TJ) (Omega Race Hack)" "" "Cartridge.MD5" "a98b649912b6ca19eaf5c2d2faf38562" "Cartridge.Name" "This Planet Sucks (Greg Troutman) (PAL) [!]" "Cartridge.Rarity" "New Release" "Display.YStart" "36" "" "Cartridge.MD5" "a995b6cbdb1f0433abc74050808590e6" "Cartridge.Manufacturer" "Imagic, Rob Fulop, Bob Smith" "Cartridge.ModelNo" "720106-1A, IA3600" "Cartridge.Name" "Riddle of the Sphinx (1982) (Imagic)" "" "Cartridge.MD5" "a9cb638cd2cb2e8e0643d7a67db4281c" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Larry Zwick - INTV" "Cartridge.ModelNo" "MT5861" "Cartridge.Name" "Air Raiders (1983) (M Network)" "Cartridge.Note" "AKA Air Battle" "" "Cartridge.MD5" "a9d9e19d0c89fb31780b5d63e1f8c6a4" "Cartridge.Manufacturer" "AtariAge, Chris Spry" "Cartridge.ModelNo" "CX26201" "Cartridge.Name" "Zippy the Porcupine (2014) (Sprybug) (PAL60)" "Cartridge.Rarity" "Homebrew" "Display.Format" "PAL60" "" "Cartridge.MD5" "a9e3c23599c0d77151602f8e31daf879" "Cartridge.Name" "Kung Fu Master (Genesis)" "Cartridge.Note" "Genesis controller (C is extra kick modes)" "Cartridge.Rarity" "Hack of Kung Fu Master" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "aa1c41f86ec44c0a44eb64c332ce08af" "Cartridge.Manufacturer" "Spectravideo, David Lubar" "Cartridge.ModelNo" "SA-218" "Cartridge.Name" "Bumper Bash (1983) (Spectravideo)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Display.YStart" "20" "" "Cartridge.MD5" "aa2c4b32656bde9a75042a4d158583e1" "Cartridge.Name" "Oystron X (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "aa5cfe3b20395aba1d479135943ad85c" "Cartridge.Name" "Defender (Hack) (Unknown)" "Cartridge.Rarity" "Hack of Defender" "" "Cartridge.MD5" "aa7bb54d2c189a31bb1fa20099e42859" "Cartridge.Manufacturer" "CBS Electronics, Ed English" "Cartridge.ModelNo" "4L4478" "Cartridge.Name" "Mr. Do! (1983) (CBS Electronics) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "aa8e4b2cb8a78ffe6b20580033f4dec9" "Cartridge.Name" "Bitmap Demo (13-01-2003) (AD)" "" "Cartridge.MD5" "aaac0d277eda054861e613c59c2e4ff2" "Cartridge.Manufacturer" "JWDA, Todd Marshall" "Cartridge.Name" "Music Demo (JWDA)" "" "Cartridge.MD5" "aab840db22075aa0f6a6b83a597f8890" "Cartridge.Manufacturer" "Home Vision, R.J.P.G. - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83124" "Cartridge.Name" "Racing Car (1983) (Home Vision) (PAL)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "aad61898633f470ce528e3d7ef3d0adb" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype) [a1]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "aad91be0bf78d33d29758876d999848a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-018, AX-018-04" "Cartridge.Name" "Pitfall! (1981) (Activision) (Prototype)" "Cartridge.Note" "Pitfall Harry's Jungle Adventure (Jungle Runner)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "aaea37b65db9e492798f0105a6915e96" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix - Tug of War (2 of 3) (1983) (Arcadia)" "Cartridge.Note" "Uses Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "02" "" "Cartridge.MD5" "aafc79ffc32c4c9b2d73c8ada7602cfe" "Cartridge.Name" "Planet Patrol (Unknown) (PAL)" "" "Cartridge.MD5" "ab10f2974dee73dab4579f0cab35fca6" "Cartridge.Manufacturer" "ITT Family Games" "Cartridge.Name" "Wilma Wanderer (1983) (ITT Family Games) (PAL)" "Cartridge.Note" "AKA Lilly Adventure" "" "Cartridge.MD5" "ab2cfcaad3daaf673b2b14fdbb8dac33" "Cartridge.Manufacturer" "M Network, David Akers, Joe King, Patricia Lewis Du Long, Jeff Ratcliff - INTV" "Cartridge.ModelNo" "MT7045" "Cartridge.Name" "Bump 'n' Jump (1983) (M Network)" "" "Cartridge.MD5" "ab2ea35dcc1098c87455bb8210b018cf" "Cartridge.Name" "Fu Kung! (V0.04 Single Line Resolution) (10-01-2003) (AD)" "" "Cartridge.MD5" "ab301d3d7f2f4fe3fdd8a3540b7a74f5" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "IQ 180 (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "27" "Display.Height" "230" "" "Cartridge.MD5" "ab434f4c942d6472e75d5490cc4dd128" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "773-875" "Cartridge.Name" "2 Pak Special - Hoppy, Alien Force (1992) (HES) (PAL)" "" "Cartridge.MD5" "ab4ac994865fb16ebb85738316309457" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2624 - 6-99826, 49-75113" "Cartridge.Name" "Basketball (1978) (Atari)" "Cartridge.Note" "Console ports are swapped" "Cartridge.Rarity" "Common" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "ab56f1b2542a05bebc4fbccfc4803a38" "Cartridge.Manufacturer" "Activision - Imagineering, Dan Kitchen, David Lubar" "Cartridge.ModelNo" "AK-048-04" "Cartridge.Name" "River Raid II (1988) (Activision)" "" "Cartridge.MD5" "ab5bf1ef5e463ad1cbb11b6a33797228" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.ModelNo" "720104-1A, 720104-1B, IA3204" "Cartridge.Name" "Cosmic Ark (1982) (Imagic)" "" "Cartridge.MD5" "ab60ea7b707c58d356cad858eb18db43" "Cartridge.Name" "Tazer (John K. Harvey)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ab8d318da4addd39c65b7f9c408df2a6" "Cartridge.Name" "Star Trek (Genesis)" "Cartridge.Note" "Genesis controller (B is phaser, C is warp)" "Cartridge.Rarity" "Hack of Star Trek" "Controller.Left" "GENESIS" "Display.Phosphor" "YES" "" "Cartridge.MD5" "abb740bea0a6842831b4f53112fb8145" "Cartridge.Name" "Qb (V1.01) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "abb741c83f665d73c86d90a7d9292a9b" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Space Attack (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "abc64037ca5d5b04ae8a7eedbca3ed74" "Cartridge.Name" "Green and Yellow Number 1 Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "abe40542e4ff2d1c51aa2bb033f09984" "Cartridge.Manufacturer" "Absolute Entertainment, David Crane" "Cartridge.ModelNo" "EAZ-042-04B, EAZ-042-04I" "Cartridge.Name" "Skate Boardin' (1987) (Absolute) (PAL)" "" "Cartridge.MD5" "ac05c0e53a5e7009ddd75ed4b99949fc" "Cartridge.Manufacturer" "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears" "Cartridge.ModelNo" "CX2601 - 99801, 6-99801, 49-75124" "Cartridge.Name" "Combat (1977) (Atari) (4K)" "" "Cartridge.MD5" "ac0ddbcff34d064009591607746e33b8" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Atlantis FH (2003) (TJ) (Hack)" "Cartridge.Note" "Hack of Atlantis" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "ac26d7d37248d1d8eac5eccacdbef8db" "Cartridge.Name" "Snail Against Squirrel (Unknown) (PAL)" "" "Cartridge.MD5" "ac3dd22dd945724be705ddd2785487c2" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692" "Cartridge.Name" "Moon Patrol (06-15-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ac53b83e1b57a601eeae9d3ce1b4a458" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.15) (Retroactive) (NTSC)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ac5f78bae0638cf3f2a0c8d07eb4df69" "Cartridge.Name" "Minesweeper (V.99) (Soren Gust) (PD)" "" "Cartridge.MD5" "ac7c2260378975614192ca2bc3d20e0b" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-930-04, AZ-030" "Cartridge.Name" "Decathlon (1983) (Activision)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "ac9adbd6de786a242e19d4bec527982b" "Cartridge.Manufacturer" "Activision, Alan Miller - Ariola" "Cartridge.ModelNo" "EAG-012-04I, EAX-012, EAX-012-04B - 711 012-720" "Cartridge.Name" "Ice Hockey (1981) (Activision) (PAL)" "" "Cartridge.MD5" "aca09ffea77174b148b96b205109db4d" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AG-007, CAG-007" "Cartridge.Name" "Tennis (1981) (Activision) (4K)" "" "Cartridge.MD5" "acaa27d214039d89d7031609aafa55c3" "Cartridge.Name" "Sprite Demo 6 (PD)" "" "Cartridge.MD5" "acb6787b938079f4e74313a905ec3ceb" "Cartridge.Name" "Chronocolor Donkey Kong (PD)" "" "Cartridge.MD5" "acb7750b4d0c4bd34969802a7deb2990" "Cartridge.Manufacturer" "Parker Brothers, Ed Temple" "Cartridge.ModelNo" "PB5310" "Cartridge.Name" "Amidar (1982) (Parker Bros)" "Cartridge.Rarity" "Uncommon" "Console.LeftDifficulty" "A" "Console.RightDifficulty" "A" "" "Cartridge.MD5" "acb962473185d7a652f90ed6591ae13b" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "IA3203, IX-010-04" "Cartridge.Name" "Atlantis (1982) (Imagic) (16K)" "Cartridge.Note" "AKA Lost City of Atlantis" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "ace319dc4f76548659876741a6690d57" "Cartridge.Manufacturer" "Atari, Steve Wright" "Cartridge.ModelNo" "CX2616" "Cartridge.Name" "Pele's Soccer (1981) (Atari)" "Cartridge.Note" "AKA Pele's Championship Soccer" "" "Cartridge.MD5" "ad2e6bfb3b9b9b36ba8bf493ce764c49" "Cartridge.Name" "2600 Collison Demo 1 (Piero Cavina) (PD)" "" "Cartridge.MD5" "ad42e3ca3144e2159e26be123471bffc" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Human Cannonball (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "ad7e97c19bd25d5aa3999430845c755b" "Cartridge.Name" "Sprite Demo 5 (PD)" "" "Cartridge.MD5" "ad8072675109d13fdd31a2e0403d5cff" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Tank City (Funvision)" "Cartridge.Note" "AKA Thunderground" "" "Cartridge.MD5" "adb770ff70e9adf08bbb907a7eccd240" "Cartridge.Name" "Inv Demo 3 (2001) (Erik Mooney) (PD)" "" "Cartridge.MD5" "adb79f9ac1a633cdd44954e2eac14774" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Frostbite (Digivision)" "" "Cartridge.MD5" "adf1afac3bdd7b36d2eda5949f1a0fa3" "Cartridge.Manufacturer" "Quelle - Otto Versand" "Cartridge.ModelNo" "495.463 2 - 746381" "Cartridge.Name" "Angriff der Luftflotten (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Paris Attack, M.A.D." "" "Cartridge.MD5" "adfbd2e8a38f96e03751717f7422851d" "Cartridge.Manufacturer" "Champ Games" "Cartridge.ModelNo" "CG-01-N" "Cartridge.Name" "Lady Bug (NTSC)" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ae047e9468bda961d8e9e9d8ff52980f" "Cartridge.Name" "Tunnel Demo (Red Spiral) (30-03-2003) (AD)" "" "Cartridge.MD5" "ae0d4f3396cb49de0fabdff03cb2756f" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.02) (PAL) (2001) (Retroactive)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ae10527840a1ac24de43730645ed508d" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "Planet Invaders (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "ae18c11e4d7ed2437f0bf5d167c0e96c" "Cartridge.Name" "Multi-Color Demo 3 (Bob Colbert) (PD)" "" "Cartridge.MD5" "ae2f1f69bb38355395c1c75c81acc644" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart" "Cartridge.ModelNo" "PB5540" "Cartridge.Name" "Star Wars - The Arcade Game (12-23-1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ae465044dfba287d344ba468820995d7" "Cartridge.Name" "Inca Gold (Unknown) (PAL)" "" "Cartridge.MD5" "ae4be3a36b285c1a1dff202157e2155d" "Cartridge.Manufacturer" "Spectravideo" "Cartridge.ModelNo" "SA-210" "Cartridge.Name" "Master Builder (1983) (Spectravideo)" "" "Cartridge.MD5" "ae682886058cd6981c4b8e93e7b019cf" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.12) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ae6cb335470788b94beb5787976e8818" "Cartridge.Name" "Mortal Kurling (02-01-2003) (CT)" "" "Cartridge.MD5" "ae83541cf4a4c0bce0adccd2c1bf6288" "Cartridge.Name" "Maze 003 Demo (PD)" "" "Cartridge.MD5" "ae97cf8ed21f4154b4360a3cf6c95c5e" "Cartridge.Name" "Teleterm 2600 (John K. Harvey) (PD)" "" "Cartridge.MD5" "aeb104f1e7b166bc0cbaca0a968fde51" "Cartridge.Name" "Ms. Pac-Man (1999) (Hack)" "Cartridge.Note" "Hack of Ms. Pac-Man" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "aec9b885d0e8b24e871925630884095c" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.ModelNo" "3125" "Cartridge.Name" "Surf's Up (1983) (Amiga) (Prototype)" "Cartridge.Note" "Uses the Joyboard controller" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "aed0b7bd64cc384f85fdea33e28daf3b" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Robert C. Polaro" "Cartridge.ModelNo" "CX2666" "Cartridge.Name" "RealSports Volleyball (1982) (Atari)" "" "Cartridge.MD5" "aed82052f7589df05a3f417bb4e45f0c" "Cartridge.Manufacturer" "Atari, Warren Robinett - Sears" "Cartridge.ModelNo" "CX2606 - 6-99825, 49-75112" "Cartridge.Name" "Slot Racers (1978) (Atari)" "" "Cartridge.MD5" "af6ab88d3d7c7417db2b3b3c70b0da0a" "Cartridge.Manufacturer" "Activision, Larry Kaplan, David Crane" "Cartridge.ModelNo" "AG-010, AG-010-04" "Cartridge.Name" "Kaboom! (1981) (Activision) (4K)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "af6f3e9718bccfcd8afb421f96561a34" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2695" "Cartridge.Name" "Xevious (01-18-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "afb3bc45c6a82739cc82582127cd96e6" "Cartridge.Manufacturer" "Atari - Sculptured Software, Adam Clayton" "Cartridge.ModelNo" "CX26151, CX26151P" "Cartridge.Name" "Dungeon (11-22-1985) (Atari) (Prototype)" "Cartridge.Note" "Dark Chambers Beta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "afc194534c1b346609ef05eff6d3cef6" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Boxing (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "afd2cf258d51ae4965ee21abba3627ab" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu" "Cartridge.ModelNo" "CX26104" "Cartridge.Name" "Big Bird's Egg Catch (12-08-1982) (Atari) (Prototype)" "Cartridge.Note" "Uses the Keypad Controller" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "" "Cartridge.MD5" "afe4eefc7d885c277fc0649507fbcd84" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Ant Party (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Cosmic Swarm" "Display.Phosphor" "YES" "" "Cartridge.MD5" "afe776db50e3378cd6f29c7cdd79104a" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Bobby is Going Home (TJ)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.YStart" "23" "Display.Height" "245" "" "Cartridge.MD5" "afe88aae81d99e0947c0cfb687b16251" "Cartridge.Manufacturer" "Apollo - Games by Apollo" "Cartridge.ModelNo" "AP-2006" "Cartridge.Name" "Infiltrate (1982) (Apollo)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "aff8cba0f2d2eb239953dd7116894a08" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (3 of 3) (1982) (Starpath) (PAL)" "" "Cartridge.MD5" "b00088418fc891f3faa3d4ddde6ace94" "Cartridge.Name" "Unknown Title (bin00007 (200102)) (PD)" "" "Cartridge.MD5" "b00a8bc9d7fe7080980a514005cbad13" "Cartridge.Manufacturer" "K-Tel Vision" "Cartridge.Name" "Vulture Attack (1982) (K-Tel Vision) (PAL)" "Cartridge.Note" "AKA Condor Attack" "" "Cartridge.MD5" "b00e8217633e870bf39d948662a52aac" "Cartridge.Manufacturer" "Konami" "Cartridge.ModelNo" "RC 102-X 02" "Cartridge.Name" "Marine Wars (1983) (Konami)" "" "Cartridge.MD5" "b049fc8ac50be7c2f28418817979c637" "Cartridge.Manufacturer" "Activision - Imagineering, Dan Kitchen, David Lubar" "Cartridge.ModelNo" "EAK-048-04, EAK-048-04B" "Cartridge.Name" "River Raid II (1988) (Activision) (PAL)" "" "Cartridge.MD5" "b06050f686c6b857d0df1b79fea47bb4" "Cartridge.Manufacturer" "Activision" "Cartridge.ModelNo" "AIZ-001" "Cartridge.Name" "Moonsweeper (1988) (Activision)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b061e98a4c854a672aadefa233236e51" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX2620, CX2620P" "Cartridge.Name" "Basic Programming (1979) (Atari) (PAL)" "Cartridge.Note" "Uses Keypad Controllers" "Cartridge.Rarity" "Common" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b095009004df341386d22b2a3fae3c81" "Cartridge.Name" "Sub-Scan (Unknown) (PAL)" "" "Cartridge.MD5" "b09b79c9628878be051e89f7f1e77378" "Cartridge.Manufacturer" "Activision, Larry Kaplan, David Crane - Ariola" "Cartridge.ModelNo" "EAG-010, PAG-010 - 711 010-720" "Cartridge.Name" "Kaboom! (1981) (Activision) (PAL) (4K)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "b0ba51723b9330797985808db598fc31" "Cartridge.Manufacturer" "Atari, Michael Callahan, Preston Stuart" "Cartridge.ModelNo" "CX26103" "Cartridge.Name" "Alpha Beam with Ernie (1983) (Atari) (PAL) [a]" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "b0c47e426c7f799aee2c40422df8f56a" "Cartridge.Name" "Space Treat (PAL) (Fabrizio Zavagli)" "" "Cartridge.MD5" "b0c9cf89a6d4e612524f4fd48b5bb562" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2663" "Cartridge.Name" "Combat Two (1982) (Atari) (Prototype)" "Cartridge.Note" "AKA Super Combat" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "b0e1ee07fbc73493eac5651a52f90f00" "Cartridge.Manufacturer" "Colin Hughes" "Cartridge.Name" "Tetris 2600 (Colin Hughes)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b12a7f63787a6bb08e683837a8ed3f18" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.ModelNo" "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04" "Cartridge.Name" "Demon Attack (1982) (Imagic) [fixed]" "Cartridge.Note" "AKA Death from Above" "" "Cartridge.MD5" "b1339c56a9ea63122232fe4328373ac5" "Cartridge.Manufacturer" "Goliath - Hot Shot" "Cartridge.ModelNo" "83-215" "Cartridge.Name" "Dream Flight (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Nightmare" "Display.Height" "256" "" "Cartridge.MD5" "b1486e12de717013376447ac6f7f3a80" "Cartridge.Manufacturer" "Spectravideo, Mark Turmell, Quelle" "Cartridge.ModelNo" "SA-217, SA-217C - 413.723 8" "Cartridge.Name" "Gas Hog - Piraten Schiff (1983) (Spectravideo) (PAL)" "" "Cartridge.MD5" "b15026b43c6758609667468434766dd8" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (0.06) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b16cd9784589219391c839cb68c47b9c" "Cartridge.Manufacturer" "Video Soft, Jerry Lawson, Dan McElroy" "Cartridge.Name" "Golf Diagnostic (1983) (Video Soft) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "b17b9cc4103844dcda54f77f44acc93a" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "377.943 6" "Cartridge.Name" "Stopp die Gangster (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Gangster Alley" "" "Cartridge.MD5" "b1a6c96e9093352106bc335e96caa154" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 1 (Joe Grand)" "Cartridge.Rarity" "New Release" "Display.YStart" "38" "" "Cartridge.MD5" "b1b20536aef4eed9c79dc5804f077862" "Cartridge.Name" "Euchre (NTSC) (09-11-2001) (Erik Eid)" "" "Cartridge.MD5" "b1c14b5ac896400cc91c8e5dd67acb59" "Cartridge.Name" "River Raid (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b1d1e083dc9e7d9a5dc1627869d2ade7" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-1004" "Cartridge.Name" "Mario's Bros. (1983) (CCE)" "Cartridge.Note" "AKA Mario Bros." "" "Cartridge.MD5" "b1e2d5dc1353af6d56cd2fe7cfe75254" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26171" "Cartridge.Name" "MotoRodeo (1991) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b1fd0b71de9f6eeb5143a97963674cb6" "Cartridge.Name" "Multi-Color Demo 7 (Bob Colbert) (PD)" "" "Cartridge.MD5" "b227175699e372b8fe10ce243ad6dda5" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2649, 49-75163" "Cartridge.Name" "Asteroids (1981) (Atari) [a1]" "Cartridge.Rarity" "Common" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b23ebf427713dd0198b7ef47dbd07ef4" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Sky Diver (Jone Yuan) (4K) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b24f6a5820a4b7763a3d547e3e07441d" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-823" "Cartridge.Name" "Demon Attack (1983) (CCE)" "" "Cartridge.MD5" "b26506fbf411009e5e3f7365f442960e" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2642" "Cartridge.Name" "Hunt & Score (1978) (Atari) (PAL) (4K)" "Cartridge.Note" "Uses the Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "b2737034f974535f5c0c6431ab8caf73" "Cartridge.Manufacturer" "CBS Electronics, Richard K. Balaska Jr., Andy Frank, Stuart Ross" "Cartridge.ModelNo" "4L 2520 5000" "Cartridge.Name" "Tunnel Runner (1983) (CBS Electronics)" "" "Cartridge.MD5" "b2761efb8a11fc59b00a3b9d78022ad6" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2651 - 99805, 49-75602" "Cartridge.Name" "Blackjack (1977) (Atari) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "" "Cartridge.MD5" "b290c2b139344fcff5b312c71b9ac3b2" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "UFO (32 in 1) (1988) (Atari) (PAL) (4K)" "Cartridge.Note" "AKA Space Jockey" "" "Cartridge.MD5" "b29359f7de62fed6e6ad4c948f699df8" "Cartridge.Manufacturer" "Goliath" "Cartridge.ModelNo" "3" "Cartridge.Name" "Phantom Tank (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Tanks But No Tanks" "" "Cartridge.MD5" "b2a6f31636b699aeda900f07152bab6e" "Cartridge.Name" "Space Instigators (Public Release 2) (06-01-2003) (CT)" "" "Cartridge.MD5" "b2d1e63f7f22864096b7b6c154151d55" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Bounce! (17-03-2003) (Fabrizio Zavagli)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b2d3bcee001cff2bd2d8a21b2cb55109" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Kevin Osborn" "Cartridge.ModelNo" "CX2691" "Cartridge.Name" "Joust (08-09-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b2d5d200f0af8485413fad957828582a" "Cartridge.Manufacturer" "Atari - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "CX26155P" "Cartridge.Name" "Sprint Master (1988) (Atari) (PAL)" "Cartridge.Note" "AKA Sprint 88, Sprint 2000" "" "Cartridge.MD5" "b2f0d7217147160b2f481954cedf814b" "Cartridge.Name" "Marquee Drawer (2001) (B. Watson)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b3017e397f74efd53caf8fae0a38e3fe" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.12) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b311ab95e85bc0162308390728a7361d" "Cartridge.Manufacturer" "Parker Brothers - Roklan" "Cartridge.ModelNo" "PB5080" "Cartridge.Name" "Gyruss (1984) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b31dc989f594764eacfa7931cead0050" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (2 of 3) (1983) (Arcadia)" "" "Cartridge.MD5" "b31f178aa0d569cccac7959f84e0a724" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2699" "Cartridge.Name" "Taz (07-13-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "b3203e383b435f7e43f9492893c7469f" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-003" "Cartridge.Name" "Sssnake (1983) (Gameworld) (PAL)" "" "Cartridge.MD5" "b36040a2f9ecafa73d835d804a572dbf" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Pac Man (1983) (Digitel)" "" "Cartridge.MD5" "b37f0fe822b92ca8f5e330bf62d56ea9" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Beck-Tech, Steve Beck" "Cartridge.ModelNo" "6210, 7210, 06003. 99001" "Cartridge.Name" "Spike's Peak (1983) (Xonox) (PAL)" "" "Cartridge.MD5" "b392964e8b1c9c2bed12246f228011b2" "Cartridge.Name" "Name This Game (Unknown) (PAL)" "" "Cartridge.MD5" "b4030c38a720dd84b84178b6ce1fc749" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Kevin Miller" "Cartridge.ModelNo" "MT5687" "Cartridge.Name" "International Soccer (1982) (M Network)" "" "Cartridge.MD5" "b40dea357d41c5408546e4e4d5f27779" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Spider Fighter (Digivision)" "" "Cartridge.MD5" "b41fdd4a522e1d5a2721840028684ac2" "Cartridge.Name" "Green and Yellow Number 1 Demo 2 (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b42df8d92e3118dc594cecd575f515d7" "Cartridge.Manufacturer" "Mystique - American Multiple Industries" "Cartridge.ModelNo" "1003" "Cartridge.Name" "Burning Desire (1982) (Mystique) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b438a6aa9d4b9b8f0b2ddb51323b21e4" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5861 A030" "Cartridge.Name" "Bogey Blaster (1988) (Telegames) (PAL)" "Cartridge.Note" "AKA Air Raiders" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "b451307b8b5e29f1c5f2cf064f6c7227" "Cartridge.Name" "Demo Image Series #6 - Mario (Fixed) (26-02-2003) (AD)" "" "Cartridge.MD5" "b49331b237c8f11d5f36fe2054a7b92b" "Cartridge.Name" "Condor Attack (Unknown) (PAL)" "" "Cartridge.MD5" "b4a4c87840613f102acb5b3a647d0a67" "Cartridge.Name" "Mobile 48 Sprite Kernel (04-01-2003) (Eric Ball)" "" "Cartridge.MD5" "b4daedb43511521db9036d503b3c1b69" "Cartridge.Name" "Sokoban (01-01-2003) (Adam Wozniak) [a1]" "" "Cartridge.MD5" "b4e2fd27d3180f0f4eb1065afc0d7fc9" "Cartridge.Manufacturer" "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, William O. Sheppard" "Cartridge.ModelNo" "5002002" "Cartridge.Name" "London Blitz (1983) (Avalon Hill)" "" "Cartridge.MD5" "b4f05e544834d0238a0c263491775edf" "Cartridge.Manufacturer" "Starpath Corporation, Steve Hales, Stephen H. Landrum" "Cartridge.ModelNo" "4 AR-4102" "Cartridge.Name" "Suicide Mission (Preview) (1982) (Starpath) (PAL)" "Cartridge.Note" "AKA Meteoroids" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b4f31ea8a6cc9f1fd4d5585a87c3b487" "Cartridge.Manufacturer" "Mystique - American Multiple Industries, Joel H. Martin" "Cartridge.Name" "Beat 'Em & Eat 'Em (1982) (Mystique) (PAL)" "Cartridge.Note" "Uses the Paddle Controller (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 45" "" "Cartridge.MD5" "b4f87ce75f7329c18301a2505fe59cd3" "Cartridge.Manufacturer" "Videospielkassett - Ariola" "Cartridge.ModelNo" "PGP232" "Cartridge.Name" "Autorennen (Ariola) (PAL)" "Cartridge.Note" "AKA Grand Prix" "" "Cartridge.MD5" "b50ae55aac93fbed258bc5a873edd2cb" "Cartridge.Manufacturer" "Recompile" "Cartridge.Name" "E.T. The Extra-Terrestrial (Recompile) (Hack)" "Cartridge.Note" "www.neocomputer.org/projects/et" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b5110f55ed99d5279f18266d001a8cd5" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Auto-mobile Demo (2001) (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "b56264f738b2eb2c8f7cf5a2a75e5fdc" "Cartridge.Manufacturer" "Atari - GCC, John Allred, Douglas B. Macrae, Betty Ryan Tylko" "Cartridge.ModelNo" "CX2694, CX2694P" "Cartridge.Name" "Pole Position (1983) (Atari) (PAL)" "Cartridge.Note" "AKA RealSports Driving" "" "Cartridge.MD5" "b5657d4c1c732fbb6af150668464247f" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Excalibur (Dragonstomper Beta) (1982) (Arcadia) (Prototype)" "" "Cartridge.MD5" "b59417d083b0be2d49a7d93769880a4b" "Cartridge.Manufacturer" "Pet Boat" "Cartridge.Name" "Donkey Kong (1983) (Pet Boat) (PAL)" "" "Cartridge.MD5" "b59fd465abf76f64c85652ff29d5952d" "Cartridge.Manufacturer" "VentureVision, Dan Oliver" "Cartridge.Name" "Innerspace (1983) (VentureVision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "b5a1a189601a785bdb2f02a424080412" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "720021-1A, IA3410" "Cartridge.Name" "Shootin' Gallery (1983) (Imagic)" "" "Cartridge.MD5" "b5cb9cf6e668ea3f4cc2be00ea70ec3c" "Cartridge.Manufacturer" "CommaVid, Irwin Gaines - Ariola" "Cartridge.ModelNo" "CM-005 - 712 005-720" "Cartridge.Name" "Mines of Minos (1982) (CommaVid) (PAL)" "Cartridge.Note" "AKA Im Labyrinth des Roboters" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b5cdbab514ea726a14383cff6db40e26" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-04" "Cartridge.Name" "Mission Survive (1983) (Video Gems) (PAL) [a]" "Console.RightDifficulty" "A" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b5efe0271d2214e4d5dc798881486884" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26192" "Cartridge.Name" "Klax (06-14-1990) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "b6166f15720fdf192932f1f76df5b65d" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.ModelNo" "3130" "Cartridge.Name" "Off Your Rocker (1983) (Amiga) (Prototype)" "Cartridge.Note" "Uses the Amiga Joyboard" "" "Cartridge.MD5" "b64426e787f04ff23ee629182c168603" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Plaque Attack (1983) (Dynacom)" "" "Cartridge.MD5" "b65d4a38d6047735824ee99684f3515e" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "MegaBoy (Dynacom)" "" "Cartridge.MD5" "b676a9b7094e0345a76ef027091d916b" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Mission Survive (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b6812eaf87127f043e78f91f2028f9f4" "Cartridge.Manufacturer" "Simage" "Cartridge.Name" "Eli's Ladder (1984) (Simage)" "" "Cartridge.MD5" "b6821ac51c4c1dcb283f01be2f047dc1" "Cartridge.Name" "Rubik's Cube 3D Demo (25-11-2002) (TJ)" "" "Cartridge.MD5" "b6960be26bee87d53ba4e2e71cfe772f" "Cartridge.Name" "3-D Corridor (Spiral Words) (31-03-2003) (AD)" "" "Cartridge.MD5" "b6d52a0cf53ad4216feb04147301f87d" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "720055-1A, IA3312" "Cartridge.Name" "No Escape! (1983) (Imagic)" "" "Cartridge.MD5" "b6e40bce550672e5495a8cdde7075b8b" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Mundry, Scott Nelson" "Cartridge.ModelNo" "AR-4401" "Cartridge.Name" "Survival Island (1 of 3) (1983) (Arcadia) (PAL)" "" "Cartridge.MD5" "b702641d698c60bcdc922dbd8c9dd49c" "Cartridge.Manufacturer" "Atari, Ian Shepard" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Space War (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "b719ada17771a8d206c7976553825139" "Cartridge.Manufacturer" "Ron Corcoran" "Cartridge.Name" "DUP Space Invaders (Ron Corcoran) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "b731d35e4ac6b3b47eba5dd0991f452f" "Cartridge.Name" "Rubik's Cube 3D Demo (Final) (08-01-2003) (TJ)" "" "Cartridge.MD5" "b7345220a0c587f3b0c47af33ebe533c" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "176.433 1" "Cartridge.Name" "Landungskommando (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Strategy X" "" "Cartridge.MD5" "b76fbadc8ffb1f83e2ca08b6fb4d6c9f" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-005, CAG-005, AG-005-04" "Cartridge.Name" "Skiing (1980) (Activision)" "" "Cartridge.MD5" "b77468d586957d1b7fb4cccda2684f47" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Boxing (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "b7903268e235310dc346a164af4c7022" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Cat Trax (Thomas Jentzsch) (PAL60)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Hack" "Display.Format" "PAL60" "Display.YStart" "30" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b79fe32320388a197ac3a0b932cc2189" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "13207, EIZ-001-04I" "Cartridge.Name" "Moonsweeper (1983) (Imagic) (PAL) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b7a7e34e304e4b7bc565ec01ba33ea27" "Cartridge.Manufacturer" "Parker Brothers" "Cartridge.ModelNo" "PB5820" "Cartridge.Name" "Mr. Do!'s Castle (1984) (Parker Bros) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b7b1d3ce07e75976c43a2dca3866237e" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Freeway Chicken (32 in 1) (1988) (Atari) (PAL) (4K)" "Cartridge.Note" "AKA Freeway" "" "Cartridge.MD5" "b7e459d5416eeb196aaa8e092db14463" "Cartridge.Name" "Push (V0.02) (1998) (AD)" "" "Cartridge.MD5" "b7f184013991823fc02a6557341d2a7a" "Cartridge.Name" "Blue Rod Demo (PD)" "" "Cartridge.MD5" "b80d50ecee73919a507498d0a4d922ae" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius Software, David Lubar" "Cartridge.ModelNo" "11008" "Cartridge.Name" "Fantastic Voyage (1982) (20th Century Fox)" "" "Cartridge.MD5" "b816296311019ab69a21cb9e9e235d12" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2652 - 6-99816, 49-75151" "Cartridge.Name" "Casino (1979) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "" "Cartridge.MD5" "b822fba8b7c8a97ea4e92aeb2c455ef9" "Cartridge.Manufacturer" "Dactari" "Cartridge.Name" "Freeway (Dactari) (4K)" "" "Cartridge.MD5" "b83579c4450fcbdf2b108903731fa734" "Cartridge.Name" "Mission 3,000 A.D. (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b83df1f32b4539c324bdf94851b4db55" "Cartridge.Manufacturer" "Angelino" "Cartridge.Name" "One On One by Angelino (Basketball Hack)" "Cartridge.Note" "Hack of Basketball (1978) (Atari)" "Cartridge.Rarity" "New Release (Hack)" "" "Cartridge.MD5" "b86552198f52cfce721bafb496363099" "Cartridge.Manufacturer" "Apollo, Tim Martin" "Cartridge.ModelNo" "AP-2007" "Cartridge.Name" "Kyphus (1982) (Apollo) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "b86a12e53ab107b6caedd4e0272aa034" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Treasure Hunting (Funvision)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "b879e13fd99382e09bcaf1d87ad84add" "Cartridge.Manufacturer" "Zellers" "Cartridge.Name" "Time Warp (Zellers)" "" "Cartridge.MD5" "b8865f05676e64f3bec72b9defdacfa7" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-004" "Cartridge.Name" "Fishing Derby (1980) (Activision)" "" "Cartridge.MD5" "b897f9e3f939b9f21566d56db812a84e" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Flag Capture (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "b8ed78afdb1e6cfe44ef6e3428789d5f" "Cartridge.Manufacturer" "Data Age, J. Ray Dettling" "Cartridge.ModelNo" "112-007" "Cartridge.Name" "Bermuda Triangle (1983) (Data Age)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "b9232c1de494875efe1858fc8390616d" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "110" "Cartridge.Name" "Harbor Escape (1983) (Panda)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "b9336ed6d94a5cc81a16483b0a946a73" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Michael Sierchio" "Cartridge.ModelNo" "CX2667, CX2667P" "Cartridge.Name" "RealSports Soccer (1983) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b958d5fd9574c5cf9ece4b9421c28ecd" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Multi-Sprite Game V1.0 (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "b95a6274ca0e0c773bfdc06b4c3daa42" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "3-D Corridor (29-03-2003) (Paul Slocum)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "b98cc2c6f7a0f05176f74f0f62c45488" "Cartridge.Manufacturer" "Spectravideo" "Cartridge.ModelNo" "SV-010" "Cartridge.Name" "CompuMate (1983) (Spectravideo)" "Cartridge.Type" "CM" "Controller.Left" "COMPUMATE" "Controller.Right" "COMPUMATE" "Display.Phosphor" "YES" "" "Cartridge.MD5" "b9b4612358a0b2c1b4d66bb146767306" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "23" "Display.Height" "245" "" "Cartridge.MD5" "b9d1e3be30b131324482345959aed5e5" "Cartridge.Manufacturer" "Activision, Rex Bradford" "Cartridge.Name" "Kabobber (07-25-1983) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "b9f6fa399b8cd386c235983ec45e4355" "Cartridge.Manufacturer" "Parker Brothers, John Emerson" "Cartridge.ModelNo" "931511" "Cartridge.Name" "Action Force (1983) (Parker Bros) (PAL)" "Cartridge.Note" "AKA G.I. Joe - Cobra Strike" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 55" "" "Cartridge.MD5" "b9f9c0fed0db08c34346317f3957a945" "Cartridge.Manufacturer" "SuperVision" "Cartridge.ModelNo" "405, 427, 806, 808, 813, 816" "Cartridge.Name" "Chopper Command (SuperVision) (PAL)" "" "Cartridge.MD5" "ba257438f8a78862a9e014d831143690" "Cartridge.Manufacturer" "U.S. Games Corporation - JWDA, Todd Marshall, Robin McDaniel, Henry Will IV" "Cartridge.ModelNo" "VC2002" "Cartridge.Name" "Squeeze Box (1983) (U.S. Games)" "" "Cartridge.MD5" "ba317f83cdfcd58cbc65aac1ccb87bc5" "Cartridge.Name" "Jammed (2001) (XYPE) [a1]" "" "Cartridge.MD5" "ba3a17efd26db8b4f09c0cf7afdf84d1" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-021" "Cartridge.Name" "Spider Fighter (1983) (Activision) (16K)" "Display.YStart" "30" "" "Cartridge.MD5" "ba3b0eebccc7b791107de5b4abb671b4" "Cartridge.Name" "Thrust (V0.9) (2000) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ba657d940a11e807ff314bba2c8b389b" "Cartridge.Manufacturer" "Activision, John Van Ryzin" "Cartridge.ModelNo" "AG-038-04" "Cartridge.Name" "Cosmic Commuter (1984) (Activision) (16K)" "" "Cartridge.MD5" "bac28d06dfc03d3d2f4a7c13383e84ee" "Cartridge.Manufacturer" "Supergame" "Cartridge.Name" "Demon Attack (Supergame)" "" "Cartridge.MD5" "bae1a23f9b6acdadf465cfb330ba0acb" "Cartridge.Manufacturer" "Atari - GCC, Doug Macrae" "Cartridge.ModelNo" "CX2677" "Cartridge.Name" "Dig Dug (1983) (Atari) [a]" "" "Cartridge.MD5" "bae66907c3200bc63592efe5a9a69dbb" "Cartridge.Manufacturer" "Spectravision - Spectravideo - Quelle" "Cartridge.ModelNo" "SA-201 - 412.783 3" "Cartridge.Name" "Gangster Alley (1982) (Spectravision) (PAL)" "" "Cartridge.MD5" "baf4ce885aa281fd31711da9b9795485" "Cartridge.Manufacturer" "Atari, Douglas Neubauer" "Cartridge.ModelNo" "CX26176" "Cartridge.Name" "Radar Lock (1989) (Atari)" "" "Cartridge.MD5" "bb07f917611cde42b7d83746ee27147d" "Cartridge.Name" "Star Fire - Warping!! (13-04-2003) (MP)" "" "Cartridge.MD5" "bb18189021d58362d9e4d317cd2e28b7" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAG-001, PAG-001, EAG-001-04B, EAG-001-04I - 711 001-715" "Cartridge.Name" "Dragster (1980) (Activision) (PAL) (4K)" "Cartridge.Note" "AKA Dragster Rennen" "" "Cartridge.MD5" "bb5049e4558daade0f87fed69a244c59" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.ModelNo" "CX2649, CX2649P" "Cartridge.Name" "Asteroids (1981) (Atari) (PAL) [no copyright]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "bb579404924c40ca378b4aff6ccf302d" "Cartridge.Name" "Lightbulb Lightens, The (PD) (Non Functional)" "" "Cartridge.MD5" "bb6a5a2f7b67bee5d1f237f62f1e643f" "Cartridge.Name" "Demo Image Series #5 - Animegirl (19-02-2003) (AD)" "" "Cartridge.MD5" "bb745c893999b0efc96ea9029e3c62ca" "Cartridge.Manufacturer" "Play Video" "Cartridge.Name" "Planet Patrol (1982) (Play Video) (PAL)" "" "Cartridge.MD5" "bb756aa98b847dddc8fc170bc79f92b2" "Cartridge.Name" "Golf (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "bb9f06b288b5275bc0d38b6731b2526a" "Cartridge.Name" "Star Fire - Meteor Dance 2 (18-11-2002) (MP)" "" "Cartridge.MD5" "bbf8c7c9ed280151934aabe138e41ba7" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "1130" "Cartridge.Name" "Power Play Arcade Video Game Album V (1984) (Amiga) (Prototype)" "Cartridge.Note" "Mogul Maniac, Surf's Up, Off Your Rocker, S.A.C. Alert" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "bc3057a35319aae3a5cd87a203736abe" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-845" "Cartridge.Name" "Time Warp (1983) (CCE)" "" "Cartridge.MD5" "bc33c685e6ffced83abe7a43f30df7f9" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Seaquest (1983) (Dynacom)" "" "Cartridge.MD5" "bc4cf38a4bee45752dc466c98ed7ad09" "Cartridge.Manufacturer" "Atari, Douglas Neubauer, Mimi Nyden" "Cartridge.ModelNo" "CX26136" "Cartridge.Name" "Solaris (1986) (Atari) (PAL)" "Cartridge.Note" "AKA Universe, Star Raiders II, The Last Starfighter" "" "Cartridge.MD5" "bc526185ad324241782dc68ba5d0540b" "Cartridge.Name" "Dodge Demo 1 (PD)" "" "Cartridge.MD5" "bc5389839857612cfabeb810ba7effdc" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2671" "Cartridge.Name" "SwordQuest - WaterWorld (1983) (Atari)" "" "Cartridge.MD5" "bc6432cbed32c695658514c4eb41d905" "Cartridge.Manufacturer" "Manuel Polik" "Cartridge.Name" "Star Fire (MP) (2002) (PD)" "Cartridge.Note" "Won't work with Stella < V1.2" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "bc703ea6afb20bc089f04d8c9d79a2bd" "Cartridge.Name" "Gunfight 2600 - Not mergeable with Colbert wizardry... (2001) (MP)" "" "Cartridge.MD5" "bc97d544f1d4834cc72bcc92a37b8c1b" "Cartridge.Name" "Sky Demo (PD)" "" "Cartridge.MD5" "bcb31f22856b0028c00d12f0e4c0a952" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Thunderground (Canal 3)" "" "Cartridge.MD5" "bccb4e2cfad5efc93f6d55dc992118ce" "Cartridge.Manufacturer" "Activision, Carol Shaw" "Cartridge.ModelNo" "AX-020, AX-020-04" "Cartridge.Name" "River Raid (1982) (Activision) (8K)" "" "Cartridge.MD5" "bce4c291d0007f16997faa5c4db0a6b8" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "292.651 7" "Cartridge.Name" "Weltraumtunnel (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Innerspace" "" "Cartridge.MD5" "bce93984b920e9b56cf24064f740fe78" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Checkers (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "bcef7880828a391cf6b50d5a6dcef719" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-009" "Cartridge.Name" "Bermuda, The (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "bd1bd6f6b928df17a702def0302f46f4" "Cartridge.Name" "Binary To Decimal Routine (2001) (AD)" "" "Cartridge.MD5" "bd39598f067a1193ae81bd6182e756d1" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Night Stalker (1988) (Telegames) (PAL)" "Cartridge.Note" "AKA Dark Cavern" "" "Cartridge.MD5" "bd430c2193045c68d1a20a018a976248" "Cartridge.Name" "Pac Ghost Sprite Demo 2 (PD)" "" "Cartridge.MD5" "bda1463e02ae3a6e1107ffe1b572efd2" "Cartridge.Manufacturer" "Atari, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX26111" "Cartridge.Name" "Snoopy and the Red Baron (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "bdb4b584ddc90c9d2ec7e21632a236b6" "Cartridge.Manufacturer" "Atari Freak 1" "Cartridge.Name" "Nitemare at Sunshine Bowl-a-Rama (Atari Freak 1) (Hack)" "Cartridge.Note" "Hack of Pac-Man Jr." "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "bdbaeff1f7132358ea64c7be9e46c1ac" "Cartridge.Manufacturer" "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer" "Cartridge.ModelNo" "11105" "Cartridge.Name" "Mega Force (1982) (20th Century Fox) (PAL) [a]" "" "Cartridge.MD5" "bdc381baf7c252c63739c5e9ed087a5c" "Cartridge.Name" "Vertical Ship Demo 1 (PD)" "" "Cartridge.MD5" "bdecc81f740200780db04a107c3a1eba" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "874.254 6" "Cartridge.Name" "Super-Cowboy beim Rodeo (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Stampede" "" "Cartridge.MD5" "bdf1996e2dd64baf8eff5511811ca6ca" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "H.E.R.O. (Tron)" "" "Cartridge.MD5" "be060a704803446c02e6f039ab12eb91" "Cartridge.Manufacturer" "Parker Brothers, Rex Bradford, Sam Kjellman" "Cartridge.ModelNo" "931501" "Cartridge.Name" "Star Wars - The Empire Strikes Back (1982) (Parker Bros) (PAL)" "" "Cartridge.MD5" "be1922bd8e09d74da471287e1e968653" "Cartridge.Manufacturer" "Cropsy" "Cartridge.Name" "Hangman Pacman Demo (Cropsy) (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "be2870a0120fd28d25284e9ccdcbdc99" "Cartridge.Name" "Tomb Raider 2600 [REV 01] (Montezuma's Revenge Hack)" "" "Cartridge.MD5" "be35d8b37bbc03848a5f020662a99909" "Cartridge.Manufacturer" "Atari, Joe Decuir, Steve Mayer, Larry Wagner - Sears" "Cartridge.ModelNo" "CX2601 - 99801, 6-99801, 49-75124" "Cartridge.Name" "Combat (1977) (Atari) (4K) [a]" "" "Cartridge.MD5" "be3f0e827e2f748819dac2a22d6ac823" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (Puzzy)" "Cartridge.Note" "AKA Cosmic Corridor, Le Tunnel de L'Estace" "Display.YStart" "34" "Display.Height" "215" "" "Cartridge.MD5" "be41463cd918daef107d249f8cde3409" "Cartridge.Name" "Berzerk (Voice Enhanced) (Hack)" "Cartridge.Note" "Hack of Berzerk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "be561b286b6432cac71bccbae68002f7" "Cartridge.Name" "Counter Demo (PD)" "" "Cartridge.MD5" "be929419902e21bd7830a7a7d746195d" "Cartridge.Manufacturer" "Activision, Garry Kitchen" "Cartridge.ModelNo" "AX-025, AX-025-04" "Cartridge.Name" "Keystone Kapers (1983) (Activision)" "" "Cartridge.MD5" "becd908f9d7bb361982c3dc02d6475c6" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "THX-1138 (Kyle Pittman) (Hack)" "Cartridge.Note" "Hack of Berserk" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "bedfbde71fb606601f936b5b057f26f7" "Cartridge.Manufacturer" "Activision, Garry Kitchen - Ariola" "Cartridge.ModelNo" "EAX-025, EAX-025-04I - 711 025-725" "Cartridge.Name" "Keystone Kapers (1983) (Activision) (PAL) (16K)" "" "Cartridge.MD5" "befce0de2012b24fd6cb8b53c17c8271" "Cartridge.Name" "Push (V0.03) (No Illegal Opcodes) (1998) (AD)" "" "Cartridge.MD5" "bf52327c2197d9d2c4544be053caded1" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "AG-930-04, AZ-030" "Cartridge.Name" "Decathlon (HES) (PAL) (16K)" "" "Cartridge.MD5" "bf5e2079586cb307bf5eb2413e2e61af" "Cartridge.Name" "Star Fire - 1LK Intro (13-11-2002) (TJ)" "" "Cartridge.MD5" "bf84f528de44225dd733c0e6a8e400a0" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Demons to Diamonds (CCE)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 57" "" "Cartridge.MD5" "bf976cf80bcf52c5f164c1d45f2b316b" "Cartridge.Manufacturer" "Atari, Tod Frye, Mimi Nyden" "Cartridge.ModelNo" "CX2657" "Cartridge.Name" "SwordQuest - FireWorld (1982) (Atari) (PAL)" "Cartridge.Note" "AKA Adventure II, SwordQuest II - FireWorld" "" "Cartridge.MD5" "bf9ddc5dd9056633d4ac0dac8b871dfe" "Cartridge.Name" "Star Fire - Cockpit View (10-10-2002) (MP)" "" "Cartridge.MD5" "bfa58198c6b9cd8062ee76a2b38e9b33" "Cartridge.Name" "20 Sprites at Once Demo 4 (PD)" "" "Cartridge.MD5" "bfb73aabb2489316cd5882c3cd11d9f9" "Cartridge.Manufacturer" "AtariAge, Chris Walton & Thomas Jentzsch" "Cartridge.ModelNo" "165" "Cartridge.Name" "Star Castle Arcade (2014) (AtariAge)" "Cartridge.Rarity" "Homebrew" "Controller.Right" "SAVEKEY" "Display.YStart" "30" "Display.Phosphor" "YES" "" "Cartridge.MD5" "bfcabc6995ef42d0b6c06786993dc4d6" "Cartridge.Name" "Star Fire - Creating a Universe (09-09-2002) (MP)" "" "Cartridge.MD5" "bff8f8f53a8aeb1ee804004ccbb08313" "Cartridge.Name" "Droid Demo 22 (David Conrad Schweinsberg) (PD)" "" "Cartridge.MD5" "bffe34516aaa3cbf5d307eab382a7e95" "Cartridge.Name" "Euchre (Release Candidate) (PAL) (28-09-2002) (Erik Eid)" "" "Cartridge.MD5" "c00734a2233ef683d9b6e622ac97a5c8" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX26133" "Cartridge.Name" "A-Team, The (03-30-1984) (Atari) (Prototype)" "Cartridge.Note" "AKA Saboteur" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c00b65d1bae0aef6a1b5652c9c2156a1" "Cartridge.Manufacturer" "Atari, Joe Decuir - Sears" "Cartridge.ModelNo" "CX2621 - 99806, 6-99806, 49-75104" "Cartridge.Name" "Video Olympics (1977) (Atari) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXDR" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 60" "" "Cartridge.MD5" "c02e1afa0671e438fd526055c556d231" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "A-Team (Atari) (Prototype) (PAL60)" "Cartridge.Rarity" "Prototype" "Display.Format" "PAL60" "" "Cartridge.MD5" "c032c2bd7017fdfbba9a105ec50f800e" "Cartridge.Manufacturer" "Activision, Charlie Heath" "Cartridge.Name" "Thwocker (04-09-1984) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c033dc1d7b6fde41b9cadce9638909bb" "Cartridge.Name" "Skeleton (V1.1) (06-09-2002) (Eric Ball)" "" "Cartridge.MD5" "c0589bb73858924389077fa3c2e9441a" "Cartridge.Manufacturer" "SOLID Corp. (D. Scott Williamson)" "Cartridge.ModelNo" "CX2655-014" "Cartridge.Name" "Star Castle 2600 (SolidCorp) [014]" "Cartridge.Note" "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c05f367fa4767ceb27abadf0066df7f4" "Cartridge.Name" "TomInv (31-07-2001) (TJ)" "" "Cartridge.MD5" "c08d0cee43077d3055febb00e5745c1d" "Cartridge.Manufacturer" "HES - Activision" "Cartridge.Name" "Super Hit Pak - River Raid, Sky Jinks, Grand Prix, Fishing Derby, Checkers (HES) (PAL)" "" "Cartridge.MD5" "c0a68837c60e15d1fc5a40c9a62894bc" "Cartridge.Manufacturer" "Arcadia Corporation, Kevin Norman" "Cartridge.ModelNo" "7 AR-4103" "Cartridge.Name" "Killer Satellites (1983) (Arcadia) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c0d2434348de72fa6edcc6d8e40f28d7" "Cartridge.Manufacturer" "Sega - Beck-Tech, Steve Beck" "Cartridge.ModelNo" "010-01" "Cartridge.Name" "Tapper (1984) (Sega)" "Display.Height" "225" "" "Cartridge.MD5" "c118854d670289a8b5d5156aa74b0c49" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Skiing (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "c126656df6badfa519cc63e681fb3596" "Cartridge.Manufacturer" "Ron Corcoran" "Cartridge.Name" "Space Invaders (2002) (Ron Corcoran) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c150c76cbde2c9b5a97eb5399d46c64f" "Cartridge.Name" "Unknown Title (xxx00000 (200203)) (PD)" "" "Cartridge.MD5" "c16c79aad6272baffb8aae9a7fff0864" "Cartridge.Manufacturer" "U.S. Games Corporation - JWDA, Sylvia Day, Todd Marshall, Robin McDaniel, Henry Will IV" "Cartridge.ModelNo" "VC2001" "Cartridge.Name" "Gopher (1982) (U.S. Games)" "Cartridge.Note" "AKA Gopher Attack" "" "Cartridge.MD5" "c16fbfdbfdf5590cc8179e4b0f5f5aeb" "Cartridge.Name" "Wall Break (Unknown)" "" "Cartridge.MD5" "c17bdc7d14a36e10837d039f43ee5fa3" "Cartridge.Manufacturer" "Spectravision - Spectravideo" "Cartridge.ModelNo" "SA-203" "Cartridge.Name" "Cross Force (1982) (Spectravision)" "" "Cartridge.MD5" "c1a83f44137ea914b495fc6ac036c493" "Cartridge.Manufacturer" "Atari, Carla Meninsky" "Cartridge.ModelNo" "CX2660" "Cartridge.Name" "Star Raiders (1982) (Atari) (PAL)" "Cartridge.Note" "Uses Joystick (left) and Keypad (right) Controllers" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "c1b038ce5cb6d85e956c5509b0e0d0d8" "Cartridge.Name" "Rotating Colors Demo 2 (Junkosoft) (PD)" "" "Cartridge.MD5" "c1b1049b88bcd98437d8872d1d62ba31" "Cartridge.Name" "Demo Image Series #4 - Donald (19-02-2003) (AD)" "" "Cartridge.MD5" "c1b7aeabc3ec41556d924c8372a9ba5b" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.Name" "Dukes of Hazard (1980) (Atari) (Prototype)" "Cartridge.Note" "AKA Stunt Cycle" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c1cb228470a87beb5f36e90ac745da26" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AX-015, AX-015-04" "Cartridge.Name" "Chopper Command (1982) (Activision)" "" "Cartridge.MD5" "c1e6e4e7ef5f146388a090f1c469a2fa" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA283" "Cartridge.Name" "Z-Tack (1983) (Bomb)" "Cartridge.Note" "AKA Base Attack" "" "Cartridge.MD5" "c1f209d80f0624dada5866ce05dd3399" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Deadly Discs (1988) (Telegames) (PAL)" "Cartridge.Note" "AKA TRON - Deadly Discs" "" "Cartridge.MD5" "c1fdd44efda916414be3527a47752c75" "Cartridge.Manufacturer" "Parker Brothers, John Emerson" "Cartridge.ModelNo" "PB5920" "Cartridge.Name" "G.I. Joe - Cobra Strike (1983) (Parker Bros)" "Cartridge.Note" "Uses the Paddle (left) and Joystick (right) Controllers" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "c20f15282a1aa8724d70c117e5c9709e" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-02" "Cartridge.Name" "Surfer's Paradise (1983) (Video Gems) (PAL)" "" "Cartridge.MD5" "c21450c21efb7715746e9fa87ad6f145" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - It could've been soooo cool, but... (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "c216b91f5db21a093ded6a5aaec85709" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Dragster (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.YStart" "20" "" "Cartridge.MD5" "c221607529cabc93450ef25dbac6e8d2" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Color Test (26-09-2002) (Eckhard Stolberg)" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "" "Cartridge.MD5" "c225379e7c4fb6f886ef9c8c522275b4" "Cartridge.Manufacturer" "Video Mania" "Cartridge.Name" "Frostbite (1983) (Video Mania)" "" "Cartridge.MD5" "c225abfb584960efe1f359fc94b73379" "Cartridge.Name" "Joustpong (21-09-2002) (Kirk Israel) (PD)" "" "Cartridge.MD5" "c2410d03820e0ff0a449fa6170f51211" "Cartridge.Name" "Pac-Man (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c246e05b52f68ab2e9aee40f278cd158" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Star Wars - Ewok Adventure (Thomas Jentzsch) (Prototype)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.Height" "240" "" "Cartridge.MD5" "c2778507b83d9540e9be5713758ff945" "Cartridge.Name" "Island Flyer Demo 2 (PD)" "" "Cartridge.MD5" "c28b29764c2338b0cf95537cc9aad8c9" "Cartridge.Name" "Multi-Color Demo 4 (Bob Colbert) (PD)" "" "Cartridge.MD5" "c29d17eef6b0784db4586c12cb5fd454" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "River Raid (Jone Yuan) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c29f8db680990cb45ef7fef6ab57a2c2" "Cartridge.Manufacturer" "Parker Brothers, Mike Brodie - Roklan, Paul Crowley" "Cartridge.ModelNo" "PB5320" "Cartridge.Name" "Super Cobra (1983) (Parker Bros)" "" "Cartridge.MD5" "c2a37f1c7603c5fd97df47d6c562abfa" "Cartridge.Manufacturer" "Roger Williams" "Cartridge.Name" "Bar-Score Demo (2001) (Roger Williams)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "c2b5c50ccb59816867036d7cf730bf75" "Cartridge.Manufacturer" "Salu - Avantgarde Software, Michael Buetepage" "Cartridge.ModelNo" "460741" "Cartridge.Name" "Ghostbusters II (1992) (Salu) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c2bcd8f2378c3779067f3a551f662bb7" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAG-002, EAG-002-04I, PAG-002 - 711 002-715" "Cartridge.Name" "Boxing (1980) (Activision) (PAL) (4K)" "" "Cartridge.MD5" "c2c7a11717e255593e54d0acaf653ee5" "Cartridge.Name" "Chopper Command (208 in 1) (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c2fbef02b6eea37d8df3e91107f89950" "Cartridge.Manufacturer" "Champ Games" "Cartridge.ModelNo" "CG-02-N" "Cartridge.Name" "Conquest Of Mars (NTSC)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "c31a17942d162b80962cb1f7571cd1d5" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.ModelNo" "VCS83112" "Cartridge.Name" "Sky Alien (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Sky Aliem" "" "Cartridge.MD5" "c3205e3707f646e1a106e09c5c49c1bf" "Cartridge.Name" "Unknown Title (bin00003 (200206)) (PD)" "" "Cartridge.MD5" "c3472fa98c3b452fa2fd37d1c219fb6f" "Cartridge.Manufacturer" "Atari, Carla Meninsky - Sears" "Cartridge.ModelNo" "CX2637 - 49-75158" "Cartridge.Name" "Dodge 'Em (1980) (Atari) [a]" "" "Cartridge.MD5" "c370c3268ad95b3266d6e36ff23d1f0c" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2641, CX2641P" "Cartridge.Name" "Surround (1977) (Atari) (PAL)" "" "Cartridge.MD5" "c3a9550f6345f4c25b372c42dc865703" "Cartridge.Manufacturer" "Atari - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "CX2663" "Cartridge.Name" "Road Runner (1989) (Atari) (PAL)" "" "Cartridge.MD5" "c3aeb796fdaf9429e8cd6af6346f337e" "Cartridge.Name" "If It's Not One Thing It's Another (1997) (Chris Cracknell)" "" "Cartridge.MD5" "c3bbc673acf2701b5275e85d9372facf" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26157" "Cartridge.Name" "Stunt Cycle (07-21-1980) (Atari) (Prototype)" "" "Cartridge.MD5" "c3e4aa718f46291311f1cce53e6ccd79" "Cartridge.Name" "Hangman Ghost 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c3ef5c4653212088eda54dc91d787870" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-002, CAG-002, AG-002-04" "Cartridge.Name" "Boxing (1980) (Activision)" "" "Cartridge.MD5" "c3f53993ade534b0982ca3a286c85bb5" "Cartridge.Name" "Full Screen Bitmap Drawing System (12-02-2003) (AD)" "" "Cartridge.MD5" "c4060a31d61ba857e756430a0a15ed2e" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Pick 'n Pile (2003) (TJ)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.Height" "215" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c41e7735f6701dd50e84ee71d3ed1d8f" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Spider Fighter (1983) (Dynacom)" "" "Cartridge.MD5" "c43bd363e1f128e73ba5f0380b6fd7e3" "Cartridge.Manufacturer" "Atari, Chris Crawford" "Cartridge.Name" "Wizard (1980) (Atari) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c446288fe62c0c2737639fd788ae4a21" "Cartridge.Name" "Mark's Sound Demo (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c450a285daa7a3b65188c2c3cf04fb3e" "Cartridge.Manufacturer" "Wizard Video Games" "Cartridge.ModelNo" "007" "Cartridge.Name" "Halloween (1983) (Wizard Video Games) [a]" "" "Cartridge.MD5" "c469151655e333793472777052013f4f" "Cartridge.Name" "Base Attack (Unknown) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c471b97446a85304bbac021c57c2cb49" "Cartridge.Manufacturer" "First Star Software, Alex Leavens, Shirley Ann Russell" "Cartridge.Name" "Boing! (1983) (First Star Software) (PAL)" "Cartridge.Note" "AKA Bubbles, Soap Suds, The Emphysema Game" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c47244f5557ae12c61e8e01c140e2173" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Allred" "Cartridge.ModelNo" "CX2688, CX2688P" "Cartridge.Name" "Jungle Hunt (1983) (Atari) (PAL) [a1]" "" "Cartridge.MD5" "c473b222b7c5308d0773326416094272" "Cartridge.Name" "Star Fire (28-11-2002) (MP) [a1]" "" "Cartridge.MD5" "c47b7389e76974fd0de3f088fea35576" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Mighty Mouse (Funvision)" "Cartridge.Note" "AKA Gopher" "" "Cartridge.MD5" "c482f8eebd45e0b8d479d9b71dd72bb8" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Push (V0.03) (1998) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c49fe437800ad7fd9302f3a90a38fb7d" "Cartridge.Manufacturer" "Atari, Dan Hitchens, Mimi Nyden" "Cartridge.ModelNo" "CX2697, CX2697P" "Cartridge.Name" "Mario Bros. (1983) (Atari) (PAL)" "" "Cartridge.MD5" "c4b73c35bc2f54b66cd786f55b668a82" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (1982) (Arcadia) [a]" "" "Cartridge.MD5" "c4bbbb0c8fe203cbd3be2e318e55bcc0" "Cartridge.Name" "Atlantis (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c4bc8c2e130d76346ebf8eb544991b46" "Cartridge.Manufacturer" "Imagic" "Cartridge.Name" "Imagic Selector ROM (1982) (Imagic) [a]" "" "Cartridge.MD5" "c4d888bcf532e7c9c5fdeafbb145266a" "Cartridge.Name" "Space Robot (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c504a71c411a601d1fc3173369cfdca4" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.02) (Stella) (2001) (Retroactive)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c5124e7d7a8c768e5a18bde8b54aeb1d" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.ModelNo" "720104-2A, IA3204P, EIX-008-04I" "Cartridge.Name" "Cosmic Ark (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "c517144e3d3ac5c06f2f682ebf212dd7" "Cartridge.Manufacturer" "Tigervision - Teldec" "Cartridge.ModelNo" "7-008 - 3.60006 VG" "Cartridge.Name" "Miner 2049er (1983) (Tigervision) (PAL)" "" "Cartridge.MD5" "c529e63013698064149b9e0468afd941" "Cartridge.Name" "S.I.PLIX 2 (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "c52d9bbdc5530e1ef8e8ba7be692b01e" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26130" "Cartridge.Name" "Holey Moley (02-29-1984) (Atari) (Prototype)" "Cartridge.Note" "Uses Keypad Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "c5301f549d0722049bb0add6b10d1e09" "Cartridge.Manufacturer" "Atari, Carla Meninsky, Ed Riddle - Sears" "Cartridge.ModelNo" "CX2611 - 99821, 49-75149" "Cartridge.Name" "Indy 500 (1977) (Atari)" "Cartridge.Note" "Uses the Driving Controllers" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "Controller.MouseAxis" "45" "" "Cartridge.MD5" "c5387fc1aa71f11d2fa82459e189a5f0" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (BitCorp) (PAL)" "Cartridge.Note" "AKA Cosmic Corridor, Weltraum-Tunnel" "Display.Height" "256" "" "Cartridge.MD5" "c541a5f6fc23b40a211196dd78233780" "Cartridge.Manufacturer" "Atari, Carla Meninsky - Sears" "Cartridge.ModelNo" "CX2660 - 49-75187" "Cartridge.Name" "Star Raiders (1981) (Atari) (Prototype)" "Cartridge.Note" "Uses Joystick (left) and Keypad (right) Controllers" "Cartridge.Rarity" "Prototype" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "c54b4207ce1d4bf72fadbb1a805d4a39" "Cartridge.Manufacturer" "Billy Eno" "Cartridge.Name" "Sniper (Feb 30) (2001) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c569e57dca93d3bee115a49923057fd7" "Cartridge.Name" "Pac-Space (Pac-Man Hack)" "Display.YStart" "33" "" "Cartridge.MD5" "c58708c09ccb61625cda9d15ddcd8be6" "Cartridge.Manufacturer" "SPIKE the Percussionist" "Cartridge.Name" "NOIZ Invaders (SPIKE) (2002) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c5930d0e8cdae3e037349bfa08e871be" "Cartridge.Manufacturer" "Atari, Howard Scott Warshaw - Sears" "Cartridge.ModelNo" "CX2655 - 49-75167" "Cartridge.Name" "Yars' Revenge (1982) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c59633dbebd926c150fb6d30b0576405" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5861 A030" "Cartridge.Name" "Bogey Blaster (1988) (Telegames)" "Cartridge.Note" "AKA Air Raiders" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "c5a76bafc4676edb76e0126fb9f0fb2d" "Cartridge.Manufacturer" "Charles Morgan" "Cartridge.Name" "Zero Patrol (Charles Morgan) (Hack)" "Cartridge.Note" "Hack of Moon Patrol" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c5bab953ac13dbb2cba03cd0684fb125" "Cartridge.Manufacturer" "SpiceWare - Darrell Spice Jr." "Cartridge.Name" "Stay Frosty (SpiceWare)" "Cartridge.Note" "Part of Stella's Stocking 2007 Xmas compilation" "Cartridge.Rarity" "Homebrew" "Cartridge.Sound" "STEREO" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c5c7cc66febf2d4e743b4459de7ed868" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2696" "Cartridge.Name" "Asterix (1983) (Atari) (PAL) [a]" "Cartridge.Note" "AKA Taz" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "c5d2834bf98e90245e545573eb7e6bbc" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Snoopy and the Red Baron (CCE)" "" "Cartridge.MD5" "c5dd8399257d8862f3952be75c23e0eb" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680" "Cartridge.Name" "RealSports Tennis (1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c5fe45f2734afd47e27ca3b04a90213c" "Cartridge.Manufacturer" "Atari, Brad Stewart" "Cartridge.ModelNo" "CX2622, CX2622P" "Cartridge.Name" "Breakout (1978) (Atari) (PAL) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "c63a98ca404aa5ee9fcff1de488c3f43" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26145" "Cartridge.Name" "Venture (1987) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c6556e082aac04260596b4045bc122de" "Cartridge.Manufacturer" "Atari - GCC, Dave Payne" "Cartridge.ModelNo" "CX2669" "Cartridge.Name" "Vanguard (1983) (Atari)" "" "Cartridge.MD5" "c6688781f4ab844852f4e3352772289b" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2695" "Cartridge.Name" "Xevious (08-02-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c67ff409f28f44883bd5251cea79727d" "Cartridge.Name" "Gunfight 2600 - Music & Bugfixes 1 (2001) (MP)" "" "Cartridge.MD5" "c689148ad9275667924ab334107b517e" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Space Raid (Jone Yuan)" "Cartridge.Note" "AKA MegaMania" "" "Cartridge.MD5" "c68a6bafb667bad2f6d020f879be1d11" "Cartridge.Manufacturer" "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26110" "Cartridge.Name" "Crystal Castles (1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c6ae21caceaad734987cb24243793bd5" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Frostbite (CCE)" "" "Cartridge.MD5" "c6c63da3bc2e47291f63280e057061d0" "Cartridge.Manufacturer" "128-in-1 Junior Console" "Cartridge.Name" "Human Cannonball (128-in-1 Junior Console) (PAL) (4K)" "" "Cartridge.MD5" "c6cedb25b7d390b580ea8edb614b168b" "Cartridge.Name" "Star Fire - Radar Completed (22-10-2002) (MP)" "" "Cartridge.MD5" "c6d48c6ae6461e0e82753540a985ac9e" "Cartridge.Manufacturer" "Ed Federmeyer" "Cartridge.Name" "Edtris (1994) (Ed Federmeyer)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "c6d7fe7a46dc46f962fe8413c6f53fc9" "Cartridge.Manufacturer" "Parker Brothers, Mark Lesser" "Cartridge.ModelNo" "PB5950" "Cartridge.Name" "Lord of the Rings (1983) (Parker Bros) (Prototype) [a]" "Cartridge.Note" "Journey to Rivendell (The Lord of the Rings I)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c6db733e0b108c2580a1d65211f06dbf" "Cartridge.Manufacturer" "Atari, Eric Manghise, Mimi Nyden, Joseph Tung" "Cartridge.ModelNo" "CX2640" "Cartridge.Name" "RealSports Baseball (07-09-1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c738fc3f5aae1e8f86f7249f6c82ac81" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2622 - 6-99813, 49-75107" "Cartridge.Name" "Breakout (1978) (Atari) (16K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 60" "" "Cartridge.MD5" "c73ae5ba5a0a3f3ac77f0a9e14770e73" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "9 AR-4105" "Cartridge.Name" "Official Frogger, The (1983) (Starpath)" "Display.YStart" "30" "" "Cartridge.MD5" "c745487828a1a6a743488ecebc55ad44" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-002" "Cartridge.Name" "Galactic (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA The Challenge of.... Nexar" "" "Cartridge.MD5" "c74bfd02c7f1877bbe712c1da5c4c194" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "River Raid Tanks (Thomas Jentzsch) (Hack)" "Cartridge.Note" "Hack of River Raid" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "c7600d72247c5dfa1ec1a88d23e6c85e" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "13" "Cartridge.Name" "Sweat! - The Decathlon Game (1 of 3) (1983) (Arcadia) (Prototype)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Cartridge.Rarity" "Prototype" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "c77c35a6fc3c0f12bf9e8bae48cba54b" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Action Graphics, John Perkins, David Thiel" "Cartridge.ModelNo" "6230, 7210, 06004, 99004" "Cartridge.Name" "Artillery Duel (1983) (Xonox)" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "c77d3b47f2293e69419b92522c6f6647" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "101" "Cartridge.Name" "Tank Brigade (1983) (Panda)" "Cartridge.Note" "AKA Tanks But No Tanks" "" "Cartridge.MD5" "c7900a7fe95a47eef3b325072ad2c232" "Cartridge.Manufacturer" "Larry Petit" "Cartridge.Name" "Super Congo Bongo (2003) (Larry Petit) (Hack)" "Cartridge.Note" "Hack of Bongo" "Cartridge.Rarity" "Hack" "Display.YStart" "34" "" "Cartridge.MD5" "c7d5819b26b480a49eb26aeb63cc831e" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PGP210" "Cartridge.Name" "Ice Hockey (4 Game in One Light Green) (1983) (BitCorp) (PAL)" "Cartridge.Note" "AKA Hockey, Hockey" "" "Cartridge.MD5" "c7e43ad79c5e5c029d9f5ffde23e32cf" "Cartridge.Name" "PAL-NTSC Detector (15-11-2002) (CT)" "" "Cartridge.MD5" "c7eab66576696e11e3c11ffff92e13cc" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680, CX2680P" "Cartridge.Name" "RealSports Tennis (1983) (Atari) (PAL) [a2]" "" "Cartridge.MD5" "c7f13ef38f61ee2367ada94fdcc6d206" "Cartridge.Manufacturer" "Parker Brothers, Joe Gaucher" "Cartridge.ModelNo" "PB5370" "Cartridge.Name" "Popeye (1983) (Parker Bros)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c82ec00335cbb4b74494aecf31608fa1" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "E.T. - The Extra-Terrestrial (CCE)" "" "Cartridge.MD5" "c830f6ae7ee58bcc2a6712fb33e92d55" "Cartridge.Manufacturer" "Atari, Michael Kosaka, Carla Meninsky" "Cartridge.ModelNo" "CX2687" "Cartridge.Name" "Tempest (01-05-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "c866c995c0d2ca7d017fef0fc0c2e268" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.00) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c880c659cdc0f84c4a66bc818f89618e" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Open Sesame (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "Display.YStart" "20" "Display.Height" "254" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c8c7da12f087e8d16d3e6a21b371a5d3" "Cartridge.Name" "Demo Image Series #9 - Genius (28-02-2003) (AD)" "" "Cartridge.MD5" "c8fa5d69d9e555eb16068ef87b1c9c45" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26144" "Cartridge.Name" "Donkey Kong Junior (1987) (Atari)" "" "Cartridge.MD5" "c9196e28367e46f8a55e04c27743148f" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Stampede (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "c92cfa54b5d022637fdcbdc1ef640d82" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.05) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "c9b7afad3bfd922e006a6bfc1d4f3fe7" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2628 - 6-99842, 49-75117" "Cartridge.Name" "Bowling (1979) (Atari)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "c9c25fc536de9a7cdc5b9a916c459110" "Cartridge.Manufacturer" "Activision, Mike Lorenzen" "Cartridge.ModelNo" "AX-023" "Cartridge.Name" "Oink! (1983) (Activision)" "" "Cartridge.MD5" "c9d02d3cfeef8b48fb71cb4520a4aa84" "Cartridge.Name" "Euchre (More for less) (PAL) (22-08-2002) (Erik Eid)" "" "Cartridge.MD5" "c9e721eb29c940c2e743485b044c0a3f" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "c9f6e521a49a2d15dac56b6ddb3fb4c7" "Cartridge.Manufacturer" "Parker Brothers, Rex Bradford" "Cartridge.ModelNo" "PB5000" "Cartridge.Name" "Star Wars - Jedi Arena (1983) (Parker Bros)" "Cartridge.Note" "Uses the Paddle Controllers (swapped)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 50" "" "Cartridge.MD5" "ca09fa7406b7d2aea10d969b6fc90195" "Cartridge.Manufacturer" "Activision, Matthew L. Hubbard, Bob Whitehead" "Cartridge.ModelNo" "AX-024" "Cartridge.Name" "Dolphin (1983) (Activision)" "" "Cartridge.MD5" "ca4f8c5b4d6fb9d608bb96bc7ebd26c7" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Hal Finney, Glenn Hightower, Peter Kaminski - INTV" "Cartridge.ModelNo" "MT4317" "Cartridge.Name" "Adventures of TRON (1983) (M Network)" "Cartridge.Note" "AKA Tron Joystick" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "ca50cc4b21b0155255e066fcd6396331" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-031" "Cartridge.Name" "UFO Patrol (Suntek) (PAL)" "Cartridge.Note" "AKA X'Mission" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ca53fc8fd8b3c4a7df89ac86b222eba0" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-812" "Cartridge.Name" "Pac Man (1983) (CCE)" "" "Cartridge.MD5" "ca54de69f7cdf4d7996e86f347129892" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "201" "Cartridge.Name" "Philly Flasher (1982) (PlayAround)" "Cartridge.Note" "Uses the Paddle Controllers, AKA Beat 'Em & Eat 'Em" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 45" "" "Cartridge.MD5" "ca7aaebd861a9ef47967d31c5a6c4555" "Cartridge.Manufacturer" "Atari, Bob Whitehead" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Homerun (32 in 1) (1988) (Atari) (PAL)" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "ca7abc774a2fa95014688bc0849eee47" "Cartridge.Manufacturer" "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26110" "Cartridge.Name" "Crystal Castles (1984) (Atari) (PAL)" "" "Cartridge.MD5" "ca7f166a94eed1a349dec6d6a358bcad" "Cartridge.Manufacturer" "Activision, Alan Miller - Ariola" "Cartridge.ModelNo" "EAG-007, EAG-007-04I, PAG-007 - 711 007-720" "Cartridge.Name" "Tennis (1981) (Activision) (PAL) (4K)" "" "Cartridge.MD5" "cac9928a84e1001817b223f0cecaa3f2" "Cartridge.Manufacturer" "Amiga - Video Soft, Jerry Lawson, Dan McElroy" "Cartridge.Name" "3-D Genesis (1983) (Amiga) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cad982c9b45bc5eff34e4ea982d5f1ca" "Cartridge.Name" "Song (17-02-2003) (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cade123747426df69570a2bc871d3baf" "Cartridge.Manufacturer" "Gakken" "Cartridge.ModelNo" "011" "Cartridge.Name" "Marine Wars (1983) (Gakken) (PAL)" "" "Cartridge.MD5" "cae8f83c06831ec7bb6a3c07e98e9342" "Cartridge.Manufacturer" "Colin Hughes" "Cartridge.Name" "Tetris 2600 (Colin Hughes) [o1]" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cb18d8d5fbdcb1cd7bd36c5423348859" "Cartridge.Name" "RAM-Pong (NTSC) v1.0" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "cb24210dc86d92df97b38cf2a51782da" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-01" "Cartridge.Name" "Missile Control (1983) (Video Gems) (PAL)" "" "Cartridge.MD5" "cb4a7b507372c24f8b9390d22d54a918" "Cartridge.Manufacturer" "ITT Family Games" "Cartridge.ModelNo" "554-37 338" "Cartridge.Name" "Peter Penguin (1983) (ITT Family Games) (PAL)" "Cartridge.Note" "AKA Frisco (Pumuckl-Serie)" "" "Cartridge.MD5" "cb8399dc0d409ff1f531ef86b3b34953" "Cartridge.Name" "Demo Image Series #12 - Luigi And Mario (01-03-2003) (AD)" "" "Cartridge.MD5" "cb9626517b440f099c0b6b27ca65142c" "Cartridge.Manufacturer" "Atari, Larry Kaplan - Sears" "Cartridge.ModelNo" "CX2664 - 6-99818" "Cartridge.Name" "Brain Games (1978) (Atari) (4K)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "cb96b0cf90ab7777a2f6f05e8ad3f694" "Cartridge.Manufacturer" "Silvio Mogno" "Cartridge.Name" "Rainbow Invaders" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "cb9b2e9806a7fbab3d819cfe15f0f05a" "Cartridge.Manufacturer" "Parker Brothers - JWDA, Todd Marshall, Robin McDaniel, Ray Miller" "Cartridge.ModelNo" "931513" "Cartridge.Name" "Star Wars - Death Star Battle (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "cba56e939252b05df7b7de87307d12ca" "Cartridge.Name" "Playfield Text Demo (2001) (Roger Williams)" "" "Cartridge.MD5" "cbad928e10aeee848786cc55394fb692" "Cartridge.Name" "Fu Kung! (V0.06a Cuttle Cart Compatible) (15-01-2003) (AD)" "" "Cartridge.MD5" "cbb0ee17c1308148823cc6da85bff25c" "Cartridge.Name" "Rotating Colors Demo 1 (Junkosoft) (PD)" "" "Cartridge.MD5" "cbc373fbcb1653b4c56bfabba33ea50d" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Voleyball (CCE)" "Cartridge.Note" "AKA RealSports Volleyball" "" "Cartridge.MD5" "cbced209dd0575a27212d3eee6aee3bc" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2003" "Cartridge.Name" "Racquetball (1982) (Apollo) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cbd981a23c592fb9ab979223bb368cd5" "Cartridge.Manufacturer" "Atari, Carla Meninsky - Sears" "Cartridge.ModelNo" "CX2660 - 49-75187" "Cartridge.Name" "Star Raiders (1982) (Atari)" "Cartridge.Note" "Uses Joystick (left) and Keypad (right) Controllers" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "cbe5a166550a8129a5e6d374901dffad" "Cartridge.Manufacturer" "Atari, Carla Meninsky - Sears" "Cartridge.ModelNo" "CX2610 - 49-75127" "Cartridge.Name" "Warlords (1981) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "AUTO 50" "" "Cartridge.MD5" "cbeafd37f15e0dddb0540dbe15c545a4" "Cartridge.Name" "Black and White Fast Scolling Demo (PD)" "" "Cartridge.MD5" "cc03c68b8348b62331964d7a3dbec381" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Marauder (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "cc12581e079cd18330a89902625b8347" "Cartridge.Manufacturer" "Dave Neuman" "Cartridge.Name" "Space Battle (PAL)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "cc1939e4769d0c157ace326efcfdcf80" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (3 of 4) (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "cc2973680c150886cce1ed8693c3aca2" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "874.254 6" "Cartridge.Name" "Super-Cowboy beim Rodeo (1983) (Quelle) (PAL) (4K)" "Cartridge.Note" "AKA Stampede" "" "Cartridge.MD5" "cc3d942c6958bd16b1c602623f59e6e1" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel" "Cartridge.ModelNo" "CX26114" "Cartridge.Name" "Pigs in Space (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "cc7138202cd8f6776212ebfc3a820ecc" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams" "Cartridge.ModelNo" "CX26101" "Cartridge.Name" "Oscar's Trash Race (03-30-1983) (Atari) (Prototype)" "Cartridge.Note" "Uses the Keypad Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "cc724ebe74a109e39c0b2784ddc980ca" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Dave Staugas" "Cartridge.ModelNo" "CX2682" "Cartridge.Name" "Krull (05-27-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "cc74ddb45d7bc4d04c2e6f1907416699" "Cartridge.Name" "Colour Display Programme (1997) (Chris Cracknell)" "" "Cartridge.MD5" "cca33ae30a58f39e3fc5d80f94dc0362" "Cartridge.Name" "Okie Dokie (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ccb56107ff0492232065b85493daa635" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG206 [demonstration cartridge]" "Cartridge.Name" "Bobby Is Going Home (1983) (BitCorp) (PAL) [demo cart]" "Cartridge.Note" "AKA Bobby geht Heim" "Display.YStart" "42" "" "Cartridge.MD5" "ccb5fa954fb76f09caae9a8c66462190" "Cartridge.Manufacturer" "Answer Software Corporation - TY Associates" "Cartridge.ModelNo" "ASC1001" "Cartridge.Name" "Malagai (1983) (Answer Software)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ccb807eb79b0ed0f5fdc460445ef703a" "Cartridge.Name" "Superman (Stunt_Cycle_Rules!) (Hack)" "Cartridge.Note" "Hack of Superman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "ccbd36746ed4525821a8083b0d6d2c2c" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2649, 49-75163" "Cartridge.Name" "Asteroids (1981) (Atari) [no copyright]" "Cartridge.Rarity" "Common" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cccfe9e9a11b1dad04beba46eefb7351" "Cartridge.Name" "Poker Squares (V0.25) (PAL) (2001) (B. Watson)" "" "Cartridge.MD5" "ccd6ce508eee4b3fca67212833edcd85" "Cartridge.Manufacturer" "Otto Versand" "Cartridge.ModelNo" "746422" "Cartridge.Name" "Hot Wave (Double-Game Package) (1983) (Otto Versand) (PAL)" "Cartridge.Note" "AKA Ram It" "" "Cartridge.MD5" "cd032ab6764b55438a7b0bfb5e78595a" "Cartridge.Name" "Hangman Pac-Man 4letter (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "cd139ae6d09f3665ad09eb79da3f9e49" "Cartridge.Manufacturer" "Eric Mooney" "Cartridge.Name" "Invaders by Erik Mooney (4-24-97) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "cd34b3b3ef9e485201e841ba71beb253" "Cartridge.Manufacturer" "Bradford W. Mott" "Cartridge.Name" "Hit HMOVE At Various Cycles After WSYNC Test (Bradford W. Mott) (1998) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "cd38ad19f51b1048d8e5e99c86a2a655" "Cartridge.Name" "Demo Image Series #5 - Flag (19-02-2003) (AD)" "" "Cartridge.MD5" "cd399bc422992a361ba932cc50f48b65" "Cartridge.Manufacturer" "Arcadia Corporation, Brian McGhie" "Cartridge.ModelNo" "AR-4104" "Cartridge.Name" "Rabbit Transit (Preview) (1983) (Arcadia)" "" "Cartridge.MD5" "cd3e26786136a4692fd2cb2dfbc1927e" "Cartridge.Name" "Multiple Moving Objects Demo 2 (B. Watson)" "" "Cartridge.MD5" "cd4423bd9f0763409bae9111f888f7c2" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "River Raid (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "cd4ded1ede63c4dd09f3dd01bda7458c" "Cartridge.Manufacturer" "Future Video Games" "Cartridge.Name" "Laser Gate (Future Video Games) (PAL)" "Cartridge.Note" "AKA Innerspace" "" "Cartridge.MD5" "cd568d6acb2f14477ebf7e59fb382292" "Cartridge.Manufacturer" "Videospielkassette - Ariola" "Cartridge.ModelNo" "PGP235" "Cartridge.Name" "Fussball (Ariola) (PAL)" "Cartridge.Note" "AKA International Soccer" "" "Cartridge.MD5" "cd5af682685cfecbc25a983e16b9d833" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX26133" "Cartridge.Name" "A-Team, The (05-08-1984) (Atari) (Prototype)" "Cartridge.Note" "AKA Saboteur" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "cd88ef1736497288c4533bcca339f881" "Cartridge.Manufacturer" "Sega - Teldec" "Cartridge.ModelNo" "005-10" "Cartridge.Name" "Buck Rogers - Planet of Zoom (1983) (Sega) (PAL)" "Display.Format" "PAL" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cd8fa2e9f6255ef3d3b9b5a4f24a54f7" "Cartridge.Name" "Daredevil (V2) (Stunt_Cycle_Rules!) (PD)" "Display.Height" "220" "" "Cartridge.MD5" "cd98be8a48ebf610c9609a688b9c57f2" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen H. Landrum" "Cartridge.ModelNo" "4 AR-4102" "Cartridge.Name" "Suicide Mission (1982) (Arcadia) (Prototype)" "Cartridge.Note" "AKA Meteoroids" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cd9fea12051e414a6dfe17052067da8e" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Marble Craze Demo (PD)" "Cartridge.Rarity" "New Release" "Display.YStart" "30" "" "Cartridge.MD5" "cda38714267978b9a8b0b24bee3529ae" "Cartridge.Name" "Space Instigators (V1.6) (17-10-2002) (CT)" "" "Cartridge.MD5" "cdb81bf33d830ee4ee0606ee99e84dba" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "AR-4300" "Cartridge.Name" "Fireball (1982) (Arcadia) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "cdc1a5c61d7488eadc9aba36166b253d" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.12) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cddabfd68363a76cd30bee4e8094c646" "Cartridge.Manufacturer" "Computer Magic - CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-001" "Cartridge.Name" "MagiCard (1981) (CommaVid)" "Cartridge.Note" "Uses the Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "ce17325834bf8b0a0d0d8de08478d436" "Cartridge.Name" "Boring Freeway (Hack)" "Cartridge.Note" "Hack of Freeway" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "ce243747bf34a2de366f846b3f4ca772" "Cartridge.Manufacturer" "Home Vision - Gem International Corp. - VDI" "Cartridge.Name" "Jacky Jump (1983) (Home Vision) (PAL)" "Cartridge.Note" "AKA Bobby Is Going Home" "Display.Height" "256" "" "Cartridge.MD5" "ce4bbe11d682c15a490ae15a4a8716cf" "Cartridge.Name" "Okie Dokie (Older) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ce5cc62608be2cd3ed8abd844efb8919" "Cartridge.Manufacturer" "Atari - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "CX2663" "Cartridge.Name" "Road Runner (1989) (Atari)" "" "Cartridge.MD5" "ce64812eb83c95723b04fb56d816910b" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.04) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ce6c4270f605ad3ce5e82678b0fc71f8" "Cartridge.Name" "Vertical Rainbow Demo (PD)" "" "Cartridge.MD5" "ce82a675c773ff21e0ffc0a4d1c90a71" "Cartridge.Name" "Defender 2 (Genesis)" "Cartridge.Note" "Genesis controller (C is smartbomb)" "Cartridge.Rarity" "Hack of Defender 2" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "ce8467ae2a3a5bc88ca72a2ce44ce28c" "Cartridge.Manufacturer" "SOLID Corp. (D. Scott Williamson)" "Cartridge.ModelNo" "CX2655-015" "Cartridge.Name" "Star Castle 2600 (SolidCorp) (PAL) [015]" "Cartridge.Note" "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ce89529d6e98a13ddf3d84827bbdfe68" "Cartridge.Name" "Kung Fu Sprite Demo 2 (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ce904c0ae58d36d085cd506989116b0b" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "5687 A279" "Cartridge.Name" "International Soccer (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "cea9f72036dc6f7af5eff52459066290" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.07) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cedbd67d1ff321c996051eec843f8716" "Cartridge.Manufacturer" "Ultravision" "Cartridge.ModelNo" "1044" "Cartridge.Name" "Karate (1982) (Ultravision)" "" "Cartridge.MD5" "cef01595000627ee50863d4290372c27" "Cartridge.Name" "Many Blue Bars and Text Demo (PD)" "" "Cartridge.MD5" "cef2287d5fd80216b2200fb2ef1adfa8" "Cartridge.Manufacturer" "Milton Bradley Company" "Cartridge.ModelNo" "4363" "Cartridge.Name" "Spitfire Attack (1983) (Milton Bradley)" "Cartridge.Note" "AKA Flight Commander)" "" "Cartridge.MD5" "cf0c593c563c84fdaf0f741adb367445" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.05) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cf3a9ada2692bb42f81192897752b912" "Cartridge.Name" "Air Raiders (Unknown) (PAL)" "" "Cartridge.MD5" "cf3c2725f736d4bcb84ad6f42de62a41" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-009" "Cartridge.Name" "Bermuda, The (Rainbow Vision) (PAL) [a]" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "cf507910d6e74568a68ac949537bccf9" "Cartridge.Manufacturer" "Sega, Jeff Lorenz" "Cartridge.ModelNo" "003-01" "Cartridge.Name" "Thunderground (1983) (Sega)" "Cartridge.Note" "AKA Underground" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cf63ffac9da89ef09c6c973083061a47" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-859" "Cartridge.Name" "MASH (1983) (CCE)" "Cartridge.Note" "AKA M.A.S.H" "" "Cartridge.MD5" "cf9069f92a43f719974ee712c50cd932" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-04" "Cartridge.Name" "Mission Survive (1983) (Video Gems) (PAL)" "Console.RightDifficulty" "A" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cfad2b9ca8b8fec7fb1611d656cc765b" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG207" "Cartridge.Name" "Mission 3,000 A.D. (1983) (BitCorp) (PAL) [demo cart]" "Cartridge.Note" "demonstration cartridge" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cfb3260c603b0341d49ddfc94051ec10" "Cartridge.Manufacturer" "Dactari - Milmar" "Cartridge.Name" "Boxing (Dactari - Milmar)" "" "Cartridge.MD5" "cfb83a3b0513acaf8be4cae1512281dc" "Cartridge.Manufacturer" "Starpath Corporation" "Cartridge.Name" "Going-Up (1983) (Starpath) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "cfc226d04d7490b69e155abd7741e98c" "Cartridge.Manufacturer" "Atari, Matthew L. Hubbard" "Cartridge.ModelNo" "CX26159" "Cartridge.Name" "Double Dunk (1989) (Atari) (PAL)" "Cartridge.Note" "AKA Super Basketball" "" "Cartridge.MD5" "cfce5596a7e8ca13529e9804cad693ef" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Tennis (Canal 3) (4K)" "" "Cartridge.MD5" "cfd6a8b23d12b0462baf6a05ef347cd8" "Cartridge.Manufacturer" "Activision, Larry Kaplan" "Cartridge.ModelNo" "AX-006" "Cartridge.Name" "Bridge (1980) (Activision)" "" "Cartridge.MD5" "cfdb4d0427a1ea8085c6bc6eb90259d8" "Cartridge.Name" "Gunfight 2600 - Release Candidate (2001) (MP)" "" "Cartridge.MD5" "cfe2185f84ce8501933beb5c5e1fd053" "Cartridge.Name" "Football (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "cfe62ed7125ff9fae99b4c8a367c0399" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-026, AX-026-04" "Cartridge.Name" "Enduro (1983) (Activision) (16K)" "" "Cartridge.MD5" "cfee10bd7119f10b136921ced2ee8972" "Cartridge.Name" "Space Instigators (V1.8) (19-10-2002) (CT)" "" "Cartridge.MD5" "cfef1a2d1f6a5ee7a5e1f43f3056f112" "Cartridge.Name" "Skeleton+ (05-05-2003) (Eric Ball) (NTSC)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "cff1e9170bdbc29859b815203edf18fa" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Push (V0.01) (1998) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cff578e5c60de8caecbee7f2c9bbb57b" "Cartridge.Manufacturer" "George Veeder" "Cartridge.Name" "Suicide Adventure (George Veeder) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "cff9950d4e650094f65f40d179a9882d" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Mr. Roboto (Paul Slocum) (Hack)" "Cartridge.Note" "Hack of Berzerk" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "cfffc4b97d01cc3e7b9f47575f7b11ec" "Cartridge.Manufacturer" "Xonox - K-Tel Software, Anthony R. Henderson" "Cartridge.ModelNo" "99007, 6240" "Cartridge.Name" "Tomarc the Barbarian (1983) (Xonox) (PAL60)" "Cartridge.Note" "Genesis controller (B is jump and throw, C switches between players)" "Cartridge.Rarity" "Hack of Tomarc the Barbarian" "Controller.Left" "GENESIS" "Display.Format" "PAL60" "" "Cartridge.MD5" "d00f6f8ba89559e4b20972a478fc0370" "Cartridge.Manufacturer" "Spiceware" "Cartridge.ModelNo" "SW-01" "Cartridge.Name" "Medieval Mayhem (PAL)" "Cartridge.Rarity" "Homebrew" "Cartridge.Sound" "STEREO" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "AUTO 55" "" "Cartridge.MD5" "d010e3dfe7366e47561c088079a59439" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.10) (Stella) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d026716b3c5be2c951cc4c064317c524" "Cartridge.Name" "Fu Kung! (V0.06) (14-01-2003) (AD)" "" "Cartridge.MD5" "d0498baca989e792db4b8270a02b9624" "Cartridge.Name" "Pac Ghost Sprite Demo (PD)" "" "Cartridge.MD5" "d071d2ec86b9d52b585cc0382480b351" "Cartridge.Manufacturer" "UA Limited" "Cartridge.Name" "Cat Trax (1983) (UA Limited) (1) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d078674afdf24a4547b4b32890fdc614" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Laser Blast (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "d078d25873c5b99f78fa267245a2af02" "Cartridge.Manufacturer" "Sega - Beck-Tech, Steve Beck, Phat Ho" "Cartridge.ModelNo" "006-01" "Cartridge.Name" "Congo Bongo (1983) (Sega) [a]" "Display.YStart" "26" "Display.Height" "220" "" "Cartridge.MD5" "d08fccfbebaa531c4a4fa7359393a0a9" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.Name" "Venetian Blinds Demo (1982) (Activision)" "" "Cartridge.MD5" "d090836f0a4ea8db9ac7abb7d6adf61e" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Yahtzee (Hozer Video Games)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d09935802d6760ae58253685ff649268" "Cartridge.Manufacturer" "Telesys, Don Ruffcorn" "Cartridge.ModelNo" "1006" "Cartridge.Name" "Demolition Herby (1983) (Telesys)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d09a7504ee8c8717ac3e24d263e7814d" "Cartridge.Manufacturer" "Activision, Matthew L. Hubbard, Bob Whitehead" "Cartridge.ModelNo" "AX-024" "Cartridge.Name" "Dolphin (1983) (Activision) (16K)" "" "Cartridge.MD5" "d09f1830fb316515b90694c45728d702" "Cartridge.Manufacturer" "Imagic, Brad Stewart" "Cartridge.ModelNo" "720105-1A, IA3400" "Cartridge.Name" "Fire Fighter (1982) (Imagic)" "" "Cartridge.MD5" "d0a379946ed77b1b126230ca68461333" "Cartridge.Manufacturer" "Ataripoll" "Cartridge.Name" "Atari Invaders (Ataripoll) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d0af33865512e9b6900714c26db5fa23" "Cartridge.Manufacturer" "Telegames" "Cartridge.Name" "Armor Ambush (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "d0b26e908370683ad99bc6b52137a784" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Larry Minor, Ernie Runyon, Ed Salvo - RCA Video Jeux" "Cartridge.ModelNo" "AP-2004" "Cartridge.Name" "Lost Luggage (1982) (Apollo) (PAL)" "Cartridge.Note" "AKA La valise piegee" "" "Cartridge.MD5" "d0b9df57bfea66378c0418ec68cfe37f" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius, Grady Ward" "Cartridge.ModelNo" "11002" "Cartridge.Name" "Beany Bopper (1982) (20th Century Fox)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "d0b9f705aa5f61f47a748a66009ae2d2" "Cartridge.Name" "Synthcart (14-01-2002) (Paul Slocum)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d0cb28e1b7bd6c7f683a0917b59f707e" "Cartridge.Manufacturer" "Atari, Gary Palmer" "Cartridge.ModelNo" "CX2661P" "Cartridge.Name" "Fun with Numbers (1980) (Atari) (PAL) (4K)" "Cartridge.Note" "AKA Basic Math" "" "Cartridge.MD5" "d0cdafcb000b9ae04ac465f17788ad11" "Cartridge.Manufacturer" "Quelle - Otto Versand" "Cartridge.ModelNo" "732.273 8 - 600273, 781644" "Cartridge.Name" "Lilly Adventure (1983) (Quelle) (PAL)" "" "Cartridge.MD5" "d0e15a3ce322c5af60f07343594392af" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.ModelNo" "3125" "Cartridge.Name" "Surf's Up (1983) (Amiga) (Prototype) (4K)" "Cartridge.Note" "Uses the Joyboard controller" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d0e9beb2347595c6c7d158e9d83d2da8" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.00) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d100b11be34a1e5b7832b1b53f711497" "Cartridge.Name" "Robotfindskitten2600 (26-04-2003) (Jeremy Penner) [a2]" "" "Cartridge.MD5" "d170317ae4c7d997a989c7d6567c2840" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Stampede (Jone Yuan) (4K) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d175258b2973b917a05b46df4e1cf15d" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-032" "Cartridge.Name" "Walker (Suntek) (PAL) [a]" "Display.Height" "230" "" "Cartridge.MD5" "d17a671029b1532b197defca5f3649a7" "Cartridge.Manufacturer" "Hozer Video Games" "Cartridge.Name" "Gunfight 2600 - Limit broken again! (2001) (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "d17a8c440d6be79fae393a4b46661164" "Cartridge.Name" "Warring Worms (Beta 3) (2002) (Billy Eno)" "" "Cartridge.MD5" "d1a1841b7f2007a24439ac248374630a" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (1 of 4) (1982) (Arcadia)" "" "Cartridge.MD5" "d1a9478b99d6a55e13a9fd4262da7cd4" "Cartridge.Manufacturer" "U.S. Games Corporation, Garry Kitchen - Vidtec" "Cartridge.ModelNo" "VC1001" "Cartridge.Name" "Space Jockey (1982) (U.S. Games) (4K)" "" "Cartridge.MD5" "d1b4075925e8d3031a7616d2f02fdd1f" "Cartridge.Name" "Demo Image Series #7 - Two Marios (27-02-2003) (AD)" "" "Cartridge.MD5" "d1c3520b57c348bc21d543699bc88e7e" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-002" "Cartridge.Name" "Warplock (1983) (Gameworld) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d1d704a7146e95709b57b6d4cac3f788" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Slot Racers (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "d20e61c86ed729780feca162166912ca" "Cartridge.Manufacturer" "Supergame" "Cartridge.ModelNo" "32" "Cartridge.Name" "Pitfall (1984) (Supergame)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "d223bc6f13358642f02ddacfaf4a90c9" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-003" "Cartridge.Name" "Pac-Kong (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Spider Kong" "" "Cartridge.MD5" "d245e2f27c84016041e9496b66b722fe" "Cartridge.Name" "Gunfight 2600 - The Final Kernel (MP)" "" "Cartridge.MD5" "d25018349c544320bf3fd5092ee072bc" "Cartridge.Manufacturer" "Activision, Larry Miller" "Cartridge.ModelNo" "AX-021" "Cartridge.Name" "Spider Fighter (1983) (Activision) (8K)" "Display.YStart" "30" "" "Cartridge.MD5" "d28afe0517a046265c418181fa9dd9a1" "Cartridge.Name" "Dodge 'Em (Unknown) (PAL)" "" "Cartridge.MD5" "d2901c34bb6496bb96c7bc78a9e6142a" "Cartridge.Manufacturer" "Greg Zumwalt" "Cartridge.Name" "Fish Revenge (2003) (Greg Zumwalt) (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d2c305a443dfc49e8430964d7c1bd1b7" "Cartridge.Name" "Star Fire - Advice on radar needed (16-10-2002) (MP)" "" "Cartridge.MD5" "d2c4f8a4a98a905a9deef3ba7380ed64" "Cartridge.Manufacturer" "Mythicon, Bill Bryner, Bruce de Graaf" "Cartridge.ModelNo" "MA1001" "Cartridge.Name" "Sorcerer (1983) (Mythicon)" "" "Cartridge.MD5" "d2c8e6aa8172b16c8aa9aae739ac9c5e" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "08-08-1980" "Cartridge.Name" "Laser Blast (08-08-1980) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d2c957dd7746521b51bb09fde25c5774" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Cubis (6K) (1997) (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "d2d8c4f1ea7f347c8bcc7d24f45aa338" "Cartridge.Name" "20 Sprites at Once Demo 5 (PD)" "" "Cartridge.MD5" "d2deddb77c8b823e4be9c57cb3c69adc" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.ModelNo" "C 3007" "Cartridge.Name" "Snoopy and the Red Baron (Canal 3)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d2f713c78a9ebba9da6d10aeefc6f20f" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Enduro (Digivision) [a]" "" "Cartridge.MD5" "d3171407c3a8bb401a3a62eb578f48fb" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "GN-080" "Cartridge.Name" "Spinning Fireball (1983) (ZiMAG) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d326db524d93fa2897ab69c42d6fb698" "Cartridge.Manufacturer" "Parker Brothers, Mike Brodie - Roklan, Paul Crowley" "Cartridge.ModelNo" "931505" "Cartridge.Name" "Super Cobra (1983) (Parker Bros) (PAL)" "" "Cartridge.MD5" "d339b95f273f8c3550dc4daa67a4aa94" "Cartridge.Name" "Laser Blast (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "d341d39774277cee6a1d378a013f92ac" "Cartridge.Manufacturer" "Xonox, John Perkins" "Cartridge.ModelNo" "6230, 7210, 06004, 99004" "Cartridge.Name" "Artillery Duel (1983) (Xonox) (PAL) [a]" "Display.YStart" "20" "" "Cartridge.MD5" "d3423d7600879174c038f53e5ebbf9d3" "Cartridge.Manufacturer" "U.S. Games Corporation - Western Technologies" "Cartridge.ModelNo" "VC2005" "Cartridge.Name" "Piece o' Cake (1983) (U.S. Games)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 60" "" "Cartridge.MD5" "d3456b4cf1bd1a7b8fb907af1a80ee15" "Cartridge.Manufacturer" "Avalon Hill, Duncan Scott" "Cartridge.ModelNo" "5003002" "Cartridge.Name" "Wall Ball (1983) (Avalon Hill)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d34b933660e29c0a0a04004f15d7e160" "Cartridge.Name" "Multi-Color Demo 5 (Bob Colbert) (PD)" "" "Cartridge.MD5" "d36308387241e98f813646f346e7f9f7" "Cartridge.Manufacturer" "King Atari" "Cartridge.Name" "Ghostbuster 2 (King Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d39e29b03af3c28641084dd1528aae05" "Cartridge.Manufacturer" "Funvision - Fund. Int'l Co." "Cartridge.Name" "Spider Monster (1982) (Funvision) (PAL)" "Cartridge.Note" "AKA Spider Kong" "" "Cartridge.MD5" "d3bb42228a6cd452c111c1932503cc03" "Cartridge.Manufacturer" "UA Limited" "Cartridge.Name" "Funky Fish (1983) (UA Limited) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d44d90e7c389165f5034b5844077777f" "Cartridge.Manufacturer" "Parker Brothers, Larry Gelberg" "Cartridge.ModelNo" "PB5065" "Cartridge.Name" "Star Wars - Ewok Adventure (1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.YStart" "30" "" "Cartridge.MD5" "d45bf71871b196022829aa3b96bfcfd4" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-017, AX-017-04" "Cartridge.Name" "MegaMania (1982) (Activision) (8K)" "" "Cartridge.MD5" "d45ebf130ed9070ea8ebd56176e48a38" "Cartridge.Manufacturer" "Sega, Jeff Lorenz" "Cartridge.ModelNo" "001-01" "Cartridge.Name" "Tac-Scan (1983) (Sega)" "Cartridge.Note" "Uses the Paddle Controllers (right only)" "Console.SwapPorts" "YES" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "AUTO 60" "Display.YStart" "31" "Display.Height" "215" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d47387658ed450db77c3f189b969cc00" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "206" "Cartridge.Name" "Westward Ho (1982) (PlayAround) (PAL)" "Cartridge.Note" "AKA Custer's Revenge" "" "Cartridge.MD5" "d4806775693fcaaa24cf00fc00edcdf3" "Cartridge.Manufacturer" "Atari - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "CX26140, CX26140P" "Cartridge.Name" "Desert Falcon (1987) (Atari) (PAL)" "Cartridge.Note" "AKA Nile Flyer, Sphinx" "Display.Format" "PAL" "" "Cartridge.MD5" "d483f65468d9a265661917bae1a54f3e" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 3 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "d4942f4b55313ff269488527d84ce35c" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Glenn Parker" "Cartridge.ModelNo" "CX2675, CX2675P" "Cartridge.Name" "Ms. Pac-Man (1982) (Atari) (PAL) [a]" "" "Cartridge.MD5" "d49aff83f77a1b9041ad7185df3c2277" "Cartridge.Name" "Space Treat (60% complete) (PD)" "" "Cartridge.MD5" "d4aa89e96d2902692f5c45f36903d336" "Cartridge.Name" "Euchre (NTSC) (Erik Eid) (PD)" "" "Cartridge.MD5" "d4c590ccfb611a73b3331359700c01a3" "Cartridge.Name" "Sprite Movement Demo 2 (2001) (Roger Williams)" "" "Cartridge.MD5" "d541b20eae221a8ee321375e5971e766" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (Preview) (1982) (Arcadia)" "" "Cartridge.MD5" "d54cd41ecfd59e4b72d2c086152b9a75" "Cartridge.Manufacturer" "Amiga" "Cartridge.ModelNo" "1110" "Cartridge.Name" "Power Play Arcade Video Game Album (1983) (Amiga) (Prototype)" "Cartridge.Note" "Ghost Attack, Genesis, Havoc" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d5618464dbdc2981f6aa8b955828eeb4" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-829" "Cartridge.Name" "Megamania (1983) (CCE)" "" "Cartridge.MD5" "d563ba38151b8204c9f5c9f58e781455" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2649, 49-75163" "Cartridge.Name" "Asteroids (1981) (Atari) [a2]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d573089534ca596e64efef474be7b6bc" "Cartridge.Manufacturer" "Parker Brothers, John Emerson" "Cartridge.ModelNo" "931511" "Cartridge.Name" "Action Force (1983) (Parker Bros) (PAL) [a]" "Cartridge.Note" "AKA G.I. Joe - Cobra Strike" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 55" "" "Cartridge.MD5" "d57913088e0c49ac3a716bf9837b284f" "Cartridge.Manufacturer" "Activision, Garry Kitchen" "Cartridge.ModelNo" "EAZ-032" "Cartridge.Name" "Pressure Cooker (1983) (Activision) (PAL) [a]" "" "Cartridge.MD5" "d57eb282d7540051bc9b5427cf966f03" "Cartridge.Manufacturer" "Atari Troll" "Cartridge.Name" "Custer's Viagra (Atari Troll) (Hack)" "Cartridge.Note" "Hack of Custer's Revenge" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "d597d35c6022c590d6e75e865738558a" "Cartridge.Name" "Sprite Color Demo (PD)" "" "Cartridge.MD5" "d5aa7472e7f2cc17e893a1a36f8dadf0" "Cartridge.Name" "Overhead Adventure Demo 5 (PD)" "" "Cartridge.MD5" "d5c6b81212ad86fd9542a1fedaf57cae" "Cartridge.Name" "Sprite Demo 1 (PD)" "" "Cartridge.MD5" "d5d2d44fb73785996ccc24ae3a0f5cef" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Grand Prix (Robby)" "" "Cartridge.MD5" "d5e17022d1ecc20fd9b53dc464c302f1" "Cartridge.Manufacturer" "Activision, Carol Shaw" "Cartridge.ModelNo" "EAX-020" "Cartridge.Name" "River Raid (1982) (Activision) (SECAM)" "Display.Format" "SECAM" "" "Cartridge.MD5" "d5e27051512c1e7445a9bf91501bda09" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-008" "Cartridge.Name" "Laser Blast (1981) (Activision) (4K)" "" "Cartridge.MD5" "d5e5b3ec074fff8976017ef121d26129" "Cartridge.Manufacturer" "Star Game" "Cartridge.ModelNo" "003" "Cartridge.Name" "River Raid (Star Game)" "" "Cartridge.MD5" "d5f965c159e26a1fb49a22a47fbd1dd0" "Cartridge.Manufacturer" "Supergame" "Cartridge.Name" "River Raid II (Supergame)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "d605ed12f4eaaaec3dcd5aa909a4bad7" "Cartridge.Name" "Chronocolor Frame Demo (10-01-2003) (AD)" "" "Cartridge.MD5" "d61629bbbe035f45552e31cef7d591b2" "Cartridge.Name" "Atari Logo Demo (PD) (PAL)" "" "Cartridge.MD5" "d62283aed0f4199adb2333de4c263e9c" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX2615" "Cartridge.Name" "Demons to Diamonds (1982) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 57" "" "Cartridge.MD5" "d62d7d1a974c31c5803f96a8c1552510" "Cartridge.Name" "StarMaster (Unknown) (PAL)" "Cartridge.Note" "Use Color/BW switch to change between galactic chart and front views" "" "Cartridge.MD5" "d632b74fea533d593af82cf16e7c5e4a" "Cartridge.Name" "Fu Kung! (V0.13) (01-02-2003) (AD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d65028524761ef52fbbdebab46f79d0f" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Galaxian (CCE)" "" "Cartridge.MD5" "d65900fefa7dc18ac3ad99c213e2fa4e" "Cartridge.Name" "Grid and Purple Dot Demo (PD)" "" "Cartridge.MD5" "d69559f9c9dc6ef528d841bf9d91b275" "Cartridge.Manufacturer" "Activision, Alan Miller" "Cartridge.ModelNo" "AX-016" "Cartridge.Name" "StarMaster (1982) (Activision)" "Cartridge.Note" "Use Color/BW switch to change between galactic chart and front views" "" "Cartridge.MD5" "d6a44277c3eb4f9d039185e0ecf7bfa6" "Cartridge.Name" "Trick (1997) (Eckhard Stolberg)" "" "Cartridge.MD5" "d6acff6aed0f04690fe4024d58ff4ce3" "Cartridge.Manufacturer" "Spectravision - Spectravideo - Quelle" "Cartridge.ModelNo" "SA-202 - 412.851 8" "Cartridge.Name" "Planet Patrol (1982) (Spectravision) (PAL) [different spaceship]" "" "Cartridge.MD5" "d6b8beeb05e5b730084d4b8f381bbf8d" "Cartridge.Name" "208 in 1 Game Select ROM (Unknown) (PAL)" "" "Cartridge.MD5" "d6d1ddd21e9d17ea5f325fa09305069c" "Cartridge.Manufacturer" "Funvision - Fund. International Co." "Cartridge.Name" "Time Warp (1982) (Funvision) (PAL)" "" "Cartridge.MD5" "d6d5dd8fd322d3cf874e651e7b6c1657" "Cartridge.Name" "How to Draw a Playfield (1997) (Nick Bensema) (PD)" "" "Cartridge.MD5" "d6dc9b4508da407e2437bfa4de53d1b2" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA283" "Cartridge.Name" "Z-Tack (1983) (Bomb) (PAL)" "Cartridge.Note" "AKA Base Attack" "" "Cartridge.MD5" "d726621c676552afa503b7942af5afa2" "Cartridge.Manufacturer" "Atari, Bob Whitehead" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Blackjack (32 in 1) (1988) (Atari) (PAL) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Display.YStart" "63" "" "Cartridge.MD5" "d73ad614f1c2357997c88f37e75b18fe" "Cartridge.Manufacturer" "Goliath" "Cartridge.ModelNo" "7" "Cartridge.Name" "Space Tunnel (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Cosmic Corridor" "" "Cartridge.MD5" "d74a81fcd89c5cf0bd4c88eb207ebd62" "Cartridge.Name" "Poker Squares (V0.00a) (2001) (B. Watson)" "" "Cartridge.MD5" "d763e3a9cdcdd56c715ec826106fab6a" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-001" "Cartridge.Name" "Dragster (1980) (Activision) (16K)" "Display.YStart" "27" "" "Cartridge.MD5" "d7759fa91902edd93f1568a37dc70cdb" "Cartridge.Manufacturer" "Atari, Robert C. Polaro" "Cartridge.ModelNo" "CX26157" "Cartridge.Name" "Stunt Cycle (1980) (Atari) (Prototype) (4K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d782543818b6320e4f60d77da2b596de" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fishing Derby (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "d787ec6785b0ccfbd844c7866db9667d" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V0.04) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d7891b0faa4c7f764482762d0ed427a5" "Cartridge.Name" "Bars and Text Demo 2 (PD)" "" "Cartridge.MD5" "d79df06894e3c1585a47c2807332b319" "Cartridge.Name" "Star Fire - Explosions! (10-10-2002) (MP)" "" "Cartridge.MD5" "d7b58303ec8d8c4dbcbf54d3b9734c7e" "Cartridge.Name" "Paddle Demo (Joe Grand) (PD)" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "" "Cartridge.MD5" "d7dd56677e4ec1e6627419478a4a9668" "Cartridge.Name" "Shadow Keep (Fixed) (04-03-2003) (Andrew Towers)" "" "Cartridge.MD5" "d7f5bf138cfc7feab7b8ef1534c8b477" "Cartridge.Name" "Eric Bergstrom's KC-135 (Radar Map) (Aaron Bergstrom)" "" "Cartridge.MD5" "d816fea559b47f9a672604df06f9d2e3" "Cartridge.Manufacturer" "Atari, Gary Palmer" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fun with Numbers (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "d81bb6965e6c99b3be99ffd8978740e4" "Cartridge.Name" "Gunfight 2600 - The Final Kernel Part 3 (MP)" "" "Cartridge.MD5" "d82675ce67caf16afe5ed6b6fac8aa37" "Cartridge.Name" "Robot City (V0.23) (13-11-2002) (TJ)" "" "Cartridge.MD5" "d8295eff5dcc43360afa87221ea6021f" "Cartridge.Manufacturer" "Spectravideo" "Cartridge.ModelNo" "SA-212" "Cartridge.Name" "Mangia' (1983) (Spectravideo) (PAL)" "" "Cartridge.MD5" "d82c8a58098a6b46c5b81c16180354d1" "Cartridge.Manufacturer" "Dennis Debro" "Cartridge.Name" "Climber 5 (30-10-2002) (Dennis Debro) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d85f1e35c5445ac898746719a3d93f09" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "731.503 9" "Cartridge.Name" "Tom's Eierjagd (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Play Farm" "" "Cartridge.MD5" "d86deb100c6abed1588aa84b2f7b3a98" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2625 - 6-99827, 49-75114" "Cartridge.Name" "Football (1979) (Atari) (4K)" "" "Cartridge.MD5" "d88691c995008b9ab61a44bb686b32e4" "Cartridge.Name" "Warring Worms (07-02-2002) (Billy Eno)" "" "Cartridge.MD5" "d89fedded0436fdeda7c3c37e2fb7cf1" "Cartridge.Name" "Surround (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "d8acaa980cda94b65066568dd04d9eb0" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Sea Hunt (CCE)" "Cartridge.Note" "AKA Skindiver" "" "Cartridge.MD5" "d8b2c81cea5af04f795eb3dc6573d72b" "Cartridge.Name" "Tunnel Demo 2 (27-03-2003) (CT)" "" "Cartridge.MD5" "d8df256c0d89e494a9fb3e9abb8e44ac" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "IA3312P" "Cartridge.Name" "No Escape! (1982) (Imagic) (PAL) [a]" "" "Cartridge.MD5" "d8e4c8e2d210270cd1e0f6d1b4582b91" "Cartridge.Manufacturer" "Imagic, Mark Klein" "Cartridge.ModelNo" "EIZ-003-04I" "Cartridge.Name" "Subterranea (1983) (Imagic) (PAL) [a]" "" "Cartridge.MD5" "d90205e29bb73a4cdf28ea7662ba0c3c" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Boulderdash Demo (Brighter Version) (09-12-2002) (TJ)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d912312349d90e9d41a9db0d5cd3db70" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-818" "Cartridge.Name" "Star Voyager (1983) (CCE)" "" "Cartridge.MD5" "d9548ad44e67edec202d1b8b325e5adf" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Dan Oliver - RCA Video Jeux" "Cartridge.ModelNo" "AP-2002" "Cartridge.Name" "Space Cavern (1982) (Apollo) (PAL)" "Cartridge.Note" "AKA Les guerriers de l'espace" "" "Cartridge.MD5" "d97e3d0b4575ce0b9a6132e19cfeac6e" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Space Treat (061002) (PD)" "Cartridge.Note" "Won't work with Stella < V1.2" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "d97fd5e6e1daacd909559a71f189f14b" "Cartridge.Manufacturer" "M Network, Steve Crandall, Patricia Lewis Du Long" "Cartridge.ModelNo" "MT4646" "Cartridge.Name" "Rocky & Bullwinkle (04-20-1983) (M Network) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "d9ab6b67a17da51e5ad13717e93fa2e2" "Cartridge.Name" "Turbo (Coleco) Prototype Fake v0.1 (TJ)" "" "Cartridge.MD5" "d9b49f0678776e04916fa5478685a819" "Cartridge.Manufacturer" "Activision, John Van Ryzin - Ariola" "Cartridge.ModelNo" "EAZ-036-04, EAZ-036-04B, EAZ-036-04I - 711 036-720" "Cartridge.Name" "H.E.R.O. (1984) (Activision) (PAL)" "" "Cartridge.MD5" "d9bd343533b61389b270c0787210943b" "Cartridge.Manufacturer" "Atari, Douglas 'Solaris' Neubauer" "Cartridge.ModelNo" "CX26134" "Cartridge.Name" "Last Starfighter (1984) (Atari) (Prototype)" "Cartridge.Note" "Genesis controller (C switches to map mode)" "Cartridge.Rarity" "Hack of Last Starfighter (Solaris prototype)" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "d9c9cece2e769c7985494b1403a25721" "Cartridge.Manufacturer" "SOLID Corp. (D. Scott Williamson)" "Cartridge.ModelNo" "CX2655*" "Cartridge.Name" "Star Castle 2600 (SolidCorp)" "Cartridge.Note" "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d9da2ae7c7894a29b43b3c6b79f3b7a2" "Cartridge.Manufacturer" "Atari, Rob Fulop" "Cartridge.ModelNo" "CX2633, CX2633P" "Cartridge.Name" "Night Driver (1980) (Atari) (PAL) (4K)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 65" "Display.Phosphor" "YES" "" "Cartridge.MD5" "d9fbf1113114fb3a3c97550a0689f10f" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "713-111 - GN-050" "Cartridge.Name" "Pizza Chef (1983) (ZiMAG) (Prototype)" "Cartridge.Note" "AKA Pizza Time" "" "Cartridge.MD5" "da0fb2a484d0d2d8f79d6e063c94063d" "Cartridge.Name" "Air Raiders (1982) (Unknown) [a]" "" "Cartridge.MD5" "da4e3396aa2db3bd667f83a1cb9e4a36" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-027" "Cartridge.Name" "Plaque Attack (1983) (Activision)" "" "Cartridge.MD5" "da5096000db5fdaa8d02db57d9367998" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "River Raid (1983) (Digitel)" "" "Cartridge.MD5" "da6465a34d2e44d26aa9a2a0cd1bce4d" "Cartridge.Manufacturer" "Absolute Entertainment, Alex DeMeo" "Cartridge.ModelNo" "AG-041-04" "Cartridge.Name" "Title Match Pro Wrestling (1987) (Absolute) [a]" "" "Cartridge.MD5" "da64f33d0521d5c9958e5d2d4434ff95" "Cartridge.Name" "Star Fire - Return of the Starfield (MP)" "" "Cartridge.MD5" "da66d75e4b47fab99733529743f86f4f" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Chopper Command (1983) (Digitel)" "" "Cartridge.MD5" "da732c57697ad7d7af414998fa527e75" "Cartridge.Manufacturer" "Atari - Glenn Axworthy" "Cartridge.ModelNo" "CX26129" "Cartridge.Name" "Midnight Magic (1986) (Atari) (PAL)" "Cartridge.Note" "AKA Pinball Wizard" "Display.Phosphor" "YES" "" "Cartridge.MD5" "da79aad11572c80a96e261e4ac6392d0" "Cartridge.Manufacturer" "Salu - Ubi Soft, Dennis M. Kiss" "Cartridge.ModelNo" "460673" "Cartridge.Name" "Pick 'n' Pile (1990) (Salu) (PAL)" "Console.SwapPorts" "YES" "Display.YStart" "40" "Display.Height" "256" "Display.Phosphor" "YES" "" "Cartridge.MD5" "da7a17dcdaa62d6971393c0a6faf202a" "Cartridge.Name" "Flag Capture (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "dab844deed4c752632b5e786b0f47999" "Cartridge.Name" "Super Challenge Baseball (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "dac38b4dd3da73bb7b2e9d70c61d2b7c" "Cartridge.Name" "Hangman Monkey Biglist3 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "dac5c0fe74531f077c105b396874a9f1" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX2680" "Cartridge.Name" "RealSports Tennis (1983) (Atari)" "" "Cartridge.MD5" "dac762e4d01d445bdef20b7771f6570e" "Cartridge.Manufacturer" "Atari, Carla Meninsky, Ed Riddle - Sears" "Cartridge.ModelNo" "CX2611 - 99821, 49-75149" "Cartridge.Name" "Indy 500 (1977) (Atari) (4K) [a]" "Cartridge.Note" "Uses the Driving Controllers" "Controller.Left" "DRIVING" "Controller.Right" "DRIVING" "Controller.MouseAxis" "45" "Display.YStart" "28" "" "Cartridge.MD5" "dad2ab5f66f98674f12c92abcfbf3a20" "Cartridge.Name" "Blue and White Sprite Demo (PD)" "" "Cartridge.MD5" "daeb54957875c50198a7e616f9cc8144" "Cartridge.Manufacturer" "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer" "Cartridge.ModelNo" "11005" "Cartridge.Name" "Mega Force (1982) (20th Century Fox)" "" "Cartridge.MD5" "daef7d8e5a09981c4aa81573d4dbb380" "Cartridge.Manufacturer" "Adam Thornton" "Cartridge.Name" "Lord of the Rings (Adam Thornton) (Hack)" "Cartridge.Note" "Hack of Dark Mage" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dafc3945677ccc322ce323d1e9930beb" "Cartridge.Manufacturer" "Atari" "Cartridge.Name" "A-Team (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "db1753cc702c18d3917ec7f3b0e8659f" "Cartridge.Name" "Frame Counter 2 (2001) (Jake Patterson) (PD)" "" "Cartridge.MD5" "db339aea2b65b84c7cfe0eeab11e110a" "Cartridge.Name" "Chronocolor Frame Demo 2 (10-01-2003) (AD)" "" "Cartridge.MD5" "db4eb44bc5d652d9192451383d3249fc" "Cartridge.Manufacturer" "CBS Electronics - E.F. Dreyer - VSS, Ed Salvo" "Cartridge.ModelNo" "4L 2738 0000" "Cartridge.Name" "Mountain King (1983) (CBS Electronics)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "db5073bd75eb05f7d62a7268396d1e77" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Golf (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "db76f7a0819659d9e585f2cdde9175c7" "Cartridge.Manufacturer" "Xonox" "Cartridge.ModelNo" "99005, 6220, 6250" "Cartridge.Name" "Robin Hood (1983) (Xonox) (PAL) [a]" "Display.YStart" "30" "" "Cartridge.MD5" "db80d8ef9087af4764236f7b5649fa12" "Cartridge.Manufacturer" "M Network, Steve Crandall, Patricia Lewis Du Long" "Cartridge.ModelNo" "MT4646" "Cartridge.Name" "Rocky & Bullwinkle (1983) (Mattel) (Prototype) (4K)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "db971b6afc9d243f614ebf380af0ac60" "Cartridge.Manufacturer" "Gammation, Robert L. Esken Jr." "Cartridge.Name" "Gamma-Attack (1983) (Gammation)" "Cartridge.Note" "Uses right joystick controller" "Console.SwapPorts" "YES" "Display.Height" "220" "" "Cartridge.MD5" "dba2692a216cb6c262c78f8b111a813e" "Cartridge.Name" "Star Fire (08-10-2002) (MP)" "" "Cartridge.MD5" "dba270850ae997969a18ee0001675821" "Cartridge.Manufacturer" "Greg Troutman" "Cartridge.Name" "Dark Mage (Greg Troutman) (PD) (4K)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dbabb80e92ff18d8eecf615c0539151e" "Cartridge.Name" "Sprite Demo 3 (PD)" "" "Cartridge.MD5" "dbb10b904242fcfb8428f372e00c01af" "Cartridge.Manufacturer" "Atari, John Dunn" "Cartridge.ModelNo" "CX2631, CX2631P" "Cartridge.Name" "Superman (1979) (Atari) (PAL)" "" "Cartridge.MD5" "dbc7485ad5814d466de780a3e7ed3b46" "Cartridge.Manufacturer" "Kyle Pittman" "Cartridge.Name" "Pink Floyd (Kyle Pittman) (PD)" "Cartridge.Note" "Hack of Adventures of Tron (Mattel)" "Cartridge.Rarity" "New Release (Hack)" "" "Cartridge.MD5" "dbc8829ef6f12db8f463e30f60af209f" "Cartridge.Manufacturer" "Data Age" "Cartridge.ModelNo" "DA1001" "Cartridge.Name" "Encounter at L-5 (1982) (Data Age)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 50" "" "Cartridge.MD5" "dbdaf82f4f0c415a94d1030271a9ef44" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Kaboom! (CCE)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "dbdd21e1ee3d72119e8cd14d943c585b" "Cartridge.Name" "Slot Machine (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "dc13df8420ec69841a7c51e41b9fbba5" "Cartridge.Manufacturer" "Atari, Mimi Nyden, Steve Woita" "Cartridge.ModelNo" "CX26132" "Cartridge.Name" "Garfield (06-21-1984) (Atari) (Prototype)" "Cartridge.Note" "AKA Garfield on the Run" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "dc33479d66615a3b09670775de4c2a38" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-033" "Cartridge.Name" "I.Q. Memory Teaser (Suntek) (PAL)" "Cartridge.Note" "AKA IQ 180" "" "Cartridge.MD5" "dc6aa0bb21a6e66e80e75ba5edc5c0dd" "Cartridge.Name" "Star Fire - Kernel Done (MP)" "" "Cartridge.MD5" "dc81c4805bf23959fcf2c649700b82bf" "Cartridge.Manufacturer" "Imagic, Michael Greene" "Cartridge.ModelNo" "720055-2A, IA3312P" "Cartridge.Name" "No Escape! (1983) (Imagic) (PAL)" "" "Cartridge.MD5" "dc905b22de0f191a029df13eddfcabc4" "Cartridge.Manufacturer" "Atari, Warren Robinett" "Cartridge.Name" "Elf Adventure (05-02-83) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "dca90ea1084a2fdbe300d7178ca1a138" "Cartridge.Manufacturer" "Imagic, Dennis Koble" "Cartridge.ModelNo" "IA3000P" "Cartridge.Name" "Trick Shot (1982) (Imagic) (PAL) [a]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dca941dab5c6f859b71883b13ade9744" "Cartridge.Name" "Hangman Pac-Man Biglist2 (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "dcba0e33aa4aed67630a4b292386f405" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.08) (Half Speed Version) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dcc2956c7a39fdbf1e861fc5c595da0d" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, David Rolfe - INTV" "Cartridge.ModelNo" "MT5664" "Cartridge.Name" "Frogs and Flies (1982) (M Network)" "Cartridge.Note" "AKA Frogs 'n' Flies" "" "Cartridge.MD5" "dcec46a98f45b193f07239611eb878c2" "Cartridge.Name" "Bars and Text Demo (PD)" "" "Cartridge.MD5" "dd08e18cfee87a0e7fc19a684b36e124" "Cartridge.Manufacturer" "Atari - GCC, Kevin Osborn" "Cartridge.ModelNo" "CX2689, CX2689P" "Cartridge.Name" "Kangaroo (1983) (Atari) (PAL) [a]" "" "Cartridge.MD5" "dd0cbe5351551a538414fb9e37fc56e8" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson" "Cartridge.ModelNo" "99006, 6220" "Cartridge.Name" "Sir Lancelot (1983) (Xonox) (PAL)" "" "Cartridge.MD5" "dd0de0f61af2a2a4878e377b880a3933" "Cartridge.Manufacturer" "SOLID Corp. (D. Scott Williamson)" "Cartridge.ModelNo" "CX2655-013" "Cartridge.Name" "Star Castle 2600 (SolidCorp) [013]" "Cartridge.Note" "http://starcastle2600.blogspot.com/p/star-castle-2600-story.html" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dd10b5ee37fdbf909423f2998a1f3179" "Cartridge.Name" "Space Instigators (V1.9) (21-10-2002) (CT)" "" "Cartridge.MD5" "dd1422ffd538e2e33b339ebeef4f259d" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.Name" "Red Vs. Blue (1981) (Atari) (Prototype)" "Cartridge.Note" "RealSports Football Beta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "dd17711a30ad60109c8beace0d4a76e8" "Cartridge.Name" "Karate (Unknown) (PAL)" "Display.YStart" "20" "" "Cartridge.MD5" "dd4f4e0fbd81762533e39e6f5b55bb3a" "Cartridge.Name" "Turbo WIP (TJ)" "" "Cartridge.MD5" "dd7598b8bcb81590428900f71b720efb" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Computer Magic" "Cartridge.ModelNo" "99005, 6220, 6250" "Cartridge.Name" "Robin Hood (1983) (Xonox) (PAL)" "Display.YStart" "30" "" "Cartridge.MD5" "dd7884b4f93cab423ac471aa1935e3df" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2649, 49-75163" "Cartridge.Name" "Asteroids (1981) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "dd8a2124d4eda200df715c698a6ea887" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (3 of 3) (1982) (Starpath)" "" "Cartridge.MD5" "dd92d6ad50976f881d86b52d38616118" "Cartridge.Manufacturer" "SpkSoft" "Cartridge.Name" "River Raid (SpkSoft) [h1]" "" "Cartridge.MD5" "dda23757407c4e217f64962c87ad0c82" "Cartridge.Manufacturer" "Atari Freak 1" "Cartridge.Name" "Nitemare at Sunshine Bowl-a-Rama (Atari Freak 1) (Hack) [a]" "Cartridge.Note" "Hack of Pac-Man Jr." "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "ddd1efc1862cd3eb3baf4cba81ff5050" "Cartridge.Name" "Max3 (2001) (Maxime Beauvais) (PD)" "" "Cartridge.MD5" "de0173ed6be9de6fd049803811e5f1a8" "Cartridge.Manufacturer" "Xonox - K-Tel Software - Product Guild, Anthony R. Henderson" "Cartridge.ModelNo" "99008, 6240" "Cartridge.Name" "Motocross Racer (1983) (Xonox)" "" "Cartridge.MD5" "de07e9cb43ad8d06a35f6506e22c62e9" "Cartridge.Name" "Oh No! (Version 4) (22-01-2003) (AD)" "" "Cartridge.MD5" "de1a636d098349be11bbc2d090f4e9cf" "Cartridge.Name" "Pressure Gauge (Hozer Video Games)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "de1e9fb700baf8d2e5ae242bffe2dbda" "Cartridge.Manufacturer" "Activision - Imagineering, Mike Reidel" "Cartridge.ModelNo" "EAK-043-04I" "Cartridge.Name" "Commando (1988) (Activision) (PAL)" "" "Cartridge.MD5" "de24f700fd28d5b8381de13abd091db9" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Plaque Attack (CCE)" "" "Cartridge.MD5" "de29e46dbea003c3c09c892d668b9413" "Cartridge.Manufacturer" "Coleco - Woodside Design Associates, Steve 'Jessica Stevens' Kitchen" "Cartridge.ModelNo" "4L1717, 4L1718, 4L1719, 4L2277" "Cartridge.Name" "Carnival (1983) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "de3d0e37729d85afcb25a8d052a6e236" "Cartridge.Manufacturer" "Spectravision - Spectravideo" "Cartridge.ModelNo" "SA-204" "Cartridge.Name" "Tapeworm (1982) (Spectravision)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "de4436eaa41e5d7b7609512632b90078" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AX-014, AX-014-04" "Cartridge.Name" "Grand Prix (1982) (Activision) (16K)" "" "Cartridge.MD5" "de5aab22e5aba5edcb29a3e7491ff319" "Cartridge.Manufacturer" "Star Game" "Cartridge.ModelNo" "001" "Cartridge.Name" "Donkey Kong (Star Game)" "Cartridge.Note" "AKA Inca Gold" "Display.YStart" "30" "" "Cartridge.MD5" "de61a0b171e909a5a4cfcf81d146dbcb" "Cartridge.Manufacturer" "Rainbow Vision - Suntek" "Cartridge.ModelNo" "SS-005" "Cartridge.Name" "Tom Boy (Rainbow Vision) (PAL)" "Cartridge.Note" "AKA Pitfall!" "" "Cartridge.MD5" "de62f8a30298e2325249fe112ecb5c10" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-810" "Cartridge.Name" "Enduro (1983) (CCE)" "" "Cartridge.MD5" "de78b3a064d374390ac0710f95edde92" "Cartridge.Manufacturer" "Bomb - Onbase" "Cartridge.ModelNo" "CA281" "Cartridge.Name" "Assault (1983) (Bomb)" "Cartridge.Note" "AKA Sky Alien" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "de7a64108074098ba333cc0c70eef18a" "Cartridge.Name" "Nuts (Unknown)" "Display.YStart" "37" "" "Cartridge.MD5" "de7bca4e569ad9d3fd08ff1395e53d2d" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Thrust (V1.22) (2000) (TJ)" "Cartridge.Note" "Won't work with Stella < V1.2, supports Booster Grip" "Cartridge.Rarity" "New Release" "Controller.Left" "BOOSTERGRIP" "" "Cartridge.MD5" "de8443ff47283e7b274a7838cb071fb6" "Cartridge.Manufacturer" "Atari, Lou Harp" "Cartridge.ModelNo" "CX26122" "Cartridge.Name" "Sinistar (01-04-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "dea0ade296f7093e71185e802b500db8" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Fishing Derby (CCE)" "" "Cartridge.MD5" "deb39482e77f984d4ce73be9fd8adabd" "Cartridge.Manufacturer" "Activision, David Lubar" "Cartridge.ModelNo" "AK-048-04" "Cartridge.Name" "River Raid II (1988) (Activision) [a]" "" "Cartridge.MD5" "ded26e1cb17f875a9c17515c900f9933" "Cartridge.Name" "Space Treat (29-12-2002) (Fabrizio Zavagli)" "" "Cartridge.MD5" "df12953b919844dad2070ed2e70c9fa2" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.ModelNo" "3135" "Cartridge.Name" "S.A.C. Alert (1983) (Amiga) (Prototype) (PAL)" "Cartridge.Note" "Uses Joyboard" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "df2745d585238780101df812d00b49f4" "Cartridge.Manufacturer" "Bit Corporation" "Cartridge.ModelNo" "PG202" "Cartridge.Name" "Space Tunnel (1982) (BitCorp)" "Cartridge.Note" "AKA Cosmic Corridor, Weltraum-Tunnel" "Display.Height" "222" "" "Cartridge.MD5" "df3e6a9b6927cf59b7afb626f6fd7eea" "Cartridge.Name" "Tuby Bird (208 in 1) (Unknown) (PAL)" "Cartridge.Note" "AKA Dolphin" "" "Cartridge.MD5" "df40af244a8d68b492bfba9e97dea4d6" "Cartridge.Manufacturer" "Franklin Cruz" "Cartridge.Name" "Asteroids 2 (Franlin Cruz) (Hack)" "Cartridge.Note" "Hack of Asteroids" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "df5cc5cccdc140eb7107f5b8adfacda1" "Cartridge.Manufacturer" "Cracker Jack Productions" "Cartridge.Name" "Lumberman (Cracker Jack) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "df62a658496ac98a3aa4a6ee5719c251" "Cartridge.Manufacturer" "Atari, Tom Reuterdahl - Sears" "Cartridge.ModelNo" "CX2626 - 6-99829, 49-75116" "Cartridge.Name" "Miniature Golf (1979) (Atari)" "Cartridge.Note" "AKA Arcade Golf" "" "Cartridge.MD5" "df6a28a89600affe36d94394ef597214" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Dan Oliver" "Cartridge.ModelNo" "AP-2002" "Cartridge.Name" "Space Cavern (1982) (Apollo)" "" "Cartridge.MD5" "df6a46714960a3e39b57b3c3983801b5" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG201" "Cartridge.Name" "Sea Monster (1982) (Puzzy) (PAL)" "" "Cartridge.MD5" "df753cb87d3af4d03f694ab848638108" "Cartridge.Manufacturer" "CBS Electronics, Bob Curtiss" "Cartridge.ModelNo" "4L1845, 4L1852, 4L1853, 4L1854" "Cartridge.Name" "Solar Fox (1983) (CBS Electronics) (PAL) [a]" "" "Cartridge.MD5" "df95e4af466c809619299f49ece92365" "Cartridge.Manufacturer" "Atari - CCW, Michael Callahan, Preston Stuart" "Cartridge.ModelNo" "CX26103" "Cartridge.Name" "Alpha Beam with Ernie (06-03-1983) (Atari) (Prototype) (PAL)" "Cartridge.Note" "Uses Keypad Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "dfad86dd85a11c80259f3ddb6151f48f" "Cartridge.Manufacturer" "HES - Imagineering, David Lubar" "Cartridge.ModelNo" "535" "Cartridge.Name" "My Golf (1990) (HES) (PAL) [fixed]" "" "Cartridge.MD5" "dfafa3fa58f5cc3f0342cca475df6095" "Cartridge.Name" "Space Treat (V1.1 Beta) (24-12-2002) (Fabrizio Zavagli)" "" "Cartridge.MD5" "dfc03ef371cf5163f54c50d8ee73c8cf" "Cartridge.Manufacturer" "Atari, Gary Palmer" "Cartridge.ModelNo" "CX2661" "Cartridge.Name" "Fun with Numbers (1980) (Atari) (4K)" "Cartridge.Note" "AKA Basic Math" "" "Cartridge.MD5" "dfc3dbbb39f05d7dd8ee3ac987478970" "Cartridge.Name" "Imagic Selector ROM (1982) (Imagic) (PAL)" "" "Cartridge.MD5" "dfcdd6f593bb7b05dbc2e8e1fc6ee0de" "Cartridge.Name" "Gunfight 2600 - Scenarios complete (MP)" "" "Cartridge.MD5" "dfe034297200dff672df9533ed1449a9" "Cartridge.Name" "Sprite Movement Demo 1 (2001) (Roger Williams)" "" "Cartridge.MD5" "dfe6aa7443bb813cefa35a4cf4887422" "Cartridge.Name" "This Planet Sucks (Greg Troutman) [a1]" "Cartridge.Rarity" "New Release" "Display.YStart" "36" "" "Cartridge.MD5" "dff33523ccd2fdc8912e84cab8e0d982" "Cartridge.Name" "Fu Kung! (V0.03) (10-01-2003) (AD)" "" "Cartridge.MD5" "e01e00504e6d4b88fa743c0bbe8a96e5" "Cartridge.Name" "Qb (Special Edition, some bugfixes) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e020f612255e266a8a6a9795a4df0c0f" "Cartridge.Manufacturer" "Telegames - VSS" "Cartridge.ModelNo" "7062 A305" "Cartridge.Name" "Universal Chaos (1988) (Telegames) (PAL)" "Cartridge.Note" "AKA Targ" "" "Cartridge.MD5" "e02156294393818ff872d4314fc2f38e" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC005" "Cartridge.Name" "Dice Puzzle (1983) (Sancho) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e0221c95aa657f5764eeeb64c8429258" "Cartridge.Name" "Tomb Raider 2600 [REV 02] (Montezuma's Revenge Hack)" "" "Cartridge.MD5" "e03b0b091bea5bc9d3f14ee0221e714d" "Cartridge.Manufacturer" "CBS Electronics, Bob Curtiss" "Cartridge.ModelNo" "4L1852, 4L1853, 4L1854, 4L1855" "Cartridge.Name" "Solar Fox (1983) (CBS Electronics) (PAL)" "" "Cartridge.MD5" "e040df95a055b18ebdb094e904cb71b2" "Cartridge.Name" "Score Demo (B. Watson)" "" "Cartridge.MD5" "e04f1c1e4401d584d3f4343410a5bcc4" "Cartridge.Manufacturer" "Wizard Video Games - MicroGraphic Image, Robert Barber, Tim Martin" "Cartridge.ModelNo" "007" "Cartridge.Name" "Halloween (1983) (Wizard Video Games) (Prototype) [a]" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e0b24c3f40a46cda52e29835ab7ad660" "Cartridge.Manufacturer" "Quelle - Otto Versand" "Cartridge.ModelNo" "626.502 9 - 746381" "Cartridge.Name" "Top Gun (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Air Raiders" "" "Cartridge.MD5" "e0cf2dcc4c1348c468f5bb1e421c9164" "Cartridge.Name" "Invader Sprites in a Line Demo (PD)" "" "Cartridge.MD5" "e0de3773f5b867795db557be7b8a703e" "Cartridge.Name" "Boulderdash (13 Blocks Wide) (02-04-2003) (AD)" "" "Cartridge.MD5" "e0eff071f578ecf19edc2ab276644e46" "Cartridge.Name" "Gas Gauge Demo (2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "e1029676edb3d35b76ca943da7434da8" "Cartridge.Manufacturer" "Atari, Robert C. Polaro, Alan J. Murphy - Sears" "Cartridge.ModelNo" "CX2609 - 49-75186" "Cartridge.Name" "Defender (10-30-1981) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e10bf1af6bf3b4a253c5bef6577fe923" "Cartridge.Manufacturer" "Rob Kudla" "Cartridge.Name" "Space Invaders (1978) (Atari) [h1]" "Cartridge.Note" "Hack of Space Invaders (Atari)" "Cartridge.Rarity" "New Release (Hack)" "" "Cartridge.MD5" "e10d2c785aadb42c06390fae0d92f282" "Cartridge.Manufacturer" "Parker Brothers, Dawn Stockbridge" "Cartridge.ModelNo" "PB5910" "Cartridge.Name" "Strawberry Shortcake - Musical Match-Ups (1983) (Parker Bros)" "Display.Height" "225" "" "Cartridge.MD5" "e1143b72a30d4d3fee385eec38b4aa4d" "Cartridge.Name" "Word Zapper (Unknown)" "" "Cartridge.MD5" "e12e32dee68201b6765fcd0ed54d6646" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2612, CX2612P" "Cartridge.Name" "Street Racer (1977) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (swapped)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 75" "" "Cartridge.MD5" "e13818a5c0cb2f84dd84368070e9f099" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-839" "Cartridge.Name" "Misterious Thief, A (1983) (CCE)" "Cartridge.Note" "AKA A Mysterious Thief" "Display.Height" "216" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e13c7627b2e136b9c449d9e8925b4547" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2624 - 6-99826, 49-75113" "Cartridge.Name" "Basketball (1978) (Atari) (4K)" "Cartridge.Rarity" "Common" "" "Cartridge.MD5" "e1486c7822c07117b4f94a32e5ed68c1" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (06-14-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e14dc36b24fe22c04fa076e298f2e15f" "Cartridge.Manufacturer" "Activision, Larry Kaplan, David Crane" "Cartridge.ModelNo" "AG-010, AG-010-04" "Cartridge.Name" "Kaboom! (1981) (Activision) (16K)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "e14feddeb82f5160ed5cf9ca4078e58d" "Cartridge.Name" "SpaceMaster X-7 (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "e150f0d14f013a104b032305c0ce23ef" "Cartridge.Manufacturer" "Spectravision - Spectravideo" "Cartridge.ModelNo" "SA-205" "Cartridge.Name" "China Syndrome (1982) (Spectravision) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e15b5525cf8f77297b322838df8d999c" "Cartridge.Name" "Sprite Demo 0 (PD)" "" "Cartridge.MD5" "e171558c51bb3bac97bfa79fa2c1a19c" "Cartridge.Name" "Warring Worms (Tim Strauss Edition) (20-12-2002) (Billy Eno)" "" "Cartridge.MD5" "e17699a54c90f3a56ae4820f779f72c4" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "465.302 8" "Cartridge.Name" "Vogel Flieh (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Dolphin" "" "Cartridge.MD5" "e18abe87035379c56b435bfe8175077b" "Cartridge.Manufacturer" "Grimlock" "Cartridge.Name" "Rumble 2600 (Grimlock) (Hack)" "Cartridge.Note" "Hack of Mario Bros." "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e1a51690792838c5c687da80cd764d78" "Cartridge.Manufacturer" "20th Century Fox, John Russell" "Cartridge.Name" "Alligator People (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e1b90f1e01b1a316d7bbf141525cc00e" "Cartridge.Name" "Sky Jinks (Unknown) (PAL) (4K) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e1d5c8213e82820128fa9c4775f1e166" "Cartridge.Manufacturer" "Jess Ragan" "Cartridge.Name" "Jungle King (2003) (Jess Ragan) (Hack)" "Cartridge.Note" "Hack of Jungle Hunt" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e1d79e4e7c150f3861256c541ec715a1" "Cartridge.Name" "Space Jockey (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "e1e09e2f280e8e142121a377d0dc1b46" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Thrust (V1.21) (2000) (TJ)" "Cartridge.Note" "Won't work with Stella < V1.2, bugfixed" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "e1efe2ef7664bb6758b1a22ff8ea16a1" "Cartridge.Manufacturer" "Dynacom" "Cartridge.Name" "Enduro (1983) (Dynacom)" "" "Cartridge.MD5" "e1f88da6da8a7d521ca1dcbf2bc6978b" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAG-005, PAG-005, EAG-005-04B - 711 005-715" "Cartridge.Name" "Skiing (1980) (Activision) (PAL) (4K)" "" "Cartridge.MD5" "e21ee3541ebd2c23e817ffb449939c37" "Cartridge.Manufacturer" "Tigervision - Software Electronics Corp., Karl T. Olinger - Teldec" "Cartridge.ModelNo" "7-001" "Cartridge.Name" "King Kong (1982) (Tigervision)" "Display.YStart" "28" "" "Cartridge.MD5" "e237ee91514d5ed535c95a14fc608c11" "Cartridge.Manufacturer" "Activision, Matthew L. Hubbard, Bob Whitehead" "Cartridge.ModelNo" "AX-024" "Cartridge.Name" "Dolphin (1983) (Activision) (8K)" "" "Cartridge.MD5" "e2389c0be5b5b84e0d3ca36ec7e67514" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.09) (NTSC) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e24d7d879281ffec0641e9c3f52e505a" "Cartridge.Manufacturer" "Parker Brothers, Mark Lesser" "Cartridge.ModelNo" "PB5950" "Cartridge.Name" "Lord of the Rings (1983) (Parker Bros) (Prototype)" "Cartridge.Note" "Journey to Rivendell (The Lord of the Rings I)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e25e173740f7ecc0e23025445c4591f3" "Cartridge.Manufacturer" "Greg Zumwalt" "Cartridge.Name" "Comitoid (Greg Zumwalt)" "" "Cartridge.MD5" "e275cbe7d4e11e62c3bfcfb38fca3d49" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Ken Smith - INTV" "Cartridge.ModelNo" "MT5658" "Cartridge.Name" "Super Challenge Football (1982) (M Network)" "Cartridge.Note" "AKA Pro Football" "" "Cartridge.MD5" "e28113d10c0c14cc3b5f430b0d142fcb" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-816" "Cartridge.Name" "Keystone Kappers (1983) (CCE) [a]" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "e2846af3e4d172b251ab77cbdd01761e" "Cartridge.Manufacturer" "Steve Engelhardt" "Cartridge.Name" "Adventure Plus (2003) (Steve Engelhardt) (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e2904748da63dfefc8816652b924b642" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Catch Time (Jone Yuan)" "Cartridge.Note" "AKA Plaque Attack" "" "Cartridge.MD5" "e2b682f6e6d76b35c180c7d847e93b4f" "Cartridge.Name" "Dodge Demo 4 (PD)" "" "Cartridge.MD5" "e2c1b60eaa8eda131632d73e4e0c146b" "Cartridge.Manufacturer" "Atari - GCC, Mark Ackerman, Noellie Alito" "Cartridge.ModelNo" "CX2692" "Cartridge.Name" "Moon Patrol (07-04-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e2c89f270f72cd256ed667507fa038a2" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4101" "Cartridge.Name" "Communist Mutants from Space (1982) (Arcadia) (PAL)" "" "Cartridge.MD5" "e2ca84a2bb63d1a210ebb659929747a9" "Cartridge.Manufacturer" "Telesys, Don 'Donyo' Ruffcorn" "Cartridge.ModelNo" "1002" "Cartridge.Name" "Cosmic Creeps (1982) (Telesys) (PAL)" "Cartridge.Note" "AKA Space Maze, Spaze Maze" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e2eccbbe963f80f291cb1f18803bf557" "Cartridge.Manufacturer" "Atari, Joe Decuir, Steve Mayer, Larry Wagner" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Combat (32 in 1) (1988) (Atari) (PAL) (4K)" "Display.YStart" "40" "Display.Height" "256" "" "Cartridge.MD5" "e314b42761cd13c03def744b4afc7b1b" "Cartridge.Manufacturer" "Activision, David Crane, Dan Kitchen" "Cartridge.ModelNo" "AZ-108-04" "Cartridge.Name" "Ghostbusters (1985) (Activision)" "" "Cartridge.MD5" "e34c236630c945089fcdef088c4b6e06" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAB-035-04 - 711 035-721" "Cartridge.Name" "Pitfall II (1984) (Activision) (PAL)" "Cartridge.Note" "Lost Caverns" "" "Cartridge.MD5" "e3533684a7ef930a7fbd0c4dd8ec4847" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-856" "Cartridge.Name" "Pimball (1983) (CCE)" "Cartridge.Note" "AKA Video Pinball" "" "Cartridge.MD5" "e3600be9eb98146adafdc12d91323d0f" "Cartridge.Manufacturer" "Atari, Carol Shaw" "Cartridge.ModelNo" "CX2618, CX2618P" "Cartridge.Name" "3-D Tic-Tac-Toe (1980) (Atari) (PAL)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "e363e467f605537f3777ad33e74e113a" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2603 - 99803, 49-75601" "Cartridge.Name" "Star Ship (1977) (Atari)" "" "Cartridge.MD5" "e377c3af4f54a51b85efe37d4b7029e6" "Cartridge.Manufacturer" "20th Century Fox Video Games, Steve Beck" "Cartridge.ModelNo" "11035" "Cartridge.Name" "Save the Whales (1983) (20th Century Fox) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e37c8055d70979af354251ebe9f1b7dd" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "Mega Funpak - Gorf, P. Patrol, Pacman, Skeet Shoot (HES) (PAL)" "" "Cartridge.MD5" "e38dc1f81a02e325562cd285123f579b" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein" "Cartridge.ModelNo" "CX2681, CX2681P" "Cartridge.Name" "Battlezone (1983) (Atari) (PAL) [a1]" "" "Cartridge.MD5" "e39843c56b7a4a08b18fa7949ec3ee6b" "Cartridge.Name" "Joshua Invaders (Hack)" "Cartridge.Note" "Hack of Space Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e39a13b13dc82c5fdbfbbfd55ba1230e" "Cartridge.Name" "Analog Clock (Additional Frame Info) (V0.0) (20-01-2003) (AD)" "" "Cartridge.MD5" "e3c0451d29dad724231bc5818ec4bae0" "Cartridge.Name" "Single-Scanline Positioning Demo 1 (2001) (Roger Williams)" "" "Cartridge.MD5" "e3c35eac234537396a865d23bafb1c84" "Cartridge.Manufacturer" "TechnoVision - Video Technology" "Cartridge.ModelNo" "TVS1001" "Cartridge.Name" "Nuts (1983) (TechnoVision) (PAL)" "Display.YStart" "45" "" "Cartridge.MD5" "e3ed4ba3361756970f076e46e9cad1d2" "Cartridge.Name" "Tennis (Unknown) (PAL) (4K) [a]" "" "Cartridge.MD5" "e40a818dac4dd851f3b4aafbe2f1e0c1" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, Dr. Lee Salk" "Cartridge.ModelNo" "CX26135" "Cartridge.Name" "Peek-A-Boo (1984) (Atari) (Prototype)" "Cartridge.Note" "Uses the Keypad Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "e42b937c30c617241ca9e01e4510c3f6" "Cartridge.Name" "Pitfall! (No Walls Hack)" "" "Cartridge.MD5" "e434c0e161dd3c3fb435eb6bad2e182c" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Brad Rice" "Cartridge.ModelNo" "CX2681" "Cartridge.Name" "Battlezone (05-02-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e49ac0ec879a0d7820bc2598fc2cfcd4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Kaboom! (CCE) (4K)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "e4a0b28befaaa2915df1fa01238b1e29" "Cartridge.Name" "Gunfight 2600 - Red River (MP)" "" "Cartridge.MD5" "e4afe157c09962cf39cdb25845d83d47" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAG-009, PAG-009 - 711 009-720" "Cartridge.Name" "Freeway (1981) (Activision) (PAL) (4K)" "" "Cartridge.MD5" "e4b12deaafd1dbf5ac31afe4b8e9c233" "Cartridge.Manufacturer" "Adam Thornton" "Cartridge.Name" "Lord of the Rings (Adam Thornton) (Hack) [a]" "Cartridge.Note" "Hack of Dark Mage" "Cartridge.Rarity" "Hack" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e4bff1d5df70163c0428a1ead309c22d" "Cartridge.Manufacturer" "Atari, Robert C. Polaro, Alan J. Murphy" "Cartridge.ModelNo" "CX2609, CX2609P" "Cartridge.Name" "Defender (1982) (Atari) (PAL)" "" "Cartridge.MD5" "e4c00beb17fdc5881757855f2838c816" "Cartridge.Manufacturer" "20th Century Fox Video Games - Sirius, Ed Hodapp" "Cartridge.ModelNo" "11004" "Cartridge.Name" "Deadly Duck (1982) (20th Century Fox)" "" "Cartridge.MD5" "e4c2077a18e3c27f4819aa7757903aa0" "Cartridge.Name" "Many Blue Bars Demo (PD)" "" "Cartridge.MD5" "e4c666ca0c36928b95b13d33474dbb44" "Cartridge.Manufacturer" "Arcadia Corporation, Steve Hales, Stephen H. Landrum" "Cartridge.ModelNo" "4 AR-4102" "Cartridge.Name" "Suicide Mission (1982) (Arcadia)" "Cartridge.Note" "AKA Meteoroids" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e4d41f2d59a56a9d917038682b8e0b8c" "Cartridge.Manufacturer" "Cody Pittman" "Cartridge.Name" "Kiss Meets Pacman (Cody Pittman) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "e4e9125a8741977583776729359614e1" "Cartridge.Manufacturer" "SnailSoft" "Cartridge.Name" "Comitoid beta 4 (SnailSoft)" "" "Cartridge.MD5" "e505bd8e59e31aaed20718d47b15c61b" "Cartridge.Manufacturer" "Funvision - Fund. Int'l Co." "Cartridge.Name" "Space War (1982) (Funvision) (PAL)" "Cartridge.Note" "AKA Condor Attack" "" "Cartridge.MD5" "e51030251e440cffaab1ac63438b44ae" "Cartridge.Manufacturer" "Parker Brothers - On-Time Software, Joe Gaucher, Louis Marbel" "Cartridge.ModelNo" "PB5110" "Cartridge.Name" "James Bond 007 (1984) (Parker Bros)" "Cartridge.Rarity" "Rare" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e51c23389e43ab328ccfb05be7d451da" "Cartridge.Manufacturer" "Arcadia Corporation, Scott Nelson" "Cartridge.ModelNo" "13" "Cartridge.Name" "Sweat! - The Decathlon Game (1983) (Arcadia) (Prototype)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Cartridge.Rarity" "Prototype" "Controller.Left" "PADDLES" "" "Cartridge.MD5" "e5359cbbbff9c6d7fe8aeff5fb471b46" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-849" "Cartridge.Name" "Boom Bang (1983) (CCE)" "Cartridge.Note" "AKA Crackpots" "" "Cartridge.MD5" "e549f1178e038fa88dc6d657dc441146" "Cartridge.Manufacturer" "Atari, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2625 - 6-99827, 49-75114" "Cartridge.Name" "Football (1979) (Atari)" "" "Cartridge.MD5" "e556e07cc06c803f2955986f53ef63ed" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.ModelNo" "2665" "Cartridge.Name" "Front Line (1984) (Coleco)" "" "Cartridge.MD5" "e558be88eef569f33716e8e330d2f5bc" "Cartridge.Manufacturer" "Shock Vision" "Cartridge.Name" "Keystone Kapers (Shock Vision)" "" "Cartridge.MD5" "e56da674188ba2f02c7a0a343a01236f" "Cartridge.Name" "This Planet Sucks Demo 4 (Greg Troutman) (PD)" "Cartridge.Rarity" "New Release" "Display.YStart" "36" "" "Cartridge.MD5" "e5a6e0bb7d56e2f08b237e15076e5699" "Cartridge.Name" "Color Table Display Helper (PD)" "" "Cartridge.MD5" "e5bacf526036d3c8c99db5b030cf00e7" "Cartridge.Name" "Starmaster (Genesis)" "Cartridge.Note" "Genesis controller (C switches to map mode)" "Cartridge.Rarity" "Hack of Starmaster" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "e5d5085123a98c1e61818caa2971e999" "Cartridge.Name" "Euchre (PAL) (Erik Eid) (PD)" "" "Cartridge.MD5" "e5d72ff8bab4450be57785cc9e83f3c0" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "6082 A145" "Cartridge.Name" "Kung Fu Superkicks (1988) (Telegames) (PAL)" "Cartridge.Note" "AKA Chuck Norris Superkicks" "" "Cartridge.MD5" "e5ecd78edd24326a968809decbc7b916" "Cartridge.Manufacturer" "Imagic, Bob Smith" "Cartridge.ModelNo" "720020-1A, IA3611" "Cartridge.Name" "Cheese (Dragonfire Beta) (05-21-1982) (Imagic) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e5f17b3e62a21d0df1ca9aee1aa8c7c5" "Cartridge.Manufacturer" "CommaVid, John Bronstein" "Cartridge.ModelNo" "CM-003" "Cartridge.Name" "Cosmic Swarm (1982) (CommaVid)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e5f360226dc552aba3e7e9b202330f48" "Cartridge.Manufacturer" "Supercat" "Cartridge.Name" "Mega Bitmap Demo (2007) (Supercat)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e5f84930aa468db33c0d0f7b26dd8293" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-826" "Cartridge.Name" "Grand Prix (1983) (CCE) [a]" "" "Cartridge.MD5" "e5fcc62e1d73706be7b895e887e90f84" "Cartridge.Name" "Air-Sea Battle (Unknown) (PAL) (4K)" "Display.YStart" "40" "Display.Height" "260" "" "Cartridge.MD5" "e600f5e98a20fafa47676198efe6834d" "Cartridge.Manufacturer" "Parker Brothers - Roklan" "Cartridge.ModelNo" "PB5080" "Cartridge.Name" "Gyruss (1984) (Parker Bros) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e609e8a007127b8fcff79ffc380da6b1" "Cartridge.Name" "Multi-Sprite Game V2.3 (Piero Cavina) (PD)" "" "Cartridge.MD5" "e61210293b14c9c4ecc91705072c6a7e" "Cartridge.Manufacturer" "Gameworld" "Cartridge.ModelNo" "133-005" "Cartridge.Name" "Bugs (1983) (Gameworld) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 50" "" "Cartridge.MD5" "e62e60a3e6cb5563f72982fcd83de25a" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "End of the World (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "Display.Height" "240" "" "Cartridge.MD5" "e63a87c231ee9a506f9599aa4ef7dfb9" "Cartridge.Manufacturer" "Tigervision, Warren Schwader" "Cartridge.ModelNo" "7-003" "Cartridge.Name" "Threshold (1982) (Tigervision)" "Display.YStart" "22" "" "Cartridge.MD5" "e63efdfda9a4003dcd77a854a781a06a" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Combat Rock (PD) (Hack) [a]" "Cartridge.Note" "Hack of Combat" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e643aaec9a9e1c8ab7fe1eae90bc77d7" "Cartridge.Manufacturer" "Roger Williams" "Cartridge.Name" "Asymmetric Playfield (Roger Williams)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "e64a8008812327853877a37befeb6465" "Cartridge.Manufacturer" "Answer Software Corporation - TY Associates" "Cartridge.ModelNo" "ASC1002" "Cartridge.Name" "Gauntlet (1983) (Answer Software)" "" "Cartridge.MD5" "e6508b878145187b87b9cded097293e7" "Cartridge.Name" "Oystron (V2.8) (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "e66e5af5dea661d58420088368e4ef0d" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-011" "Cartridge.Name" "Stampede (1981) (Activision) (4K)" "" "Cartridge.MD5" "e6d5948f451a24994dfaaca51dfdb4e1" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Football (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "e6de4ef9ab62e2196962aa6b0dedac59" "Cartridge.Manufacturer" "Imagic, Wilfredo Aguilar, Michael Becker, Dennis Koble" "Cartridge.ModelNo" "720113-2A, 13206" "Cartridge.Name" "Solar Storm (1983) (Imagic) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 45" "" "Cartridge.MD5" "e6e5bb0e4f4350da573023256268313d" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Missile Control (Thomas Jentzsch)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "e6f49a1053c79211f82be4d90dc9fe3d" "Cartridge.Name" "Gunfight 2600 - Little progress... (2001) (MP)" "" "Cartridge.MD5" "e723ad8f406cb258b89681ef4cef0eff" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Sadoom (TJ) (PAL) (Hack)" "Cartridge.Note" "Hack of Kaboom!" "Cartridge.Rarity" "Hack" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "e72eb8d4410152bdcb69e7fba327b420" "Cartridge.Manufacturer" "Atari, Douglas Neubauer, Mimi Nyden" "Cartridge.ModelNo" "CX26136" "Cartridge.Name" "Solaris (1986) (Atari)" "Cartridge.Note" "AKA Universe, Star Raiders II, The Last Starfighter" "" "Cartridge.MD5" "e72ee2d6e501f07ec5e8a0efbe520bee" "Cartridge.Manufacturer" "Imagic, Dave Johnson" "Cartridge.ModelNo" "720119-2A, 13211, EIX-004-04I" "Cartridge.Name" "Quick Step! (1983) (Imagic) (PAL)" "" "Cartridge.MD5" "e73838c43040bcbc83e4204a3e72eef4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Apples and Dolls (CCE)" "Cartridge.Note" "AKA I Want My Mommy" "Display.Height" "215" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e74022cfe31ec8908844718dfbdedf7a" "Cartridge.Name" "Space Treat (30-12-2002) (Fabrizio Zavagli) [a2]" "" "Cartridge.MD5" "e77ec259e1387bc308b0534647a89198" "Cartridge.Manufacturer" "Parker Brothers, David Lamkins, Laura Nikolich" "Cartridge.ModelNo" "931503" "Cartridge.Name" "Spider-Man (1982) (Parker Bros) (PAL)" "" "Cartridge.MD5" "e77f332b71f13884c84771e7a121182d" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Hey! Stop! (Jone Yuan)" "Cartridge.Note" "AKA Keystone Kapers" "" "Cartridge.MD5" "e784a9d26707cfcd170a4c1c60422a72" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "147.443 6" "Cartridge.Name" "Gefecht im All (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Space Jockey" "Display.YStart" "64" "" "Cartridge.MD5" "e7864caaf9ec49ed67b1904ce8602690" "Cartridge.Name" "Donkey Kong 2K3 Pic (PD)" "" "Cartridge.MD5" "e7a758bb0b43d0f7004e92b9abf4bc83" "Cartridge.Name" "Troll's Adventure (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e7dd8c2e6c100044002c1086d02b366e" "Cartridge.Manufacturer" "Activision, Steve Cartwright - Ariola" "Cartridge.ModelNo" "EAX-013, PAX-013, 711 013-720" "Cartridge.Name" "Barnstorming (1982) (Activision) (PAL)" "Cartridge.Note" "AKA Die tollkeuhnen Flieger" "" "Cartridge.MD5" "e7f005ddb6902c648de098511f6ae2e5" "Cartridge.Manufacturer" "Spectravideo - Universum" "Cartridge.ModelNo" "SV-010" "Cartridge.Name" "CompuMate (1983) (Spectravideo) (PAL)" "Cartridge.Type" "CM" "Display.Phosphor" "YES" "Display.PPBlend" "80" "" "Cartridge.MD5" "e800e4aec7c6c54c9cf3db0d1d030058" "Cartridge.Name" "Qb (2.06) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e80a4026d29777c3c7993fbfaee8920f" "Cartridge.Name" "Frisco (Unknown)" "" "Cartridge.MD5" "e823b13751e4388f1f2a375d3560a8d7" "Cartridge.Manufacturer" "Arcadia Corporation, Stephen Harland Landrum" "Cartridge.ModelNo" "AR-4105" "Cartridge.Name" "Official Frogger (Preview) (1983) (Arcadia) [a]" "Display.YStart" "32" "" "Cartridge.MD5" "e879b7093ac4cfad74c88d636ca97d00" "Cartridge.Name" "Poker Squares (V0.0f) (2001) (B. Watson)" "" "Cartridge.MD5" "e88340f5bd2f03e2e9ce5ecfa9c644f5" "Cartridge.Name" "Lock 'n' Chase (Unknown) (PAL)" "" "Cartridge.MD5" "e8a3473bf786cf796d1336d2d03a0008" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart" "Cartridge.ModelNo" "PB5540" "Cartridge.Name" "Star Wars - The Arcade Game (12-05-1983) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e8aa36e3d49e9bfa654c25dcc19c74e6" "Cartridge.Manufacturer" "Atari, Joe Decuir, Larry Caplan, Steve Mayer, Larry Wagner" "Cartridge.ModelNo" "CX2601, CX2601P" "Cartridge.Name" "Combat (1977) (Atari) (PAL)" "Display.Height" "260" "" "Cartridge.MD5" "e8e7b9bdf4bf04930c2bcaa0278ee637" "Cartridge.Name" "Boring Taz (Hack)" "Cartridge.Note" "Hack of Taz" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e8f7679359c4f532f5d5e93af7d8a985" "Cartridge.Name" "Hangman Invader Original Words (Hack)" "Cartridge.Note" "Hack of Hangman" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e9034b41741dcee64ab6605aba9de455" "Cartridge.Manufacturer" "Digivision" "Cartridge.Name" "Phanton Tank (Digivision)" "Cartridge.Note" "AKA Tanks But No Tanks" "Display.YStart" "30" "" "Cartridge.MD5" "e908611d99890733be31733a979c62d8" "Cartridge.Manufacturer" "Atari, Dan Hitchens, Mimi Nyden" "Cartridge.ModelNo" "CX2697" "Cartridge.Name" "Mario Bros. (1983) (Atari)" "" "Cartridge.MD5" "e91d2ecf8803ae52b55bbf105af04d4b" "Cartridge.Manufacturer" "Atari, Howard Scott Warshaw" "Cartridge.ModelNo" "CX2655, CX2655P" "Cartridge.Name" "Yars' Revenge (1982) (Atari) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e923001015bedd7901569f035d9c592c" "Cartridge.Name" "Adventure II (Hack)" "Cartridge.Note" "Hack of Adventure" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e927ecf80f3784d745abd8368d78f2f3" "Cartridge.Name" "Space Instigators (V1.8) (19-10-2002) (CT) [a1]" "" "Cartridge.MD5" "e932f44fad2a66b6d5faec9addec208e" "Cartridge.Name" "Atari Logo Demo 1 (PD)" "" "Cartridge.MD5" "e94632b0d863dd76459d689a9865bb33" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Combat (Jone Yuan) (4K)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "e957eb4612d6bd5940d3492dfa749668" "Cartridge.Name" "Tunnel Demo (27-03-2003) (CT)" "" "Cartridge.MD5" "e959b5a2c882ccaacb43c32790957c2d" "Cartridge.Name" "Phantom II & Pirate (NTSC)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "e97eafd0635651d3999cece953c06bd5" "Cartridge.Name" "M.A.S.H (208 in 1) (Unknown) (PAL)" "" "Cartridge.MD5" "e9be3e8e4a7e73dd63ed4235a3a1a25f" "Cartridge.Name" "MMetall (Hack)" "Cartridge.Note" "Hack of Miniature Golf" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "e9c5d04643855949a23ff29349af74ea" "Cartridge.Name" "SCSIcide (Score Hack 2) (24-02-2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "e9c71f8cdba6037521c9a3c70819d171" "Cartridge.Manufacturer" "Action Hi Tech - Hi-Score" "Cartridge.Name" "Bank Heist (PAL)" "" "Cartridge.MD5" "e9cb18770a41a16de63b124c1e8bd493" "Cartridge.Manufacturer" "Parker Brothers, Joe Gaucher" "Cartridge.ModelNo" "931519" "Cartridge.Name" "Popeye (1983) (Parker Bros) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "e9e646f730b8400cd5da08c849ef3e3b" "Cartridge.Manufacturer" "Tron" "Cartridge.Name" "Enduro (Tron)" "" "Cartridge.MD5" "e9e6ad30549a6e2cd89fe93b7691d447" "Cartridge.Manufacturer" "Atari - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "CX26140, CX26140P" "Cartridge.Name" "Desert Falcon (05-27-1987) (Atari) (Prototype) (PAL)" "Cartridge.Note" "AKA Nile Flyer, Sphinx" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "e9f25c7af4f27c9e1b5b8f6fe6141e8c" "Cartridge.Manufacturer" "Champ Games" "Cartridge.ModelNo" "CG-03-N" "Cartridge.Name" "Scramble (NTSC)" "Cartridge.Note" "Compatible with Genesis controller" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ea38fcfc06ad87a0aed1a3d1588744e4" "Cartridge.Manufacturer" "Atari, Lou Harp" "Cartridge.ModelNo" "CX26122" "Cartridge.Name" "Sinistar (1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ea6d40db5498d6386571a76df448aa4c" "Cartridge.Name" "Vertical Playfield Demo 2 (PD)" "" "Cartridge.MD5" "ea7e25ade3fe68f5b786ee0aa82b1fe5" "Cartridge.Name" "Galatic (208 in 1) (Unknown) (PAL)" "Cartridge.Note" "AKA Challenge of.... Nexar, The" "" "Cartridge.MD5" "ea832e2cb6aae6f525f07452c381fa48" "Cartridge.Name" "Polar to Cartesian and VV (2001) (Roger Williams)" "" "Cartridge.MD5" "ea86176b27ab0da8cce8f0179884bfaa" "Cartridge.Name" "Demo Image Series #10 - It's Art (28-02-2003) (AD)" "" "Cartridge.MD5" "eaacfcdc1d4ee1258429b7ae7f084125" "Cartridge.Manufacturer" "Telegames" "Cartridge.ModelNo" "6057 A227" "Cartridge.Name" "Quest for Quintana Roo (1989) (Telegames)" "Cartridge.Note" "Genesis controller (B is action button, C chooses tool or weapon)" "Cartridge.Rarity" "Hack of Quest for Quintana Roo" "Controller.Left" "GENESIS" "" "Cartridge.MD5" "ead60451c28635b55ca8fea198444e16" "Cartridge.Manufacturer" "Sancho - Tang's Electronic Co." "Cartridge.ModelNo" "TEC004" "Cartridge.Name" "Nightmare (1983) (Sancho) (PAL)" "Display.Height" "256" "" "Cartridge.MD5" "eada0dd61ce13f8317de774dc1e68604" "Cartridge.Name" "2600 Digital Clock (Demo 1) (PD)" "" "Cartridge.MD5" "eae0c06ee61c63b81cd016096fc901b0" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide (v1.0) (2001) (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "eae6a5510055341d3abeb45667bb3e9b" "Cartridge.Manufacturer" "HES" "Cartridge.Name" "Wall Defender (HES) (PAL)" "Cartridge.Note" "AKA Wall Break" "" "Cartridge.MD5" "eaf744185d5e8def899950ba7c6e7bb5" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26172" "Cartridge.Name" "Xenophobe (1991) (Atari)" "" "Cartridge.MD5" "eafe8b40313a65792e88ff9f2fe2655c" "Cartridge.Manufacturer" "Eric Ball" "Cartridge.ModelNo" "ELB004" "Cartridge.Name" "Skeleton+ (NTSC)" "Cartridge.Note" "Stereo sound" "Cartridge.Rarity" "Homebrew" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "eb3d680699f8762f71f38e28e321234d" "Cartridge.Name" "Fu Kung! (V0.01) (08-01-2003) (AD)" "" "Cartridge.MD5" "eb4252faff7a4f2ba5284a98b8f78d1a" "Cartridge.Name" "John K Harvey's Equalizer (NTSC) (PD)" "Cartridge.Rarity" "New Release" "Display.Phosphor" "YES" "" "Cartridge.MD5" "eb46e99ec15858f8cd8c91cef384ce09" "Cartridge.Manufacturer" "Goliath - Hot Shot" "Cartridge.ModelNo" "83-113" "Cartridge.Name" "Ground Zero (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "eb503cc64c3560cd78b7051188b7ba56" "Cartridge.Manufacturer" "Star Game" "Cartridge.ModelNo" "043" "Cartridge.Name" "Moto Laser (Star Game)" "Cartridge.Note" "AKA Mega Force" "" "Cartridge.MD5" "eb634650c3912132092b7aee540bbce3" "Cartridge.Manufacturer" "Atari, Eric Manghise, Mimi Nyden, Joseph Tung" "Cartridge.ModelNo" "CX2640" "Cartridge.Name" "RealSports Baseball (1982) (Atari)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "eb6d6e22a16f30687ade526d7a6f05c5" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26150P" "Cartridge.Name" "Q-bert (1987) (Atari) (PAL)" "" "Cartridge.MD5" "eb71743c6c7ccce5b108fad70a326ad9" "Cartridge.Name" "Euchre (25-11-2001) (Erik Eid) (PD)" "" "Cartridge.MD5" "eb7934360658a29c50aeaff20bfda23b" "Cartridge.Manufacturer" "Activision, John Van Ryzin" "Cartridge.ModelNo" "EAZ-036-04" "Cartridge.Name" "H.E.R.O. (1984) (Activision) (SECAM)" "Display.Format" "SECAM" "" "Cartridge.MD5" "eb92193f06b645df0b2a15d077ce435f" "Cartridge.Manufacturer" "Starpath Corporation, Steve Hales, Stephen H. Landrum" "Cartridge.ModelNo" "4 AR-4102" "Cartridge.Name" "Suicide Mission (1982) (Starpath) (PAL)" "Cartridge.Note" "AKA Meteoroids" "Display.Phosphor" "YES" "" "Cartridge.MD5" "eb9712e423b57f0b07ccd315bb9abf61" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (V2.04) (PAL) (2001) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "eb9f8b84c193d9d93a58fca112aa39ed" "Cartridge.Name" "Register Twiddler Demo (PD)" "" "Cartridge.MD5" "ebcb084a91d41865b2c1915779001ca7" "Cartridge.Manufacturer" "JVP" "Cartridge.Name" "Bob Is Going Home (JVP)" "Cartridge.Note" "AKA Bobby Is Going Home" "" "Cartridge.MD5" "ebcbc8a181a738e13df6216e5c329230" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-022" "Cartridge.Name" "Seaquest (1983) (Activision) (16K)" "" "Cartridge.MD5" "ebd2488dcace40474c1a78fa53ebfadf" "Cartridge.Manufacturer" "Skill Screen Games, Herman Quast" "Cartridge.ModelNo" "SSG001" "Cartridge.Name" "Extra Terrestrials (1984) (SSG)" "Cartridge.Note" "The only Canadian-designed and manufactured Atari 2600 game from the 1980's" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "ebf2dff78a08733251bf3838f02f7938" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype) [a2]" "Cartridge.Rarity" "Prototype" "Display.YStart" "23" "Display.Height" "240" "" "Cartridge.MD5" "ebf9038e927e6a0db3e0d170c59911e6" "Cartridge.Name" "Pac-2600 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ec26fdc87b1d35f1d60ea89cda4f4dd4" "Cartridge.Name" "Star Fire - Crash Scene (04-11-2002) (MP)" "" "Cartridge.MD5" "ec3beb6d8b5689e867bafb5d5f507491" "Cartridge.Manufacturer" "U.S. Games Corporation - Vidtec - JWDA, Todd Marshall, Henry Will IV" "Cartridge.ModelNo" "VC1003" "Cartridge.Name" "Word Zapper (1982) (U.S. Games)" "Cartridge.Note" "AKA Word Grabber" "" "Cartridge.MD5" "ec407a206b718a0a9f69b03e920a0185" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "876.482 1" "Cartridge.Name" "Landung in der Normandie (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Commando Raid" "" "Cartridge.MD5" "ec5c861b487a5075876ab01155e74c6c" "Cartridge.Manufacturer" "Apollo - Games by Apollo, Ed Salvo, Byron Parks" "Cartridge.ModelNo" "AP-2001" "Cartridge.Name" "Spacechase (1982) (Apollo)" "" "Cartridge.MD5" "ece463abde92e8b89bcd867ec71751b8" "Cartridge.Manufacturer" "Puzzy - Bit Corporation" "Cartridge.ModelNo" "PG205" "Cartridge.Name" "Dancing Plate (1982) (Puzzy) (PAL)" "Cartridge.Note" "AKA Dishaster" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ece908d77ab944f7bac84322b9973549" "Cartridge.Name" "Tom Boy (Unknown) (PAL60)" "Cartridge.Note" "AKA Pitfall!" "Display.Format" "PAL60" "" "Cartridge.MD5" "ecf51385384b468834611d44a8429c03" "Cartridge.Manufacturer" "20th Century Fox Video Games, Douglas 'Dallas North' Neubauer" "Cartridge.ModelNo" "11105" "Cartridge.Name" "Mega Force (1982) (20th Century Fox) (PAL)" "" "Cartridge.MD5" "ecfa04523dde82fe42cdc7315a8f61b6" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAG-004, PAG-004 - 711 004-715" "Cartridge.Name" "Fishing Derby (1980) (Activision) (PAL) (4K)" "Cartridge.Note" "AKA Schneller als der Hai" "" "Cartridge.MD5" "ed014beeeb77dbb2bbcf9b5f6850b2f4" "Cartridge.Name" "Green Bar Text Demo (PD)" "" "Cartridge.MD5" "ed0451010d022b96a464febcba70b9c4" "Cartridge.Manufacturer" "PlayAround - J.H.M." "Cartridge.ModelNo" "203" "Cartridge.Name" "Knight on the Town (1982) (PlayAround) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ed0ab909cf7b30aff6fc28c3a4660b8e" "Cartridge.Manufacturer" "Panda" "Cartridge.ModelNo" "105" "Cartridge.Name" "Stunt Man (1983) (Panda)" "Cartridge.Note" "AKA Nightmare" "" "Cartridge.MD5" "ed1306436ce237afc5a7ed3f77134202" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-341" "Cartridge.Name" "2 Pak Special - Dolphin, Pigs 'n' Wolf (1990) (HES) (PAL)" "" "Cartridge.MD5" "ed1492d4cafd7ebf064f0c933249f5b0" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Video Cube (CCE)" "Cartridge.Note" "AKA Atari Video Cube" "" "Cartridge.MD5" "ed1a784875538c7871d035b7a98c2433" "Cartridge.Name" "Save Our Ship (Unknown) (Hack)" "Cartridge.Rarity" "Hack" "Display.YStart" "37" "" "Cartridge.MD5" "ed2218b3075d15eaa34e3356025ccca3" "Cartridge.Manufacturer" "Atari, Richard Maurer" "Cartridge.ModelNo" "CX2635, CX2635P" "Cartridge.Name" "Maze Craze (1980) (Atari) (PAL)" "Cartridge.Note" "AKA A Game of Cops 'n Robbers" "Display.Format" "PAL" "" "Cartridge.MD5" "ed5ccfc93ad4561075436ee42a15438a" "Cartridge.Manufacturer" "Atari, Tom Reuterdahl" "Cartridge.ModelNo" "CX2626, CX2626P" "Cartridge.Name" "Miniature Golf (1979) (Atari) (PAL)" "" "Cartridge.MD5" "ed8f319e82d355832195eb7715644795" "Cartridge.Manufacturer" "Activision, Larry Kaplan, David Crane" "Cartridge.ModelNo" "AG-010, AG-010-04" "Cartridge.Name" "Kaboom! (1981) (Activision) (8K)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "ed9999911b406dc5f75c850dcc17bdf4" "Cartridge.Name" "Star Fire - Shootable (Friendlier Collision Detection) (26-09-2002) (MP)" "" "Cartridge.MD5" "eddef10fdc0029301064115ae0cd41d4" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Freeway (CCE)" "" "Cartridge.MD5" "ede4ab11ca346bd023b2c21d941e0c50" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "EAZ-030" "Cartridge.Name" "Decathlon (1983) (Activision) (SECAM)" "Display.Format" "SECAM" "" "Cartridge.MD5" "ede7e8bf865b0afb4744f86d13624f9a" "Cartridge.Name" "Demo Image Series #2 - Clown (19-02-2003) (AD)" "" "Cartridge.MD5" "edf69b123e06eaf8663cc78d8aeba06e" "Cartridge.Manufacturer" "SpkSoft 98" "Cartridge.Name" "River Raid (SpkSoft 98) [h1]" "" "Cartridge.MD5" "ee28424af389a7f3672182009472500c" "Cartridge.Manufacturer" "Atari, Carol Shaw - Ralph Lauren" "Cartridge.Name" "Polo (1978) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ee456542b93fa8d7e6a8c689b5a0413c" "Cartridge.Name" "Chronocolor Donkey Kong Clean (PD)" "" "Cartridge.MD5" "ee4c186123d31a279ed7a84d3578df23" "Cartridge.Manufacturer" "Atari, Carol Shaw, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX2608" "Cartridge.Name" "Super Breakout (1982 - 1981) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 45" "" "Cartridge.MD5" "ee659ae50e9df886ac4f8d7ad10d046a" "Cartridge.Manufacturer" "Exus Corporation" "Cartridge.Name" "Video Reflex (1983) (Exus)" "Cartridge.Note" "AKA Foot Craz" "" "Cartridge.MD5" "ee6665683ebdb539e89ba620981cb0f6" "Cartridge.Manufacturer" "Coleco" "Cartridge.ModelNo" "2658" "Cartridge.Name" "Berenstain Bears (1983) (Coleco)" "Cartridge.Note" "Uses the KidVid Controller" "Cartridge.Rarity" "Unbelievably Rare" "Display.YStart" "25" "" "Cartridge.MD5" "ee67dc0b01746372d2b983d88f48e24f" "Cartridge.Name" "Scroller Demo (02-01-2003) (CT)" "" "Cartridge.MD5" "ee681f566aad6c07c61bbbfc66d74a27" "Cartridge.Manufacturer" "Activision" "Cartridge.Name" "Unknown Activision Game (10-29-1982) (Activision) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "ee6cbedf6c0aac90faa0a8dbc093ffbe" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "My Golf (CCE) (PAL)" "" "Cartridge.MD5" "ee8027d554d14c8d0b86f94737d2fdcc" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Yars' Revenge (Canal 3)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "ee84bdc5dae268e227e407c7b5e6b6b7" "Cartridge.Name" "Marilyn Monroe Demo (PD)" "" "Cartridge.MD5" "ee9caee4eb958284fb10c277b14537f1" "Cartridge.Manufacturer" "Carrere Video, Garry Kitchen - Teldec" "Cartridge.ModelNo" "USC1001" "Cartridge.Name" "Space Jockey (1983) (Carrere Video) (PAL) (4K)" "Display.YStart" "59" "" "Cartridge.MD5" "eea0da9b987d661264cce69a7c13c3bd" "Cartridge.Manufacturer" "Coleco" "Cartridge.ModelNo" "2454" "Cartridge.Name" "Zaxxon (1983) (Coleco)" "" "Cartridge.MD5" "eeb92f3f46df841487d1504f2896d61a" "Cartridge.Manufacturer" "Cody Pittman" "Cartridge.Name" "Corys Adventure (Cody Pittman) (Hack)" "Cartridge.Note" "Hack of Pac-Man" "Cartridge.Rarity" "Hack" "Display.YStart" "33" "" "Cartridge.MD5" "eec61cc4250df70939d48fe02d7122ac" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAG-005, PAG-005, EAG-005-04B - 711 005-715" "Cartridge.Name" "Skiing (1980) (Activision) (PAL)" "" "Cartridge.MD5" "eed9eaf1a0b6a2b9bc4c8032cb43e3fb" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26192" "Cartridge.Name" "Klax (1991) (Atari) (PAL)" "" "Cartridge.MD5" "eee7695ae3eea7818321df0b790b31f3" "Cartridge.Name" "Sound Paddle V2 (Dennis Caswell & Jim Nitchals) (PD)" "Cartridge.Note" "Uses the Paddle Controllers" "Console.SwapPorts" "YES" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "ef263d40a23483ab339cac44d9515a56" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Fatal Run (TJ)" "Cartridge.Note" "NTSC Conversion" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "ef3a4f64b6494ba770862768caf04b86" "Cartridge.Manufacturer" "Activision, Bob Whitehead" "Cartridge.ModelNo" "AG-034-04" "Cartridge.Name" "Private Eye (1984) (Activision)" "" "Cartridge.MD5" "ef60b06fddb675b0d783afbfa5fc5232" "Cartridge.Name" "Many Blue Bars and Text Demo 4 (PD)" "" "Cartridge.MD5" "ef66af190840871409fe1702d2483554" "Cartridge.Manufacturer" "Andrew Davie, Paul Slocum, Christopher Tumber" "Cartridge.Name" "DiscoTech (12-02-2003) (Andrew Davie)" "" "Cartridge.MD5" "ef71e9fb0d8d477226d8d42261fbf0a7" "Cartridge.Manufacturer" "Piero Cavina" "Cartridge.Name" "Multi-Sprite Demo V2.0 (Piero Cavina) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ef76ea05655a0b62cb1018c92b9b4b7d" "Cartridge.Manufacturer" "Gakken" "Cartridge.ModelNo" "010" "Cartridge.Name" "Strategy X (1983) (Gakken) (PAL)" "" "Cartridge.MD5" "efa1098c7d091b940c2543abe372f036" "Cartridge.Manufacturer" "Scott Stilphen" "Cartridge.Name" "E.T. The Extra-Terrestrial (Scott Stilphen) (Hack)" "Cartridge.Note" "Hack of E.T. The Extra-Terrestrial" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "efb47d70b2965ce689e2c5757616b286" "Cartridge.Name" "Time Test Demo (Eckhard Stolberg) (PAL) (PD)" "" "Cartridge.MD5" "efd387430a35a659ff569a9a0ec22209" "Cartridge.Manufacturer" "Atari - GCC" "Cartridge.ModelNo" "CX26118" "Cartridge.Name" "Millipede (1984) (Atari) (Prototype) (PAL)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "efefc02bbc5258815457f7a5b8d8750a" "Cartridge.Manufacturer" "CBS Electronics, Richard K. Balaska Jr." "Cartridge.ModelNo" "4L 2520 5000" "Cartridge.Name" "Tunnel Runner (1983) (CBS Electronics) [a]" "" "Cartridge.MD5" "efffafc17b7cb01b9ca35324aa767364" "Cartridge.Name" "Circus Atari (Unknown)" "" "Cartridge.MD5" "f02ba8b5292bf3017d10553c9b7b2861" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26172" "Cartridge.Name" "Xenophobe (1991) (Atari) (PAL)" "" "Cartridge.MD5" "f032b2f2d8323404a6b4541f92dd1825" "Cartridge.Name" "Many Blue Bars and Text Demo 3 (PD)" "" "Cartridge.MD5" "f047df70d3d08e331122cd2de61d6af8" "Cartridge.Manufacturer" "Dave Neuman" "Cartridge.Name" "Space Battle (NTSC)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "f04ee80011d95798006378643650aaa7" "Cartridge.Manufacturer" "Atari, Bill Aspromonte, John Russell, Michael Sierchio, Robert Zdybel" "Cartridge.ModelNo" "CX26114" "Cartridge.Name" "Pigs in Space (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "f0536303f49006806bac3aec15738336" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (4 of 4) (1982) (Arcadia)" "" "Cartridge.MD5" "f0541d2f7cda5ec7bab6d62b6128b823" "Cartridge.Manufacturer" "Atari, Paul Donaldson" "Cartridge.Name" "Bionic Breakthrough (1984) (Atari) (Prototype)" "Cartridge.Note" "Uses Mindlink Controller (left only)" "Cartridge.Rarity" "Prototype" "Controller.Left" "MINDLINK" "" "Cartridge.MD5" "f060826626aac9e0d8cda0282f4b7fc3" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2605 - 6-99822, 49-75109" "Cartridge.Name" "Outlaw (1978) (Atari) (4K)" "" "Cartridge.MD5" "f0631c6675033428238408885d7e4fde" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Test Cart (2002) (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f066bea7ab0a37b83c83c924a87c5b67" "Cartridge.Name" "Air Raiders (1982) (Unknown)" "" "Cartridge.MD5" "f0a6e99f5875891246c3dbecbf2d2cea" "Cartridge.Manufacturer" "Atari, James Andreasen - Sears" "Cartridge.ModelNo" "CX2654 - 49-75141" "Cartridge.Name" "Haunted House (1982) (Atari)" "" "Cartridge.MD5" "f0b7db930ca0e548c41a97160b9f6275" "Cartridge.Manufacturer" "Atari, Larry Wagner, Bob Whitehead - Sears" "Cartridge.ModelNo" "CX2645 - 49-75181" "Cartridge.Name" "Video Chess (1979) (Atari)" "Cartridge.Note" "AKA Computer Chess" "" "Cartridge.MD5" "f0cacae1d1b79ee92f0dc035f42e0560" "Cartridge.Name" "Boring Donkey Kong (Hack)" "Cartridge.Note" "Hack of Donkey Kong" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f0d393dbf4164a688b2346770c9bbd12" "Cartridge.Name" "Racquetball (Unknown)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f0daaa966199ef2b49403e9a29d12c50" "Cartridge.Name" "Mr. Postman (Unknown)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "f0e0addc07971561ab80d9abe1b8d333" "Cartridge.Manufacturer" "Imagic, Rob Fulop" "Cartridge.ModelNo" "720000-200, 720101-1B, 720101-1C, IA3200, IA3200C, IX-006-04" "Cartridge.Name" "Demon Attack (1982) (Imagic)" "Cartridge.Note" "AKA Death from Above" "" "Cartridge.MD5" "f10e3f45fb01416c87e5835ab270b53a" "Cartridge.Manufacturer" "Video Game Cartridge - Ariola" "Cartridge.ModelNo" "TP-607" "Cartridge.Name" "Ski Run (Ariola) (PAL)" "" "Cartridge.MD5" "f1127ade54037236e75a133b1dfc389d" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (Preview) (1982) (Arcadia)" "" "Cartridge.MD5" "f11cfab087fcbd930ab8b0becc5b2e5a" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "River Raid (Canal 3)" "" "Cartridge.MD5" "f12afbffa080dd3b2801dd14d4837cf6" "Cartridge.Manufacturer" "Atari, Michael Kosaka, Peter C. Niday, Robert Vieira" "Cartridge.ModelNo" "CX26110" "Cartridge.Name" "Crystal Castles (01-04-1984) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f137211537438b1fce3d811baef25457" "Cartridge.Name" "Incoming (02-10-2002) (Ben Larson) (PD)" "" "Cartridge.MD5" "f1489e27a4539a0c6c8529262f9f7e18" "Cartridge.Manufacturer" "Champ Games" "Cartridge.ModelNo" "CG-01-P" "Cartridge.Name" "Lady Bug (PAL60)" "Cartridge.Rarity" "Homebrew" "Console.RightDifficulty" "A" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f14d5e96ec3380aef57a4b70132c6677" "Cartridge.Manufacturer" "Goliath - Hot Shot" "Cartridge.ModelNo" "83-414" "Cartridge.Name" "Pac Kong (1983) (Goliath) (PAL)" "Cartridge.Note" "AKA Inca Gold" "" "Cartridge.MD5" "f1554569321dc933c87981cf5c239c43" "Cartridge.Manufacturer" "Atari - Glenn Axworthy" "Cartridge.ModelNo" "CX26129" "Cartridge.Name" "Midnight Magic (1986) (Atari)" "Cartridge.Note" "AKA Pinball Wizard" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f16c709df0a6c52f47ff52b9d95b7d8d" "Cartridge.Manufacturer" "Atari, Alan Miller - Sears" "Cartridge.ModelNo" "CX2662 - 6-99811" "Cartridge.Name" "Hangman (1978) (Atari)" "" "Cartridge.MD5" "f1929bb9b5db22d98dd992aa3fe72920" "Cartridge.Name" "Cube Conquest (Improved Interlace) (Billy Eno) (PD)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f19aba18f86e415812480ad2be221425" "Cartridge.Manufacturer" "Chris Larkin" "Cartridge.Name" "Solaris Trainer (2002) (Chris Larkin) (Hack)" "Cartridge.Note" "Hack of Solaris" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f1a0a23e6464d954e3a9579c4ccd01c8" "Cartridge.Manufacturer" "20th Century Fox, Douglas 'Dallas North' Neubauer" "Cartridge.ModelNo" "11006" "Cartridge.Name" "Alien (1982) (20th Century Fox)" "Cartridge.Rarity" "Rare" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f1ae6305fa33a948e36deb0ef12af852" "Cartridge.Manufacturer" "Andreas Dietrich" "Cartridge.Name" "Donkey Kong VCS (2017) (1.0)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f1b2ea568b3e156e3f2849dac83591f6" "Cartridge.Name" "Sprite Demo (1997) (Bob Colbert) (PD)" "" "Cartridge.MD5" "f1b7edff81ceef5af7ae1fa76c8590fc" "Cartridge.Manufacturer" "Atari, Richard Maurer" "Cartridge.ModelNo" "CX2632, CX2632P" "Cartridge.Name" "Space Invaders (1980) (Atari) (PAL)" "" "Cartridge.MD5" "f1beca5a198cf08190487e5c27b8e540" "Cartridge.Name" "Fu Kung! (V0.16) (2003) (AD)" "" "Cartridge.MD5" "f1e375d921858467166e53bcec05803f" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 3 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f1eeeccc4bba6999345a2575ae96508e" "Cartridge.Manufacturer" "Video Gems" "Cartridge.ModelNo" "VG-03" "Cartridge.Name" "Steeplechase (1983) (Video Gems) (PAL)" "Console.RightDifficulty" "A" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f1fe06ebe2900eac4cdd17799389a102" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Sky Diver (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "f20675c8b98518367b9f5b8ee6f7c8ea" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Stampede (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "f20bd756f3990e06c492f53cd0168e68" "Cartridge.Name" "Skeleton+ (03-05-2003) (Eric Ball) (NTSC)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "f21813aa050437f0dbc8479864acec6d" "Cartridge.Name" "Sneak 'n Peek (Unknown) (PAL)" "" "Cartridge.MD5" "f240ba9f8092d2e8a4c7d82c554bf509" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "463.860 7" "Cartridge.Name" "Strahlen der Teufelsvoegel (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Atlantis" "" "Cartridge.MD5" "f280976d69d6e27a48506bd6bad11dcd" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX2664, CX2664P" "Cartridge.Name" "Brain Games (1978) (Atari) (PAL)" "Cartridge.Note" "Uses Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "f283cc294ece520c2badf9da20cfc025" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu" "Cartridge.ModelNo" "CX26104" "Cartridge.Name" "Big Bird's Egg Catch (1983) (Atari) (PAL)" "Cartridge.Note" "Uses Kids/Keypad Controllers" "Cartridge.Rarity" "Rare" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "f28c07767b3e90a2689ade5b5e305874" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.ModelNo" "C 3014" "Cartridge.Name" "Keystone Kapers (Canal 3)" "" "Cartridge.MD5" "f2d40c70cf3e1d03bc112796315888d9" "Cartridge.Manufacturer" "Atari - CCW, Michael Callahan, Preston Stuart" "Cartridge.ModelNo" "CX26103" "Cartridge.Name" "Alpha Beam with Ernie (1983) (Atari) (PAL)" "Cartridge.Note" "Uses Keypad Controllers" "Cartridge.Rarity" "Rare" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "f2d4d6187903cac2d5ea8ed90dad120d" "Cartridge.Manufacturer" "Digimax" "Cartridge.Name" "River Raid II (Digimax)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "f2e4fb2d3600c0f76d05864e658cc57b" "Cartridge.Name" "Marble Craze (Kernel) (17-02-2002) (Paul Slocum)" "" "Cartridge.MD5" "f2f2cb35fdef063c966c1f5481050ea2" "Cartridge.Name" "Ram It (Unknown) (PAL)" "" "Cartridge.MD5" "f2f59629d7341c97644405daeac08845" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Bobby Is Going Home (Jone Yuan)" "Cartridge.Note" "2600 Screen Search Console" "" "Cartridge.MD5" "f303630a2d7316787aecd67fff6b2e33" "Cartridge.Manufacturer" "AtariAge - Fred Quimby" "Cartridge.Name" "Gingerbread Man (Fred Quimby)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f3213a8a702b0646d2eaf9ee0722b51c" "Cartridge.Manufacturer" "Atari, Carol Shaw - Sears" "Cartridge.ModelNo" "CX2618 - 49-75123" "Cartridge.Name" "3-D Tic-Tac-Toe (1980) (Atari) (4K)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "f33f1d0f7819c74148dacb48cbf1c597" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.00) (Retroactive) (Stella)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f344ac1279152157d63e64aa39479599" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-012" "Cartridge.Name" "Espial (1984) (Tigervision)" "" "Cartridge.MD5" "f34dd3b8156aaf113cb621b2e51d90b8" "Cartridge.Manufacturer" "Joe Grand" "Cartridge.Name" "SCSIcide Pre-release 5 (Joe Grand)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f34f08e5eb96e500e851a80be3277a56" "Cartridge.Manufacturer" "Atari, Brad Stewart - Sears" "Cartridge.ModelNo" "CX2622 - 6-99813, 49-75107" "Cartridge.Name" "Breakout (1978) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 60" "" "Cartridge.MD5" "f367e58667a30e7482175809e3cec4d4" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "708-111 - GN-040" "Cartridge.Name" "Cosmic Corridor (1983) (ZiMAG)" "Display.Height" "220" "" "Cartridge.MD5" "f38358cd8f5ecfedffd5aca1aa939f18" "Cartridge.Manufacturer" "Universal Gamex Corporation, Alan Roberts" "Cartridge.ModelNo" "1005" "Cartridge.Name" "X-Man (1983) (Universal) [a]" "Display.YStart" "30" "" "Cartridge.MD5" "f39e4bc99845edd8621b0f3c7b8c4fd9" "Cartridge.Manufacturer" "AtariAge" "Cartridge.Name" "Toyshop Trouble (AtariAge)" "Cartridge.Note" "F8 Emulator Release" "Controller.Right" "PADDLES" "Display.YStart" "32" "" "Cartridge.MD5" "f3c431930e035a457fe370ed4d230659" "Cartridge.Name" "Crackpots (Unknown) (PAL)" "" "Cartridge.MD5" "f3cd0f886201d1376f3abab2df53b1b9" "Cartridge.Manufacturer" "Commavid, Ben Burch" "Cartridge.ModelNo" "CM-010" "Cartridge.Name" "Rush Hour (1983) (Commavid) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "f3dfae774f3bd005a026e29894db40d3" "Cartridge.Manufacturer" "Otto Versand" "Cartridge.ModelNo" "649635" "Cartridge.Name" "See Saw (Double-Game Package) (1983) (Otto Versand) (PAL)" "Cartridge.Note" "AKA Circus Atari" "" "Cartridge.MD5" "f3f5f72bfdd67f3d0e45d097e11b8091" "Cartridge.Manufacturer" "Sears Tele-Games, Marilyn Churchill, Matthew L. Hubbard" "Cartridge.ModelNo" "CX2647 - 49-75142" "Cartridge.Name" "Submarine Commander (1982) (Sears)" "Cartridge.Note" "AKA Seawolf 3" "" "Cartridge.MD5" "f3f92aad3a335f0a1ead24a0214ff446" "Cartridge.Name" "Spectrum Color Demo (PD)" "" "Cartridge.MD5" "f4204fc92d17ed4cb567c40361ad58f1" "Cartridge.Manufacturer" "Inky" "Cartridge.Name" "Beanie Baby Bash (Inky) (Hack)" "Cartridge.Note" "Hack of Beany Bopper" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f4469178cd8998cb437fa110a228eaca" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Frostbite (1983) (Digitel)" "" "Cartridge.MD5" "f45644ff82b533a781a1ee50f2e95f3c" "Cartridge.Name" "Overhead Adventure Demo 6 (PD)" "" "Cartridge.MD5" "f457674cef449cfd85f21db2b4f631a7" "Cartridge.Manufacturer" "U.S. Games Corporation - JWDA, Todd Marshall, Wes Trager, Henry Will IV" "Cartridge.ModelNo" "VC1004" "Cartridge.Name" "Commando Raid (1982) (U.S. Games)" "" "Cartridge.MD5" "f473f99e47d4026a7a571184922ebf04" "Cartridge.Manufacturer" "Philip R. Frey" "Cartridge.Name" "Donkey Claus (Philip R. Frey) (Hack)" "Cartridge.Note" "Hack of Donkey Kong" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f48022230bb774a7f22184b48a3385af" "Cartridge.Manufacturer" "Atari, Rob Fulop - Sears" "Cartridge.ModelNo" "CX2633 - 49-75119" "Cartridge.Name" "Night Driver (1980) (Atari) (4K)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 65" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f48735115ec302ba8bb2d2f3a442e814" "Cartridge.Name" "Dishaster (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f49a34f1fdd7dc147cbf96ce2ce71b76" "Cartridge.Name" "Qb (Special Edition) (PAL) (Retroactive)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f4ab6bd5f80d8988141edde4c84b23b5" "Cartridge.Manufacturer" "Atari, Alan Miller" "Cartridge.ModelNo" "CX2624, CX2624P" "Cartridge.Name" "Basketball (1978) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "f4b8a47a95b61895e671c3ec86ffd461" "Cartridge.Manufacturer" "Parker Brothers, Wilfredo Aguilar, Michael Becker, Neil McKenzie, Bob Smith, Brad Stewart" "Cartridge.ModelNo" "PB5540" "Cartridge.Name" "Star Wars - The Arcade Game (01-03-1984) (Parker Bros) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f4c2e50b01dff99bddbe037b3489511c" "Cartridge.Name" "Hypnotic (V0.04) (2001) (Inkling) (PD)" "" "Cartridge.MD5" "f4c6621f1a0b4d27081123c08d7d1497" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-838" "Cartridge.Name" "Immies & Aggies (1983) (CCE)" "" "Cartridge.MD5" "f4cf6881b65c424095dc25dc987f151f" "Cartridge.Name" "128 in 1 Game Select ROM (Unknown)" "" "Cartridge.MD5" "f4dabd5bcc603e8464a478208037d423" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (08-21-1984) (Coleco) (Prototype)" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "f526d0c519f5001adb1fc7948bfbb3ce" "Cartridge.Manufacturer" "Mythicon, Bill Bryner, Bruce de Graaf" "Cartridge.ModelNo" "MA1003" "Cartridge.Name" "Star Fox (1983) (Mythicon)" "" "Cartridge.MD5" "f52f40299fd238c6ffd9e6107050dc76" "Cartridge.Manufacturer" "Activision, Bob Whitehead - Ariola" "Cartridge.ModelNo" "EAG-011, PAG-011 - 711 011-715" "Cartridge.Name" "Stampede (1981) (Activision) (PAL) (4K)" "" "Cartridge.MD5" "f539e32bf6ce39c8ca47cb0cdd2c5cb8" "Cartridge.Manufacturer" "Control Video Corporation" "Cartridge.Name" "GameLine Master Module ROM (1983) (Control Video)" "" "Cartridge.MD5" "f542b5d0193a3959b54f3c4c803ba242" "Cartridge.Manufacturer" "Atari, Tom Rudadahl - Sears" "Cartridge.ModelNo" "CX2634 - 49-75121" "Cartridge.Name" "Golf (1980) (Atari) (4K)" "" "Cartridge.MD5" "f5445b52999e229e3789c39e7ee99947" "Cartridge.Manufacturer" "Atari, Jim Huether" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Flag Capture (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "f5a2f6efa33a3e5541bc680e9dc31d5b" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-022" "Cartridge.Name" "Motocross (Suntek) (PAL)" "" "Cartridge.MD5" "f5a3e051730d45fea518f2e8b926565b" "Cartridge.Manufacturer" "Robby" "Cartridge.Name" "Keystone Kapers (Robby)" "" "Cartridge.MD5" "f5aa6bd10f662199c42e43863a30106c" "Cartridge.Name" "Music Kit (V1.0) - Song Player (Paul Slocum)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f5d103a9ae36d1d4ee7eef657b75d2b3" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "9 AR-4105" "Cartridge.Name" "Official Frogger, The (Preview) (1983) (Starpath)" "Display.YStart" "30" "" "Cartridge.MD5" "f613aad84d2163d6b197b220bfec1b7e" "Cartridge.Name" "X-Doom V.27 (PD)" "" "Cartridge.MD5" "f661f129644f338b13d9f4510d816c03" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Outlaw (32 in 1) (1988) (Atari) (PAL) (4K)" "" "Cartridge.MD5" "f6676e3fe901eb8515fc7ae310302c3c" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.ModelNo" "AG-008" "Cartridge.Name" "Laser Blast (1981) (Activision) (8K)" "" "Cartridge.MD5" "f67181b3a01b9c9159840b15449b87b0" "Cartridge.Manufacturer" "Atari, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX2665" "Cartridge.Name" "Frog Pond (08-27-1982) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "f687ec4b69611a7f78bd69b8a567937a" "Cartridge.Manufacturer" "Activision, Alan Miller - Ariola" "Cartridge.ModelNo" "EAZ-028 - 711 028-725" "Cartridge.Name" "Robot Tank (1983) (Activision) (PAL)" "" "Cartridge.MD5" "f69a39b215852a0c2764d2a923c1e463" "Cartridge.Name" "Move a Blue Blob Demo 2 (PD)" "" "Cartridge.MD5" "f69bb58b815a6bdca548fa4d5e0d5a75" "Cartridge.Manufacturer" "Atari, Larry Kaplan" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Bowling (32 in 1) (1988) (Atari) (PAL)" "" "Cartridge.MD5" "f69d4fcf76942fcd9bdf3fd8fde790fb" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Aquaventure (CCE)" "" "Cartridge.MD5" "f6a282374441012b01714e19699fc62a" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "710-111 - GN-010" "Cartridge.Name" "I Want My Mommy (1983) (ZiMAG)" "Display.YStart" "30" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f6a9ea814d15b85bffe980c927df606b" "Cartridge.Name" "Missile Command (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f6b5ebb65cbb2981af4d546c470629d7" "Cartridge.Manufacturer" "Coleco - Individeo, Ed Temple" "Cartridge.Name" "Cabbage Patch Kids (09-13-1984) (Coleco) (Prototype) [a]" "Cartridge.Note" "Adventures in the Park" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "f6c13e816e58c8c62f82b2c8b91a2d67" "Cartridge.Name" "Scrolling Playfield 2 (Junkosoft) (PD)" "" "Cartridge.MD5" "f6d512bef1bf253dc935d0e13c3d1462" "Cartridge.Name" "Slot Racers (Unknown) (PAL) (4K)" "" "Cartridge.MD5" "f6daebc0424fa0f8d9aaf26c86df50f4" "Cartridge.Manufacturer" "Brian Watson" "Cartridge.Name" "Color Tweaker (V1.0) (2001) (B. Watson)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "f6efa00ae99aaf33e427b674bcfd834d" "Cartridge.Name" "2600 Digital Clock (Demo 3) (PD)" "" "Cartridge.MD5" "f6f1b27efc247a0e8d473ddb4269ff9e" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "429.663 8" "Cartridge.Name" "Schnapp die Apfeldiebe (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Plaque Attack" "" "Cartridge.MD5" "f70e3f3bb2d19ec2aaec8f78dc43744f" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Pooyan (Jone Yuan) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "Display.Height" "215" "" "Cartridge.MD5" "f714a223954c28eccf459295517dcae6" "Cartridge.Name" "Big - Move This Demo (PD)" "" "Cartridge.MD5" "f724d3dd2471ed4cf5f191dbb724b69f" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Howard Scott Warshaw" "Cartridge.ModelNo" "CX2659" "Cartridge.Name" "Raiders of the Lost Ark (1982) (Atari)" "Cartridge.Note" "Console ports are swapped" "Console.SwapPorts" "YES" "" "Cartridge.MD5" "f736864442164b29235e8872013180cd" "Cartridge.Manufacturer" "Telegames - VSS" "Cartridge.ModelNo" "6057 A227" "Cartridge.Name" "Quest for Quintana Roo (1988) (Telegames) (PAL)" "" "Cartridge.MD5" "f73d2d0eff548e8fc66996f27acf2b4b" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-813" "Cartridge.Name" "Pitfall (1983) (CCE)" "" "Cartridge.MD5" "f7424985bac41067502b4a05b64cb75a" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-027" "Cartridge.Name" "Plaque Attack (1983) (Activision)" "Cartridge.Note" "Genesis controller (B is fire up, C is fire down)" "Cartridge.Rarity" "Hack of Plaque Attack" "Controller.Left" "GENESIS" "Controller.Right" "GENESIS" "" "Cartridge.MD5" "f74ad642552385c3daa203a2a6fc2291" "Cartridge.Manufacturer" "Eckhard Stolberg" "Cartridge.Name" "Cubis (1997) (Eckhard Stolberg)" "Cartridge.Rarity" "New Release" "Display.YStart" "20" "" "Cartridge.MD5" "f750b5d613796963acecab1690f554ae" "Cartridge.Manufacturer" "Manuel Polik" "Cartridge.Name" "Gunfight 2600 (MP)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f75872946e82ad74d48eae5bc28f5f0e" "Cartridge.Manufacturer" "Sears Tele-Games, Jim Huether" "Cartridge.ModelNo" "CX2614 - 49-75126" "Cartridge.Name" "Steeplechase (04-15-1980) (Sears) (Prototype)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "Prototype" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "" "Cartridge.MD5" "f777444fc21a5925e066b68b1d350575" "Cartridge.Name" "Marble Craze (Kernel Works) (Paul Slocum)" "" "Cartridge.MD5" "f77f5fc3893da5d00198e4cd96544aad" "Cartridge.Manufacturer" "Canal 3 - Intellivision" "Cartridge.Name" "Stampede (Canal 3)" "" "Cartridge.MD5" "f7856e324bc56f45b9c8e6ff062ec033" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Michael Sierchio" "Cartridge.ModelNo" "CX2667" "Cartridge.Name" "RealSports Soccer (1983) (Atari) [no opening tune]" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f78c125b5da483c41e51522947d6c4ce" "Cartridge.Name" "Sound Paddle V1 (Dennis Caswell & Jim Nitchals) (PD)" "Cartridge.Note" "Uses the Paddle Controllers" "Console.SwapPorts" "YES" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01" "" "Cartridge.MD5" "f7a138eed69665b5cd1bfa796a550b01" "Cartridge.Manufacturer" "Tigervision - Teldec" "Cartridge.ModelNo" "7-012 - 3.60016 VC" "Cartridge.Name" "Espial (1984) (Tigervision) (PAL)" "" "Cartridge.MD5" "f7a651972d78f9ba485b14690452d4be" "Cartridge.Manufacturer" "Paul Slocum" "Cartridge.Name" "Homestar Runner Demo #2 (2004-03-29)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f7af41a87533524d9a478575b0d873d0" "Cartridge.Manufacturer" "Quelle" "Cartridge.ModelNo" "495.663 7" "Cartridge.Name" "Spiderman (1983) (Quelle) (PAL)" "Cartridge.Note" "AKA Spider-Man" "" "Cartridge.MD5" "f7d6592dcb773c81c278140ed4d01669" "Cartridge.Manufacturer" "Activision, David Crane, Dan Kitchen" "Cartridge.ModelNo" "EAG-108-04, EAZ-108-04B" "Cartridge.Name" "Ghostbusters (1985) (Activision) (PAL)" "" "Cartridge.MD5" "f7e07080ed8396b68f2e5788a5c245e2" "Cartridge.Manufacturer" "Video Game Cartridge - Ariola" "Cartridge.ModelNo" "TP-617" "Cartridge.Name" "Farmyard Fun (Ariola)" "Cartridge.Note" "AKA Play Farm" "Display.Height" "215" "" "Cartridge.MD5" "f7f50d9c9d28bcc9f7d3075668b7ac89" "Cartridge.Manufacturer" "Activision, David Crane - Ariola" "Cartridge.ModelNo" "EAG-008, PAG-008, EAG-008-04I - 711 008-720" "Cartridge.Name" "Laser Blast (1981) (Activision) (PAL) (4K)" "" "Cartridge.MD5" "f7fac15cf54b55c5597718b6742dbec2" "Cartridge.Manufacturer" "Spiceware" "Cartridge.ModelNo" "SW-01" "Cartridge.Name" "Medieval Mayhem (NTSC)" "Cartridge.Rarity" "Homebrew" "Cartridge.Sound" "STEREO" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "AUTO 55" "" "Cartridge.MD5" "f802fa61011dd9eb6f80b271bac479d0" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-023" "Cartridge.Name" "Mole Hunter (Suntek) (PAL)" "Cartridge.Note" "AKA Topy" "" "Cartridge.MD5" "f80cf77164079d774b9b0fae33dffca9" "Cartridge.Name" "Fu Kung! (V0.15) (Negative Version) (05-02-2003) (AD)" "" "Cartridge.MD5" "f8240e62d8c0a64a61e19388414e3104" "Cartridge.Manufacturer" "Activision, Steve Cartwright" "Cartridge.ModelNo" "AX-013" "Cartridge.Name" "Barnstorming (1982) (Activision)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "f825c538481f9a7a46d1e9bc06200aaf" "Cartridge.Manufacturer" "Atari, Richard Maurer - Sears" "Cartridge.ModelNo" "CX2635 - 49-75157" "Cartridge.Name" "Maze Craze (1980) (Atari)" "Cartridge.Note" "AKA A Game of Cops 'n Robbers" "Display.Format" "NTSC" "" "Cartridge.MD5" "f844f4c6f3baaaf5322657442d6f29eb" "Cartridge.Manufacturer" "Atari, Sam Comstock, Richard Dobbis, Nick 'Sandy Maiwald' Turner" "Cartridge.ModelNo" "CX26111" "Cartridge.Name" "Snoopy and the Red Baron (1983) (Atari) (PAL)" "" "Cartridge.MD5" "f847fb8dba6c6d66d13724dbe5d95c4d" "Cartridge.Manufacturer" "Absolute Entertainment, David Crane" "Cartridge.ModelNo" "AG-042-02, AG-042-04" "Cartridge.Name" "Skate Boardin' (1987) (Absolute)" "" "Cartridge.MD5" "f8582bc6ca7046adb8e18164e8cecdbc" "Cartridge.Name" "Panda Chase (Unknown) (PAL)" "Display.Height" "256" "" "Cartridge.MD5" "f8648d0c6ad1266434f6c485ff69ec40" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Oink! (CCE)" "" "Cartridge.MD5" "f8811d45a9935cca90c62f924712f8e6" "Cartridge.Manufacturer" "Jone Yuan Telephonic Enterprise Co" "Cartridge.Name" "Chopper Command (Jone Yuan) (Hack)" "Cartridge.Note" "2600 Screen Search Console" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f8b2a6a4d73ebff10d805a9b59041986" "Cartridge.Manufacturer" "Activision, Larry Kaplan - Ariola" "Cartridge.ModelNo" "EAX-006, PAX-006 - 771 006-720" "Cartridge.Name" "Bridge (1980) (Activision) (PAL)" "" "Cartridge.MD5" "f8bfd99163d2c4ec688357786e6fba28" "Cartridge.Name" "Eckhard Stolberg's Scrolling Text Demo 2 (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f8c1c4a41303bd40b0d6c81bfaf8573b" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "773-891" "Cartridge.Name" "2 Pak Special - Dungeon Master, Creature Strike (1992) (HES) (PAL)" "" "Cartridge.MD5" "f8ff34b53d86f55bd52d7a520af6d1dc" "Cartridge.Name" "Big Dig (04-04-2003) (CT)" "Display.Height" "220" "" "Cartridge.MD5" "f90b5da189f24d7e1a2117d8c8abc952" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2653 - 6-99823, 49-75111" "Cartridge.Name" "Slot Machine (1979) (Atari)" "" "Cartridge.MD5" "f91fb8da3223b79f1c9a07b77ebfa0b2" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Nick 'Sandy Maiwald' Turner - Sears" "Cartridge.ModelNo" "CX2615 - 49-75140" "Cartridge.Name" "Demons to Diamonds (1982) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10 57" "" "Cartridge.MD5" "f93d7fee92717e161e6763a88a293ffa" "Cartridge.Manufacturer" "20th Century Fox Video Games - Lazer Micro Systems - Dunhill Electronics, B. Winston Hendrickson, Randall Hyde, Mark V. Rhoads, John Simonds" "Cartridge.ModelNo" "11013" "Cartridge.Name" "Porky's (1983) (20th Century Fox)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "f9420173efcb4b9f2b01c2a7b595cca7" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Laser Blast (CCE) (4K)" "" "Cartridge.MD5" "f954381f9e0f2009d1ac40dedd777b1a" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Robot City (V0.18) (01-09-2002) (TJ)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f9655ed51462ecfc690c7b97cec649f9" "Cartridge.Manufacturer" "Andrew Wallace" "Cartridge.Name" "Laseresal 2002 (PAL) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "f965cc981cbb0822f955641f8d84e774" "Cartridge.Manufacturer" "Answer Software Corporation - TY Associates" "Cartridge.ModelNo" "ASC2001" "Cartridge.Name" "Confrontation (1983) (Answer) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Height" "220" "Display.Phosphor" "YES" "" "Cartridge.MD5" "f9660ebed66fee8bdfdf07b4faa22941" "Cartridge.Manufacturer" "VGS" "Cartridge.Name" "Vanguard (VGS)" "" "Cartridge.MD5" "f9677b2ec8728a703eb710274474613d" "Cartridge.Manufacturer" "Atari, Ian Shepard" "Cartridge.ModelNo" "CX2604, CX2604P" "Cartridge.Name" "Space War (1978) (Atari) (PAL)" "" "Cartridge.MD5" "f97dee1aa2629911f30f225ca31789d4" "Cartridge.Manufacturer" "Avalon Hill, Jean Baer, Bill 'Rebecca Ann' Heineman, Jim Jacob" "Cartridge.ModelNo" "5005002" "Cartridge.Name" "Out of Control (1983) (Avalon Hill)" "Display.Height" "216" "" "Cartridge.MD5" "f98d2276d4a25b286135566255aea9d0" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "Name This Game (1983) (Digitel)" "" "Cartridge.MD5" "f98d869f287d2ce4f8fb36e0686929d9" "Cartridge.Name" "Skeleton+ (17-04-2003) (Eric Ball) (NTSC)" "Cartridge.Sound" "STEREO" "" "Cartridge.MD5" "f992a39b46aa48188fab12ad3809ae4a" "Cartridge.Name" "Sky Jinks (Unknown) (PAL) (Hack)" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "f9967369943209b4788d4e92cefc0795" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Fishing (32 in 1) (1988) (Atari) (PAL) (4K)" "Cartridge.Note" "AKA Fishing Derby" "" "Cartridge.MD5" "f9cef637ea8e905a10e324e582dd39c2" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Private Eye (CCE)" "" "Cartridge.MD5" "f9d51a4e5f8b48f68770c89ffd495ed1" "Cartridge.Manufacturer" "Atari, Tod Frye, Mimi Nyden" "Cartridge.ModelNo" "CX2657" "Cartridge.Name" "SwordQuest - FireWorld (1982) (Atari)" "Cartridge.Note" "AKA Adventure II, SwordQuest II - FireWorld" "" "Cartridge.MD5" "f9da42f91a1c5cfa344d2ff440c6f8d4" "Cartridge.Manufacturer" "ZUT" "Cartridge.Name" "Pac Invaders (ZUT)" "" "Cartridge.MD5" "f9de91d868d6ebfb0076af9063d7195e" "Cartridge.Name" "Maze Demo 2 (PD)" "" "Cartridge.MD5" "f9e99596345a84358bc5d1fbe877134b" "Cartridge.Manufacturer" "Activision, Larry Kaplan, David Crane - Ariola" "Cartridge.ModelNo" "EAG-010, PAG-010 - 711 010-720" "Cartridge.Name" "Kaboom! (1981) (Activision) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "01 50" "" "Cartridge.MD5" "fa0570561aa80896f0ead05c46351389" "Cartridge.Manufacturer" "Tigervision" "Cartridge.ModelNo" "7-008" "Cartridge.Name" "Miner 2049er (1983) (Tigervision)" "Display.YStart" "28" "Display.Height" "214" "" "Cartridge.MD5" "fa1b060fd8e0bca0c2a097dcffce93d3" "Cartridge.Manufacturer" "Atari - CCW, Christopher H. Omarzu, Preston Stuart, Bruce Williams" "Cartridge.ModelNo" "CX26101" "Cartridge.Name" "Oscar's Trash Race (1984) (Atari)" "Cartridge.Note" "Uses the Keypad Controllers" "Controller.Left" "KEYBOARD" "Controller.Right" "KEYBOARD" "" "Cartridge.MD5" "fa2be8125c3c60ab83e1c0fe56922fcb" "Cartridge.Manufacturer" "Camelot - DSD, Michael Doherty, Clyde Hager - Johnson & Johnson" "Cartridge.Name" "Tooth Protectors (1983) (Camelot)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fa3de71841c0841db6a741884a6b6b2f" "Cartridge.Name" "Warring Worms (17-02-2002) (Billy Eno)" "" "Cartridge.MD5" "fa4404fabc094e3a31fcd7b559cdd029" "Cartridge.Manufacturer" "Atari, Alan J. Murphy, Robert C. Polaro" "Cartridge.ModelNo" "CX26100" "Cartridge.Name" "Bugs Bunny (1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "fa529ec88eca679f6d5fd0ccb2120e46" "Cartridge.Name" "20 Sprites at Once Demo 1 (PD)" "" "Cartridge.MD5" "fa6fe97a10efb9e74c0b5a816e6e1958" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "707-111 - GN-030" "Cartridge.Name" "Tanks But No Tanks (1983) (ZiMAG)" "Cartridge.Note" "AKA Phantom Tank" "" "Cartridge.MD5" "fa73f3c77ba76763e00e12d5458b6c5d" "Cartridge.Manufacturer" "Probe 2000, Roger Booth, Todd Marshall, Robbin Daniels, Jim Wickstead" "Cartridge.ModelNo" "3152VC" "Cartridge.Name" "Pursuit of the Pink Panther (Probe) (Prototype)" "Cartridge.Note" "AKA Adventures of the Pink Panther" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "fa7ce62e7fd77e02b3e2198d70742f80" "Cartridge.Manufacturer" "Atari, Peter C. Niday" "Cartridge.ModelNo" "CX26108" "Cartridge.Name" "Donald Duck's Speedboat (04-18-1983) (Atari) (Prototype) (PAL)" "Cartridge.Note" "AKA Donald Duck's Regatta" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "fa7e11a3dbea4365975cd2f094e61d25" "Cartridge.Manufacturer" "Tim Snider" "Cartridge.Name" "Mystery Science Theater 2600 (1999) (Tim Snider) (Hack)" "Cartridge.Note" "Hack of Megamania" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "fa98d48cd609c9babc819e0a1bd8d598" "Cartridge.Manufacturer" "AtariAge (Chris Walton)" "Cartridge.Name" "Juno First (2009) (PAL60)" "Cartridge.Note" "AtariVox supported" "Cartridge.Rarity" "Homebrew" "Controller.Right" "ATARIVOX" "Display.Format" "PAL60" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fabca526d57de46768b392f758f1a008" "Cartridge.Name" "Laseresal 2600 (16-12-2001) (Andrew Wallace) (PD)" "" "Cartridge.MD5" "fac28963307b6e85082ccd77c88325e7" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Berzerk (CCE)" "" "Cartridge.MD5" "fadb89f9b23beb4d43a7895c532757e2" "Cartridge.Manufacturer" "Galaga Games" "Cartridge.Name" "River Raid (1984) (Galaga Games) (PAL)" "" "Cartridge.MD5" "fae0b86934a7c5a362281dffebdb43a0" "Cartridge.Manufacturer" "Retroactive" "Cartridge.Name" "Qb (2.07) (Retroactive) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "faebcb2ef1f3831b2fc1dbd39d36517c" "Cartridge.Manufacturer" "Atari, Jerome Domurat, Steve Woita" "Cartridge.ModelNo" "CX2696" "Cartridge.Name" "Asterix (1984) (Atari) (PAL)" "Cartridge.Note" "AKA Taz" "Cartridge.Rarity" "Extremely Rare" "" "Cartridge.MD5" "faed2ef6b44894f8c83f2b50891c35c6" "Cartridge.Manufacturer" "CCE" "Cartridge.Name" "Super Baseball (CCE)" "Cartridge.Note" "AKA RealSports Baseball" "" "Cartridge.MD5" "faffd84f3a8eceee2fa5ea5b0a3e6678" "Cartridge.Manufacturer" "Suntek" "Cartridge.ModelNo" "SS-025" "Cartridge.Name" "Spectracube Invasion (Suntek) (PAL)" "Cartridge.Note" "AKA Immies & Aggies" "" "Cartridge.MD5" "fb09ee4ccd47ae74a3c314f0d8a40344" "Cartridge.Name" "Titans (SnailSoft)" "" "Cartridge.MD5" "fb0c32ef7af5b45486db663510094be8" "Cartridge.Name" "Demo Image Series #15 - Three Marios (NTSC) (Non-Interleave) (06-03-2003) (AD)" "" "Cartridge.MD5" "fb0e84cee4c108d24253bcb7e382cffd" "Cartridge.Name" "Interleaved ChronoColour Demo (SECAM) (05-03-2003) (AD)" "" "Cartridge.MD5" "fb27afe896e7c928089307b32e5642ee" "Cartridge.Manufacturer" "M Network - APh Technological Consulting, Jeff Ronne, Brett Stutz - INTV" "Cartridge.ModelNo" "MT5662" "Cartridge.Name" "TRON - Deadly Discs (1983) (M Network)" "" "Cartridge.MD5" "fb4ca865abc02d66e39651bd9ade140a" "Cartridge.Manufacturer" "Arcadia Corporation, Brian McGhie" "Cartridge.ModelNo" "AR-4104" "Cartridge.Name" "Rabbit Transit (1983) (Arcadia)" "" "Cartridge.MD5" "fb531febf8e155328ec0cd39ef77a122" "Cartridge.Name" "Worm War I (208 in 1) (Unknown) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fb5c8af97bd8ffe88323656f462645a7" "Cartridge.Name" "Interlace Demo (Glenn Saunders)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fb833ed50c865a9a505a125fc9d79a7e" "Cartridge.Manufacturer" "ITT Family Games" "Cartridge.Name" "Pumuckl I (1983) (ITT Family Games) (PAL)" "Cartridge.Note" "AKA Panda Chase" "Display.Height" "220" "" "Cartridge.MD5" "fb884ffd89013331a6f01ae3f6abd214" "Cartridge.Manufacturer" "Activision, David Crane" "Cartridge.Name" "Venetian Blinds Demo (1982) (Activision) (PAL)" "" "Cartridge.MD5" "fb88c400d602fe759ae74ef1716ee84e" "Cartridge.Manufacturer" "20th Century Fox Video Games, Bill Aspromonte" "Cartridge.ModelNo" "11031" "Cartridge.Name" "Crash Dive (1983) (20th Century Fox)" "Cartridge.Note" "AKA Voyage to the Bottom of the Sea" "" "Cartridge.MD5" "fb91da78455d9b1606913fbf8c859772" "Cartridge.Name" "Split Screen (Ballblazer) Demo (PD)" "" "Cartridge.MD5" "fb91dfc36cddaa54b09924ae8fd96199" "Cartridge.Manufacturer" "Parker Brothers, Mark Lesser" "Cartridge.ModelNo" "PB5590" "Cartridge.Name" "Frogger II (1984) (Parker Bros) (PAL)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fbac6476e7b2b20d246202af81662c88" "Cartridge.Manufacturer" "Starpath Corporation, Stephen H. Landrum" "Cartridge.ModelNo" "AR-4400" "Cartridge.Name" "Dragonstomper (Preview) (1982) (Starpath) (PAL)" "" "Cartridge.MD5" "fbb0151ea2108e33b2dbaae14a1831dd" "Cartridge.Manufacturer" "Thomas Jentzsch" "Cartridge.Name" "Robot Tank TV (Thomas Jentzsch) (Hack)" "Cartridge.Note" "Uses two simultaneous Joystick Controllers, Hack of Robot Tank" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "fbb4f3debf48dc961b559384467f2057" "Cartridge.Manufacturer" "Digitel" "Cartridge.Name" "River Raid III (1985) (Digitel)" "Cartridge.Note" "AKA River Raid" "" "Cartridge.MD5" "fbd6102e17a5c02c6e1911381b7203f9" "Cartridge.Name" "Star Fire - Warping!! (10-04-2003) (MP)" "" "Cartridge.MD5" "fbe554aa8f759226d251ba6b64a9cce4" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, Brad Rice" "Cartridge.ModelNo" "CX2681, CX2681P" "Cartridge.Name" "Battlezone (1983) (Atari) (PAL)" "Cartridge.Rarity" "Uncommon" "" "Cartridge.MD5" "fbfebee9c14694719e3eda4854dc42ee" "Cartridge.Manufacturer" "Jake Patterson" "Cartridge.Name" "Baubles 3 (Jake Patterson) (PD)" "Cartridge.Rarity" "Homebrew" "" "Cartridge.MD5" "fc2104dd2dadf9a6176c1c1c8f87ced9" "Cartridge.Manufacturer" "Coleco - Woodside Design Associates, Harley H. Puthuff Jr." "Cartridge.ModelNo" "2663" "Cartridge.Name" "Time Pilot (1983) (Coleco)" "" "Cartridge.MD5" "fc2233fc116faef0d3c31541717ca2db" "Cartridge.Manufacturer" "Atari, Tod Frye" "Cartridge.ModelNo" "CX2646" "Cartridge.Name" "Pac-Man (1982) (Atari) (PAL)" "" "Cartridge.MD5" "fc24a94d4371c69bc58f5245ada43c44" "Cartridge.Manufacturer" "Atari - Axlon, Steve DeFrisco" "Cartridge.ModelNo" "CX26170" "Cartridge.Name" "Secret Quest (1989) (Atari)" "" "Cartridge.MD5" "fc6052438f339aea373bbc999433388a" "Cartridge.Manufacturer" "Atari, David Crane" "Cartridge.ModelNo" "CX2653P" "Cartridge.Name" "Slot Machine (1979) (Atari) (PAL)" "" "Cartridge.MD5" "fc668a2251dd79cbd903d4fa0e558f96" "Cartridge.Name" "Thrust (V1.1) (2000) (TJ) [a1]" "" "Cartridge.MD5" "fc92d74f073a44bc6e46a3b3fa8256a2" "Cartridge.Name" "Megademo (19xx) (PD)" "" "Cartridge.MD5" "fc9c1652fe3a2cade6188f4d3692481f" "Cartridge.Manufacturer" "Andrew Davies" "Cartridge.Name" "Andrew Davies early notBoulderDash demo (NTSC)" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fca4a5be1251927027f2c24774a02160" "Cartridge.Manufacturer" "Activision, John Van Ryzin" "Cartridge.ModelNo" "AZ-036-04" "Cartridge.Name" "H.E.R.O. (1984) (Activision)" "" "Cartridge.MD5" "fcbbd0a407d3ff7bf857b8a399280ea1" "Cartridge.Manufacturer" "ZiMAG - Emag - Vidco" "Cartridge.ModelNo" "GN-070" "Cartridge.Name" "Mysterious Thief, A (1983) (ZiMAG) (Prototype)" "Cartridge.Rarity" "Prototype" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fcbdf405f0fc2027b0ea45bb5af94c1a" "Cartridge.Manufacturer" "Amiga - Video Soft, Michael K. Glass, Jerry Lawson" "Cartridge.Name" "3-D Ghost Attack (1983) (Amiga) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "fcea12625c071ddc49f4e409f4038c60" "Cartridge.Manufacturer" "Fabrizio Zavagli" "Cartridge.Name" "Balls! (16-09-2002) (Fabrizio Zavagli)" "Cartridge.Rarity" "Homebrew" "Display.Phosphor" "YES" "" "Cartridge.MD5" "fcf8e306f6615f74feba5cb25550038c" "Cartridge.Name" "Blue Dot Demo (PD)" "" "Cartridge.MD5" "fd0e5148162e8ec6719445d559f018a9" "Cartridge.Manufacturer" "Activision, Steve Cartwright - Ariola" "Cartridge.ModelNo" "EAX-022, EAX-022-04I - 711 022-720" "Cartridge.Name" "Seaquest (1983) (Activision) (PAL)" "" "Cartridge.MD5" "fd10915633aea4f9cd8b518a25d62b55" "Cartridge.Manufacturer" "Atari, John Dunn" "Cartridge.ModelNo" "CX2631, CX2631P" "Cartridge.Name" "Superman (1979) (Atari) (PAL) [a]" "" "Cartridge.MD5" "fd16949913aaab5beaefed73bf2ca67c" "Cartridge.Manufacturer" "Atari - GCC, John Allred, Mike Feinstein" "Cartridge.ModelNo" "CX2688" "Cartridge.Name" "Jungle Hunt (02-03-1983) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "fd4f5536fd80f35c64d365df85873418" "Cartridge.Manufacturer" "Atari - Bobco, Robert C. Polaro" "Cartridge.ModelNo" "CX26140" "Cartridge.Name" "Desert Falcon (1987) (Atari)" "Cartridge.Note" "AKA Nile Flyer, Sphinx" "" "Cartridge.MD5" "fd6e507b5df68beeeddeaf696b6828fa" "Cartridge.Name" "Boxing (Unknown) (PAL)" "" "Cartridge.MD5" "fd7464edaa8cc264b97ba0d13e7f0678" "Cartridge.Manufacturer" "HES" "Cartridge.ModelNo" "771-333" "Cartridge.Name" "2 Pak Special - Challenge, Surfing (1990) (HES) (PAL) [a]" "" "Cartridge.MD5" "fd78f186bdff83fbad7f97cb583812fe" "Cartridge.Manufacturer" "Amiga - Video Soft" "Cartridge.ModelNo" "3125" "Cartridge.Name" "Surf's Up (1983) (Amiga) (Prototype) [a2]" "Cartridge.Note" "Uses the Joyboard controller" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "fd8b4ee0d57605b35e236e814f706ff1" "Cartridge.Manufacturer" "Atari - GCC, Mike Feinstein, John Mracek" "Cartridge.ModelNo" "CX2673, CX2673P" "Cartridge.Name" "Phoenix (1982) (Atari) (PAL) [a]" "" "Cartridge.MD5" "fd9b321cee5fbb32c39ba3ca5d9ec7cf" "Cartridge.Manufacturer" "Jeffry Johnston" "Cartridge.Name" "Radial Pong - Version 5 (Jeffry Johnston) (PD)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "fdd4995a50395db14f518f63c2d63438" "Cartridge.Name" "Oh No! (Version 3) (18-01-2003) (AD)" "" "Cartridge.MD5" "fde42e39710e75e9e4d4d75440f8e4e5" "Cartridge.Name" "Coke Zero (v1.0) (PAL)" "Display.YStart" "35" "" "Cartridge.MD5" "fdf0de38517e0cf7f0885f98ccc95836" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4200" "Cartridge.Name" "Escape from the Mindmaster (2 of 4) (1982) (Arcadia)" "" "Cartridge.MD5" "fdf6680b2b1e8054293a39700a765692" "Cartridge.Name" "Alpha Demo - The Beta Demo 2 (2000) (MP)" "" "Cartridge.MD5" "fe0b7f27e3ad50bbf9ff468ee56d553d" "Cartridge.Name" "Lines Demo (Eckhard Stolberg) (PAL) (PD)" "" "Cartridge.MD5" "fe0bc4bb92c1c4de7d5706aaa8d8c10d" "Cartridge.Name" "Sprite Demo 2 (PD)" "" "Cartridge.MD5" "fe3b461d4c8b179fe68bc77760294c25" "Cartridge.Manufacturer" "Atari, Joe Decuir" "Cartridge.ModelNo" "CX2621, CX2621P" "Cartridge.Name" "Video Olympics (1977) (Atari) (PAL) (4K)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXDR" "Controller.SwapPaddles" "YES" "" "Cartridge.MD5" "fe67087f9c22655ce519616fc6c6ef4d" "Cartridge.Manufacturer" "Atari - Zip Technology, Randy Bowker, Bruce Williams" "Cartridge.ModelNo" "CX26142" "Cartridge.Name" "Crack'ed (11-28-1988) (Atari) (Prototype)" "Cartridge.Rarity" "Prototype" "" "Cartridge.MD5" "fe6abc0f63e31e2646c9c600926b5b7f" "Cartridge.Manufacturer" "Atari" "Cartridge.ModelNo" "CX26137" "Cartridge.Name" "4 in 1 (02-19-1987) (Atari) (Prototype)" "Cartridge.Note" "Home Run, Canyon Bomber, Sky Diver, Night Driver" "Cartridge.Rarity" "Prototype" "Cartridge.Type" "4IN1" "" "Cartridge.MD5" "fe870018332a0221eb59fb18b0c6bccc" "Cartridge.Name" "Incoming (08-11-2002) (Ben Larson) (PD)" "" "Cartridge.MD5" "fe9ae625d924b54c9f8a14ac9a0f6c6d" "Cartridge.Manufacturer" "BG Dodson" "Cartridge.Name" "High Bid! (BG Dodson) (Hack)" "Cartridge.Note" "Hack of Pepsi Invaders" "Cartridge.Rarity" "Hack" "" "Cartridge.MD5" "feba8686fd0376015258d1152923958a" "Cartridge.Name" "Super Circus (Unknown) (PAL)" "Cartridge.Note" "AKA Circus Atari" "" "Cartridge.MD5" "fec0c2e2ab0588ed20c750b58cf3baa3" "Cartridge.Manufacturer" "Activision - Cheshire Engineering, David Rolfe, Larry Zwick" "Cartridge.ModelNo" "EAZ-037-04, EAZ-037-04I" "Cartridge.Name" "Beamrider (1984) (Activision) (PAL)" "Cartridge.Rarity" "Rare" "" "Cartridge.MD5" "fece458a8023a809a5006867feca40e8" "Cartridge.Name" "SCSIcide (24-02-2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "feec54aac911887940b47fe8c9f80b11" "Cartridge.Manufacturer" "Atari, Rob Fulop" "Cartridge.ModelNo" "CX2633, CX2633P" "Cartridge.Name" "Night Driver (1980) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers (left only)" "Controller.Left" "PADDLES" "Controller.MouseAxis" "AUTO 65" "Display.Phosphor" "YES" "" "Cartridge.MD5" "feedcc20bc3ca34851cd5d9e38aa2ca6" "Cartridge.Manufacturer" "Atari, David Crane - Sears" "Cartridge.ModelNo" "CX2607 - 6-99828, 49-75115" "Cartridge.Name" "Canyon Bomber (1979) (Atari)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXDR" "Controller.SwapPaddles" "YES" "Controller.MouseAxis" "10" "" "Cartridge.MD5" "ff3bd0c684f7144aeaa18758d8281a78" "Cartridge.Manufacturer" "Atari, Bob Whitehead" "Cartridge.ModelNo" "CX2651" "Cartridge.Name" "Blackjack (1977) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Cartridge.Rarity" "Rare" "Controller.Left" "PADDLES_IAXIS" "" "Cartridge.MD5" "ff5a9e340d96df6f5a5b6eb038e923bd" "Cartridge.Name" "Space Shuttle (1983) (Activision) [t1]" "" "Cartridge.MD5" "ff7627207e8aa03730c35c735a82c26c" "Cartridge.Manufacturer" "Atari, Bob Whitehead" "Cartridge.ModelNo" "CX26163P" "Cartridge.Name" "Blackjack (32 in 1) (1988) (Atari) (PAL)" "Cartridge.Note" "Uses the Paddle Controllers" "Controller.Left" "PADDLES_IAXIS" "" "Cartridge.MD5" "ff86fc8ffa717bb095e8471638c1c31c" "Cartridge.Manufacturer" "Arcadia Corporation, Dennis Caswell" "Cartridge.ModelNo" "AR-4302" "Cartridge.Name" "Party Mix - Bop a Buggy (1 of 3) (1983) (Arcadia) (PAL)" "Cartridge.Note" "Uses Paddle Controllers" "Controller.Left" "PADDLES" "Controller.Right" "PADDLES" "Controller.MouseAxis" "01 56" "" "Cartridge.MD5" "ff87d58125ae517eb7b09a0475a1ccdc" "Cartridge.Name" "SCSIcide (Score Hack 1) (24-02-2001) (Joe Grand) (PD)" "" "Cartridge.MD5" "ffb1cd548563158ce33f9d10268187e7" "Cartridge.Manufacturer" "Erik Eid" "Cartridge.Name" "Euchre (Beta) (NTSC) (12-09-2002) (Erik Eid)" "Cartridge.Rarity" "New Release" "" "Cartridge.MD5" "ffc0ff4305dd46b4b459885bd1818e2e" "Cartridge.Manufacturer" "Barry Laws Jr." "Cartridge.Name" "Star Wars - The Battle of Alderaan (Star Strike Hack)" "Cartridge.Note" "Hack of Star Strike (Mattel)" "Cartridge.Rarity" "New Release (Hack)" "" "Cartridge.MD5" "ffdc0eb3543404eb4c353fbdddfa33b6" "Cartridge.Manufacturer" "CCE" "Cartridge.ModelNo" "C-827" "Cartridge.Name" "Chopper Command (1983) (CCE) [a]" "" "Cartridge.MD5" "ffe51989ba6da2c6ae5a12d277862e16" "Cartridge.Manufacturer" "Atari - Sears" "Cartridge.ModelNo" "CX2627 - 6-99841" "Cartridge.Name" "Human Cannonball (1979) (Atari) (4K)" "Cartridge.Note" "AKA Cannon Man" "" "Cartridge.MD5" "ffebb0070689b9d322687edd9c0a2bae" "Cartridge.Name" "Spitfire Attack (1983) (Milton Bradley) [h1]" "" stella-5.1.1/src/emucore/tia/000077500000000000000000000000001324334165500160135ustar00rootroot00000000000000stella-5.1.1/src/emucore/tia/Background.cxx000066400000000000000000000056441324334165500206270ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Background.hxx" #include "TIA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Background::Background() { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Background::reset() { myColor = myObjectColor = myDebugColor = 0; myDebugEnabled = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Background::setColor(uInt8 color) { if (color != myObjectColor) myTIA->flushLineCache(); myObjectColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Background::setDebugColor(uInt8 color) { myTIA->flushLineCache(); myDebugColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Background::enableDebugColors(bool enabled) { myTIA->flushLineCache(); myDebugEnabled = enabled; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Background::applyColorLoss() { myTIA->flushLineCache(); applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Background::applyColors() { if (!myDebugEnabled) { if (myTIA->colorLossActive()) myObjectColor |= 0x01; else myObjectColor &= 0xfe; myColor = myObjectColor; } else myColor = myDebugColor; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Background::save(Serializer& out) const { try { out.putString(name()); out.putByte(myColor); out.putByte(myObjectColor); out.putByte(myDebugColor); out.putBool(myDebugEnabled); } catch(...) { cerr << "ERROR: TIA_BK::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Background::load(Serializer& in) { try { if(in.getString() != name()) return false; myColor = in.getByte(); myObjectColor = in.getByte(); myDebugColor = in.getByte(); myDebugEnabled = in.getBool(); applyColors(); } catch(...) { cerr << "ERROR: TIA_BK::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/tia/Background.hxx000066400000000000000000000032761324334165500206330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_BACKGROUND #define TIA_BACKGROUND #include "Serializable.hxx" #include "bspf.hxx" class TIA; class Background : public Serializable { public: Background(); public: void setTIA(TIA* tia) { myTIA = tia; } void reset(); void setColor(uInt8 color); void setDebugColor(uInt8 color); void enableDebugColors(bool enabled); void applyColorLoss(); uInt8 getColor() const { return myColor; } /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override { return "TIA_BK"; } private: void applyColors(); private: uInt8 myColor; uInt8 myObjectColor, myDebugColor; bool myDebugEnabled; TIA* myTIA; private: Background(const Background&) = delete; Background(Background&&) = delete; Background& operator=(const Background&) = delete; Background& operator=(Background&&); }; #endif // TIA_BACKGROUND stella-5.1.1/src/emucore/tia/Ball.cxx000066400000000000000000000220041324334165500174070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Ball.hxx" #include "TIA.hxx" enum Count: Int8 { renderCounterOffset = -4 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Ball::Ball(uInt32 collisionMask) : myCollisionMaskDisabled(collisionMask), myCollisionMaskEnabled(0xFFFF), myIsSuppressed(false) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::reset() { myColor = myObjectColor = myDebugColor = 0; collision = myCollisionMaskDisabled; myIsEnabledOld = false; myIsEnabledNew = false; myIsEnabled = false; myIsDelaying = false; myHmmClocks = 0; myCounter = 0; myIsMoving = false; myEffectiveWidth = 1; myLastMovementTick = 0; myWidth = 1; myIsRendering = false; myDebugEnabled = false; myRenderCounter = 0; updateEnabled(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::enabl(uInt8 value) { const auto enabledNewOldValue = myIsEnabledNew; myIsEnabledNew = (value & 0x02) > 0; if (myIsEnabledNew != enabledNewOldValue && !myIsDelaying) { myTIA->flushLineCache(); updateEnabled(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::hmbl(uInt8 value) { myHmmClocks = (value >> 4) ^ 0x08; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::resbl(uInt8 counter) { myCounter = counter; myIsRendering = true; myRenderCounter = Count::renderCounterOffset + (counter - 157); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::ctrlpf(uInt8 value) { static constexpr uInt8 ourWidths[] = {1, 2, 4, 8}; const uInt8 newWidth = ourWidths[(value & 0x30) >> 4]; if (newWidth != myWidth) { myTIA->flushLineCache(); myWidth = newWidth; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::vdelbl(uInt8 value) { const auto oldIsDelaying = myIsDelaying; myIsDelaying = (value & 0x01) > 0; if (oldIsDelaying != myIsDelaying) { myTIA->flushLineCache(); updateEnabled(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::toggleCollisions(bool enabled) { myCollisionMaskEnabled = enabled ? 0xFFFF : (0x8000 | myCollisionMaskDisabled); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::toggleEnabled(bool enabled) { myIsSuppressed = !enabled; updateEnabled(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::setColor(uInt8 color) { if (color != myObjectColor && myIsEnabled) myTIA->flushLineCache(); myObjectColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::setDebugColor(uInt8 color) { myTIA->flushLineCache(); myDebugColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::enableDebugColors(bool enabled) { myTIA->flushLineCache(); myDebugEnabled = enabled; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::applyColorLoss() { myTIA->flushLineCache(); applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::startMovement() { myIsMoving = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Ball::movementTick(uInt32 clock, bool apply) { myLastMovementTick = myCounter; if (clock == myHmmClocks) myIsMoving = false; if (myIsMoving && apply) tick(false); return myIsMoving; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::tick(bool isReceivingMclock) { collision = (myIsRendering && myRenderCounter >= 0 && myIsEnabled) ? myCollisionMaskEnabled : myCollisionMaskDisabled; bool starfieldEffect = myIsMoving && isReceivingMclock; if (myCounter == 156) { myIsRendering = true; myRenderCounter = Count::renderCounterOffset; uInt8 starfieldDelta = (myCounter + 160 - myLastMovementTick) % 4; if (starfieldEffect && starfieldDelta == 3 && myWidth < 4) myRenderCounter++; switch (starfieldDelta) { case 3: myEffectiveWidth = myWidth == 1 ? 2 : myWidth; break; case 2: myEffectiveWidth = 0; break; default: myEffectiveWidth = myWidth; break; } } else if (myIsRendering && ++myRenderCounter >= (starfieldEffect ? myEffectiveWidth : myWidth)) myIsRendering = false; if (++myCounter >= 160) myCounter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::setENABLOld(bool enabled) { myTIA->flushLineCache(); myIsEnabledOld = enabled; updateEnabled(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::shuffleStatus() { const auto oldIsEnabledOld = myIsEnabledOld; myIsEnabledOld = myIsEnabledNew; if (myIsEnabledOld != oldIsEnabledOld && myIsDelaying) { myTIA->flushLineCache(); updateEnabled(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::updateEnabled() { myIsEnabled = !myIsSuppressed && (myIsDelaying ? myIsEnabledOld : myIsEnabledNew); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::applyColors() { if (!myDebugEnabled) { if (myTIA->colorLossActive()) myObjectColor |= 0x01; else myObjectColor &= 0xfe; myColor = myObjectColor; } else myColor = myDebugColor; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Ball::getPosition() const { // position = // current playfield x + // (current counter - 156 (the decode clock of copy 0)) + // clock count after decode until first pixel + // 1 (it'll take another cycle after the decode for the rendter counter to start ticking) // // The result may be negative, so we add 160 and do the modulus -> 317 = 156 + 160 + 1 // // Mind the sign of renderCounterOffset: it's defined negative above return (317 - myCounter - Count::renderCounterOffset + myTIA->getPosition()) % 160; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Ball::setPosition(uInt8 newPosition) { myTIA->flushLineCache(); // See getPosition for an explanation myCounter = (317 - newPosition - Count::renderCounterOffset + myTIA->getPosition()) % 160; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Ball::save(Serializer& out) const { try { out.putString(name()); out.putInt(collision); out.putInt(myCollisionMaskDisabled); out.putInt(myCollisionMaskEnabled); out.putByte(myColor); out.putByte(myObjectColor); out.putByte(myDebugColor); out.putBool(myDebugEnabled); out.putBool(myIsEnabledOld); out.putBool(myIsEnabledNew); out.putBool(myIsEnabled); out.putBool(myIsSuppressed); out.putBool(myIsDelaying); out.putByte(myHmmClocks); out.putByte(myCounter); out.putBool(myIsMoving); out.putByte(myWidth); out.putByte(myEffectiveWidth); out.putByte(myLastMovementTick); out.putBool(myIsRendering); out.putByte(myRenderCounter); } catch(...) { cerr << "ERROR: TIA_Ball::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Ball::load(Serializer& in) { try { if(in.getString() != name()) return false; collision = in.getInt(); myCollisionMaskDisabled = in.getInt(); myCollisionMaskEnabled = in.getInt(); myColor = in.getByte(); myObjectColor = in.getByte(); myDebugColor = in.getByte(); myDebugEnabled = in.getBool(); myIsEnabledOld = in.getBool(); myIsEnabledNew = in.getBool(); myIsEnabled = in.getBool(); myIsSuppressed = in.getBool(); myIsDelaying = in.getBool(); myHmmClocks = in.getByte(); myCounter = in.getByte(); myIsMoving = in.getBool(); myWidth = in.getByte(); myEffectiveWidth = in.getByte(); myLastMovementTick = in.getByte(); myIsRendering = in.getBool(); myRenderCounter = in.getByte(); applyColors(); } catch(...) { cerr << "ERROR: TIA_Ball::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/tia/Ball.hxx000066400000000000000000000053661324334165500174300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_BALL #define TIA_BALL #include "Serializable.hxx" #include "bspf.hxx" class TIA; class Ball : public Serializable { public: Ball(uInt32 collisionMask); public: void setTIA(TIA* tia) { myTIA = tia; } void reset(); void enabl(uInt8 value); void hmbl(uInt8 value); void resbl(uInt8 counter); void ctrlpf(uInt8 value); void vdelbl(uInt8 value); void toggleCollisions(bool enabled); void toggleEnabled(bool enabled); void setColor(uInt8 color); void setDebugColor(uInt8 color); void enableDebugColors(bool enabled); void applyColorLoss(); void startMovement(); bool movementTick(uInt32 clock, bool apply); void tick(bool isReceivingMclock = true); bool isOn() const { return (collision & 0x8000); } uInt8 getColor() const { return myColor; } void shuffleStatus(); uInt8 getPosition() const; void setPosition(uInt8 newPosition); bool getENABLOld() const { return myIsEnabledOld; } bool getENABLNew() const { return myIsEnabledNew; } void setENABLOld(bool enabled); /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override { return "TIA_Ball"; } public: uInt32 collision; private: void updateEnabled(); void applyColors(); private: uInt32 myCollisionMaskDisabled; uInt32 myCollisionMaskEnabled; uInt8 myColor; uInt8 myObjectColor, myDebugColor; bool myDebugEnabled; bool myIsEnabledOld; bool myIsEnabledNew; bool myIsEnabled; bool myIsSuppressed; bool myIsDelaying; uInt8 myHmmClocks; uInt8 myCounter; bool myIsMoving; uInt8 myWidth; uInt8 myEffectiveWidth; uInt8 myLastMovementTick; bool myIsRendering; Int8 myRenderCounter; TIA* myTIA; private: Ball() = delete; Ball(const Ball&) = delete; Ball(Ball&&) = delete; Ball& operator=(const Ball&) = delete; Ball& operator=(Ball&&); }; #endif // TIA_BALL stella-5.1.1/src/emucore/tia/DelayQueue.hxx000066400000000000000000000111771324334165500206160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_DELAY_QUEUE #define TIA_DELAY_QUEUE #include "Serializable.hxx" #include "bspf.hxx" #include "smartmod.hxx" #include "DelayQueueMember.hxx" template class DelayQueueIteratorImpl; template class DelayQueue : public Serializable { public: friend DelayQueueIteratorImpl; public: DelayQueue(); public: void push(uInt8 address, uInt8 value, uInt8 delay); void reset(); template void execute(T executor); /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override; private: DelayQueueMember myMembers[length]; uInt8 myIndex; uInt8 myIndices[0xFF]; private: DelayQueue(const DelayQueue&) = delete; DelayQueue(DelayQueue&&) = delete; DelayQueue& operator=(const DelayQueue&) = delete; DelayQueue& operator=(DelayQueue&&) = delete; }; // ############################################################################ // Implementation // ############################################################################ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template DelayQueue::DelayQueue() : myIndex(0) { memset(myIndices, 0xFF, 0xFF); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template void DelayQueue::push(uInt8 address, uInt8 value, uInt8 delay) { if (delay >= length) throw runtime_error("delay exceeds queue length"); uInt8 currentIndex = myIndices[address]; if (currentIndex < 0xFF) myMembers[currentIndex].remove(address); uInt8 index = smartmod(myIndex + delay); myMembers[index].push(address, value); myIndices[address] = index; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template void DelayQueue::reset() { for (uInt8 i = 0; i < length; i++) myMembers[i].clear(); myIndex = 0; memset(myIndices, 0xFF, 0xFF); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template template void DelayQueue::execute(T executor) { DelayQueueMember& currentMember = myMembers[myIndex]; for (uInt8 i = 0; i < currentMember.mySize; i++) { executor(currentMember.myEntries[i].address, currentMember.myEntries[i].value); myIndices[currentMember.myEntries[i].address] = 0xFF; } currentMember.clear(); myIndex = smartmod(myIndex + 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template bool DelayQueue::save(Serializer& out) const { try { out.putInt(length); for (uInt8 i = 0; i < length; i++) myMembers[i].save(out); out.putByte(myIndex); out.putByteArray(myIndices, 0xFF); } catch(...) { cerr << "ERROR: TIA_DelayQueue::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template bool DelayQueue::load(Serializer& in) { try { if (in.getInt() != length) throw runtime_error("delay queue length mismatch"); for (uInt8 i = 0; i < length; i++) myMembers[i].load(in); myIndex = in.getByte(); in.getByteArray(myIndices, 0xFF); } catch(...) { cerr << "ERROR: TIA_DelayQueue::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template string DelayQueue::name() const { return "TIA_DelayQueue"; } #endif // TIA_DELAY_QUEUE stella-5.1.1/src/emucore/tia/DelayQueueIterator.hxx000066400000000000000000000021771324334165500223300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_DELAY_QUEUE_ITERATOR #define TIA_DELAY_QUEUE_ITERATOR #include "bspf.hxx" #include "DelayQueue.hxx" #include "DelayQueueMember.hxx" class DelayQueueIterator { public: virtual ~DelayQueueIterator() {} public: virtual bool isValid() const = 0; virtual uInt8 delay() const = 0; virtual uInt8 address() const = 0; virtual uInt8 value() const = 0; virtual bool next() = 0; }; #endif // TIA_DELAY_QUEUE_ITERATOR stella-5.1.1/src/emucore/tia/DelayQueueIteratorImpl.hxx000066400000000000000000000076401324334165500231520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_DELAY_QUEUE_ITERATOR_IMPL #define TIA_DELAY_QUEUE_ITERATOR_IMPL #include "bspf.hxx" #include "DelayQueue.hxx" #include "DelayQueueMember.hxx" #include "DelayQueueIterator.hxx" template class DelayQueueIteratorImpl : public DelayQueueIterator { public: DelayQueueIteratorImpl(const DelayQueue& delayQueue); public: bool isValid() const override; uInt8 delay() const override; uInt8 address() const override; uInt8 value() const override; bool next() override; private: uInt8 currentIndex() const; private: const DelayQueue& myDelayQueue; uInt8 myDelayCycle; uInt8 myIndex; }; // ############################################################################ // Implementation // ############################################################################ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template DelayQueueIteratorImpl::DelayQueueIteratorImpl( const DelayQueue& delayQueue ) : myDelayQueue(delayQueue), myDelayCycle(0), myIndex(0) { while (myDelayQueue.myMembers[currentIndex()].mySize == 0 && isValid()) myDelayCycle++; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template bool DelayQueueIteratorImpl::isValid() const { return myDelayCycle < length; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template uInt8 DelayQueueIteratorImpl::delay() const { if (!isValid()) { throw runtime_error("delay called on invalid DelayQueueInterator"); } return myDelayCycle; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template uInt8 DelayQueueIteratorImpl::address() const { if (!isValid()) { throw runtime_error("address called on invalid DelayQueueInterator"); } return myDelayQueue.myMembers[currentIndex()].myEntries[myIndex].address; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template uInt8 DelayQueueIteratorImpl::value() const { if (!isValid()) { throw runtime_error("value called on invalid DelayQueueInterator"); } return myDelayQueue.myMembers[currentIndex()].myEntries[myIndex].value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template bool DelayQueueIteratorImpl::next() { if (!isValid()) return false; if (++myIndex < myDelayQueue.myMembers[currentIndex()].mySize) return true; myIndex = 0; do { myDelayCycle++; } while (myDelayQueue.myMembers[currentIndex()].mySize == 0 && isValid()); return isValid(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template uInt8 DelayQueueIteratorImpl::currentIndex() const { return (myDelayQueue.myIndex + myDelayCycle) % length; } #endif // TIA_DELAY_QUEUE_ITERATOR_IMPL stella-5.1.1/src/emucore/tia/DelayQueueMember.hxx000066400000000000000000000101251324334165500217360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_DELAY_QUEUE_MEMBER #define TIA_DELAY_QUEUE_MEMBER #include "Serializable.hxx" #include "bspf.hxx" template class DelayQueueMember : public Serializable { public: struct Entry { uInt8 address; uInt8 value; }; public: DelayQueueMember(); public: void push(uInt8 address, uInt8 value); void remove(uInt8 address); void clear(); /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override; public: Entry myEntries[capacity]; uInt8 mySize; private: DelayQueueMember(const DelayQueueMember&) = delete; DelayQueueMember(DelayQueueMember&&) = delete; DelayQueueMember& operator=(const DelayQueueMember&) = delete; DelayQueueMember& operator=(DelayQueueMember&&) = delete; }; // ############################################################################ // Implementation // ############################################################################ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template DelayQueueMember::DelayQueueMember() : mySize(0) {} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template void DelayQueueMember::push(uInt8 address, uInt8 value) { if (mySize == capacity) throw runtime_error("delay queue overflow"); myEntries[mySize].address = address; myEntries[mySize++].value = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template void DelayQueueMember::remove(uInt8 address) { uInt8 index; for (index = 0; index < mySize; index++) { if (myEntries[index].address == address) break; } if (index < mySize) { for (uInt8 i = index + 1; i < mySize; i++) { myEntries[i-1] = myEntries[i]; } mySize--; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template void DelayQueueMember::clear() { mySize = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template bool DelayQueueMember::save(Serializer& out) const { try { out.putInt(mySize); for(uInt8 i = 0; i < mySize; ++i) { const Entry& e = myEntries[i]; out.putByte(e.address); out.putByte(e.value); } } catch(...) { cerr << "ERROR: TIA_DelayQueueMember::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template bool DelayQueueMember::load(Serializer& in) { try { mySize = in.getInt(); if (mySize > capacity) throw new runtime_error("invalid delay queue size"); for(uInt32 i = 0; i < mySize; ++i) { Entry& e = myEntries[i]; e.address = in.getByte(); e.value = in.getByte(); } } catch(...) { cerr << "ERROR: TIA_DelayQueueMember::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - template string DelayQueueMember::name() const { return "TIA_DelayQueueMember"; } #endif // TIA_DELAY_QUEUE_MEMBER stella-5.1.1/src/emucore/tia/DrawCounterDecodes.cxx000066400000000000000000000045611324334165500222710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "DrawCounterDecodes.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* const* DrawCounterDecodes::playerDecodes() const { return myPlayerDecodes; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const uInt8* const* DrawCounterDecodes::missileDecodes() const { return myMissileDecodes; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DrawCounterDecodes& DrawCounterDecodes::DrawCounterDecodes::get() { return myInstance; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DrawCounterDecodes::DrawCounterDecodes() { uInt8 *decodeTables[] = {myDecodes0, myDecodes1, myDecodes2, myDecodes3, myDecodes4, myDecodes6}; for (uInt8 *decodes : decodeTables) { memset(decodes, 0, 160); decodes[156] = 1; } myDecodes1[12] = 1; myDecodes2[28] = 1; myDecodes3[12] = myDecodes3[28] = 1; myDecodes4[60] = 1; myDecodes6[28] = myDecodes6[60] = 1; myPlayerDecodes[0] = myDecodes0; myPlayerDecodes[1] = myDecodes1; myPlayerDecodes[2] = myDecodes2; myPlayerDecodes[3] = myDecodes3; myPlayerDecodes[4] = myDecodes4; myPlayerDecodes[5] = myDecodes0; myPlayerDecodes[6] = myDecodes6; myPlayerDecodes[7] = myDecodes0; myMissileDecodes[0] = myDecodes0; myMissileDecodes[1] = myDecodes1; myMissileDecodes[2] = myDecodes2; myMissileDecodes[3] = myDecodes3; myMissileDecodes[4] = myDecodes4; myMissileDecodes[5] = myDecodes0; myMissileDecodes[6] = myDecodes6; myMissileDecodes[7] = myDecodes0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DrawCounterDecodes DrawCounterDecodes::myInstance; stella-5.1.1/src/emucore/tia/DrawCounterDecodes.hxx000066400000000000000000000030111324334165500222630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_DRAW_COUNTER_DECODES #define TIA_DRAW_COUNTER_DECODES #include "bspf.hxx" class DrawCounterDecodes { public: const uInt8* const* playerDecodes() const; const uInt8* const* missileDecodes() const; static DrawCounterDecodes& get(); protected: DrawCounterDecodes(); private: uInt8* myPlayerDecodes[8]; uInt8* myMissileDecodes[8]; uInt8 myDecodes0[160], myDecodes1[160], myDecodes2[160], myDecodes3[160], myDecodes4[160], myDecodes6[160]; static DrawCounterDecodes myInstance; private: DrawCounterDecodes(const DrawCounterDecodes&) = delete; DrawCounterDecodes(DrawCounterDecodes&&) = delete; DrawCounterDecodes& operator=(const DrawCounterDecodes&) = delete; DrawCounterDecodes& operator=(DrawCounterDecodes&&) = delete; }; #endif // TIA_DRAW_COUNTER_DECODES stella-5.1.1/src/emucore/tia/FrameLayout.hxx000066400000000000000000000016411324334165500207760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FRAME_LAYOUT #define FRAME_LAYOUT enum class FrameLayout { ntsc, // ROM display has NTSC timings (~60Hz, ~262 scanlines, etc) pal // ROM display has PAL timings (~50Hz, ~312 scanlines, etc) }; #endif // FRAME_LAYOUT stella-5.1.1/src/emucore/tia/LatchedInput.cxx000066400000000000000000000042551324334165500211310ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "LatchedInput.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LatchedInput::LatchedInput() { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LatchedInput::reset() { myModeLatched = false; myLatchedValue = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LatchedInput::vblank(uInt8 value) { if (value & 0x40) myModeLatched = true; else { myModeLatched = false; myLatchedValue = 0x80; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 LatchedInput::inpt(bool pinState) { uInt8 value = pinState ? 0 : 0x80; if (myModeLatched) { myLatchedValue &= value; value = myLatchedValue; } return value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool LatchedInput::save(Serializer& out) const { try { out.putString(name()); out.putBool(myModeLatched); out.putByte(myLatchedValue); } catch(...) { cerr << "ERROR: TIA_LatchedInput::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool LatchedInput::load(Serializer& in) { try { if(in.getString() != name()) return false; myModeLatched = in.getBool(); myLatchedValue = in.getByte(); } catch(...) { cerr << "ERROR: TIA_LatchedInput::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/tia/LatchedInput.hxx000066400000000000000000000030351324334165500211310ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_LATCHED_INPUT #define TIA_LATCHED_INPUT #include "bspf.hxx" #include "Serializable.hxx" class LatchedInput : public Serializable { public: LatchedInput(); public: void reset(); void vblank(uInt8 value); bool vblankLatched() const { return myModeLatched; } uInt8 inpt(bool pinState); /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override { return "TIA_LatchedInput"; } private: bool myModeLatched; uInt8 myLatchedValue; private: LatchedInput(const LatchedInput&) = delete; LatchedInput(LatchedInput&&) = delete; LatchedInput& operator=(const LatchedInput&) = delete; LatchedInput& operator=(LatchedInput&&) = delete; }; #endif // TIA_LATCHED_INPUT stella-5.1.1/src/emucore/tia/Missile.cxx000066400000000000000000000227771324334165500201630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Missile.hxx" #include "DrawCounterDecodes.hxx" #include "TIA.hxx" enum Count: Int8 { renderCounterOffset = -4 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Missile::Missile(uInt32 collisionMask) : myCollisionMaskDisabled(collisionMask), myCollisionMaskEnabled(0xFFFF), myIsSuppressed(false), myDecodesOffset(0) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::reset() { myDecodes = DrawCounterDecodes::get().missileDecodes()[myDecodesOffset]; myIsEnabled = false; myEnam = false; myResmp = 0; myHmmClocks = 0; myCounter = 0; myIsMoving = false; myLastMovementTick = 0; myWidth = 1; myEffectiveWidth = 1; myIsRendering = false; myRenderCounter = 0; myColor = myObjectColor = myDebugColor = 0; myDebugEnabled = false; collision = myCollisionMaskDisabled; updateEnabled(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::enam(uInt8 value) { const auto oldEnam = myEnam; myEnam = (value & 0x02) > 0; if (oldEnam != myEnam) myTIA->flushLineCache(); updateEnabled(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::hmm(uInt8 value) { myHmmClocks = (value >> 4) ^ 0x08; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::resm(uInt8 counter, bool hblank) { myCounter = counter; if (myIsRendering) { if (myRenderCounter < 0) { myRenderCounter = Count::renderCounterOffset + (counter - 157); } else { // The following is an effective description of the behavior of missile width after a // RESMx during draw. It would be much simpler without the HBLANK cases :) switch (myWidth) { case 8: myRenderCounter = (counter - 157) + ((myRenderCounter >= 4) ? 4 : 0); break; case 4: myRenderCounter = (counter - 157); break; case 2: if (hblank) myIsRendering = myRenderCounter > 1; else if (myRenderCounter == 0) myRenderCounter++; break; default: if (hblank) myIsRendering = myRenderCounter > 0; break; } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::resmp(uInt8 value, const Player& player) { const uInt8 resmp = value & 0x02; if (resmp == myResmp) return; myTIA->flushLineCache(); myResmp = resmp; if (!myResmp) myCounter = player.getRespClock(); updateEnabled(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::toggleCollisions(bool enabled) { myCollisionMaskEnabled = enabled ? 0xFFFF : (0x8000 | myCollisionMaskDisabled); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::toggleEnabled(bool enabled) { myIsSuppressed = !enabled; updateEnabled(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::nusiz(uInt8 value) { static constexpr uInt8 ourWidths[] = { 1, 2, 4, 8 }; myDecodesOffset = value & 0x07; myWidth = ourWidths[(value & 0x30) >> 4]; myDecodes = DrawCounterDecodes::get().missileDecodes()[myDecodesOffset]; if (myIsRendering && myRenderCounter >= myWidth) myIsRendering = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::startMovement() { myIsMoving = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Missile::movementTick(uInt8 clock, uInt8 hclock, bool apply) { myLastMovementTick = myCounter; if (clock == myHmmClocks) myIsMoving = false; if (myIsMoving && apply) tick(hclock); return myIsMoving; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::tick(uInt8 hclock) { const bool render = myIsRendering && (myRenderCounter >= 0 || (myIsMoving && myRenderCounter == -1 && myWidth < 4 && ((hclock + 1) % 4 == 3))) && myIsEnabled; collision = render ? myCollisionMaskEnabled : myCollisionMaskDisabled; if (myDecodes[myCounter] && !myResmp) { myIsRendering = true; myRenderCounter = Count::renderCounterOffset; } else if (myIsRendering) { if (myIsMoving && myRenderCounter == -1) { switch ((hclock + 1) % 4) { case 3: myEffectiveWidth = myWidth == 1 ? 2 : myWidth; if (myWidth < 4) myRenderCounter++; break; case 2: myEffectiveWidth = 0; break; default: myEffectiveWidth = myWidth; break; } } if (++myRenderCounter >= (myIsMoving ? myEffectiveWidth : myWidth)) myIsRendering = false; } if (++myCounter >= 160) myCounter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::setColor(uInt8 color) { if (color != myObjectColor && myIsEnabled) myTIA->flushLineCache(); myObjectColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::setDebugColor(uInt8 color) { myTIA->flushLineCache(); myDebugColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::enableDebugColors(bool enabled) { myTIA->flushLineCache(); myDebugEnabled = enabled; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::applyColorLoss() { myTIA->flushLineCache(); applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::updateEnabled() { myIsEnabled = !myIsSuppressed && myEnam && !myResmp; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::applyColors() { if (!myDebugEnabled) { if (myTIA->colorLossActive()) myObjectColor |= 0x01; else myObjectColor &= 0xfe; myColor = myObjectColor; } else myColor = myDebugColor; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Missile::getPosition() const { // position = // current playfield x + // (current counter - 156 (the decode clock of copy 0)) + // clock count after decode until first pixel + // 1 (it'll take another cycle after the decode for the rendter counter to start ticking) // // The result may be negative, so we add 160 and do the modulus // // Mind the sign of renderCounterOffset: it's defined negative above return (317 - myCounter - Count::renderCounterOffset + myTIA->getPosition()) % 160; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Missile::setPosition(uInt8 newPosition) { myTIA->flushLineCache(); // See getPosition for an explanation myCounter = (317 - newPosition - Count::renderCounterOffset + myTIA->getPosition()) % 160; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Missile::save(Serializer& out) const { try { out.putString(name()); out.putInt(collision); out.putInt(myCollisionMaskDisabled); out.putInt(myCollisionMaskEnabled); out.putBool(myIsEnabled); out.putBool(myIsSuppressed); out.putBool(myEnam); out.putByte(myResmp); out.putByte(myHmmClocks); out.putByte(myCounter); out.putBool(myIsMoving); out.putByte(myWidth); out.putByte(myEffectiveWidth); out.putByte(myLastMovementTick); out.putBool(myIsRendering); out.putByte(myRenderCounter); out.putByte(myDecodesOffset); out.putByte(myColor); out.putByte(myObjectColor); out.putByte(myDebugColor); out.putBool(myDebugEnabled); } catch(...) { cerr << "ERROR: TIA_Missile::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Missile::load(Serializer& in) { try { if(in.getString() != name()) return false; collision = in.getInt(); myCollisionMaskDisabled = in.getInt(); myCollisionMaskEnabled = in.getInt(); myIsEnabled = in.getBool(); myIsSuppressed = in.getBool(); myEnam = in.getBool(); myResmp = in.getByte(); myHmmClocks = in.getByte(); myCounter = in.getByte(); myIsMoving = in.getBool(); myWidth = in.getByte(); myEffectiveWidth = in.getByte(); myLastMovementTick = in.getByte(); myIsRendering = in.getBool(); myRenderCounter = in.getByte(); myDecodesOffset = in.getByte(); myDecodes = DrawCounterDecodes::get().missileDecodes()[myDecodesOffset]; myColor = in.getByte(); myObjectColor = in.getByte(); myDebugColor = in.getByte(); myDebugEnabled = in.getBool(); applyColors(); } catch(...) { cerr << "ERROR: TIA_Missile::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/tia/Missile.hxx000066400000000000000000000053021324334165500201510ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_MISSILE #define TIA_MISSILE #include "Serializable.hxx" #include "bspf.hxx" #include "Player.hxx" class TIA; class Missile : public Serializable { public: Missile(uInt32 collisionMask); public: void setTIA(TIA* tia) { myTIA = tia; } void reset(); void enam(uInt8 value); void hmm(uInt8 value); void resm(uInt8 counter, bool hblank); void resmp(uInt8 value, const Player& player); void nusiz(uInt8 value); void startMovement(); bool movementTick(uInt8 clock, uInt8 hclock, bool apply); void tick(uInt8 hclock); void setColor(uInt8 color); void setDebugColor(uInt8 color); void enableDebugColors(bool enabled); void applyColorLoss(); void toggleCollisions(bool enabled); void toggleEnabled(bool enabled); bool isOn() const { return (collision & 0x8000); } uInt8 getColor() const { return myColor; } uInt8 getPosition() const; void setPosition(uInt8 newPosition); /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override { return "TIA_Missile"; } public: uInt32 collision; private: void updateEnabled(); void applyColors(); private: uInt32 myCollisionMaskDisabled; uInt32 myCollisionMaskEnabled; bool myIsEnabled; bool myIsSuppressed; bool myEnam; uInt8 myResmp; uInt8 myHmmClocks; uInt8 myCounter; bool myIsMoving; uInt8 myWidth; uInt8 myEffectiveWidth; uInt8 myLastMovementTick; bool myIsRendering; Int8 myRenderCounter; const uInt8* myDecodes; uInt8 myDecodesOffset; // needed for state saving uInt8 myColor; uInt8 myObjectColor, myDebugColor; bool myDebugEnabled; TIA *myTIA; private: Missile(const Missile&) = delete; Missile(Missile&&) = delete; Missile& operator=(const Missile&) = delete; Missile& operator=(Missile&&) = delete; }; #endif // TIA_MISSILE stella-5.1.1/src/emucore/tia/PaddleReader.cxx000066400000000000000000000077431324334165500210660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "PaddleReader.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PaddleReader::PaddleReader() { reset(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaddleReader::reset(double timestamp) { myU = 0; myIsDumped = false; myValue = 0; myTimestamp = timestamp; setConsoleTiming(ConsoleTiming::ntsc); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaddleReader::vblank(uInt8 value, double timestamp) { bool oldIsDumped = myIsDumped; if (value & 0x80) { myIsDumped = true; myU = 0; myTimestamp = timestamp; } else if (oldIsDumped) { myIsDumped = false; myTimestamp = timestamp; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 PaddleReader::inpt(double timestamp) { updateCharge(timestamp); bool state = myIsDumped ? false : myU > myUThresh; return state ? 0x80 : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaddleReader::update(double value, double timestamp, ConsoleTiming consoleTiming) { if (consoleTiming != myConsoleTiming) { setConsoleTiming(consoleTiming); } if (value != myValue) { myValue = value; if (myValue < 0) { // value < 0 signifies either maximum resistance OR analog input connected to // ground (keyboard controllers). As we have no way to tell these apart we just // assume ground and discharge. myU = 0; myTimestamp = timestamp; } else { updateCharge(timestamp); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaddleReader::setConsoleTiming(ConsoleTiming consoleTiming) { myConsoleTiming = consoleTiming; myClockFreq = myConsoleTiming == ConsoleTiming::ntsc ? 60 * 228 * 262 : 50 * 228 * 312; myUThresh = USUPP * (1. - exp(-TRIPPOINT_LINES * 228 / myClockFreq / (RPOT + R0) / C)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PaddleReader::updateCharge(double timestamp) { if (myIsDumped) return; if (myValue >= 0) myU = USUPP * (1 - (1 - myU / USUPP) * exp(-(timestamp - myTimestamp) / (myValue * RPOT + R0) / C / myClockFreq)); myTimestamp = timestamp; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PaddleReader::save(Serializer& out) const { try { out.putString(name()); out.putDouble(myUThresh); out.putDouble(myU); out.putDouble(myValue); out.putDouble(myTimestamp); out.putInt(int(myConsoleTiming)); out.putDouble(myClockFreq); out.putBool(myIsDumped); } catch(...) { cerr << "ERROR: TIA_PaddleReader::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PaddleReader::load(Serializer& in) { try { if(in.getString() != name()) return false; myUThresh = in.getDouble(); myU = in.getDouble(); myValue = in.getDouble(); myTimestamp = in.getDouble(); myConsoleTiming = ConsoleTiming(in.getInt()); myClockFreq = in.getDouble(); myIsDumped = in.getBool(); } catch(...) { cerr << "ERROR: TIA_PaddleReader::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/tia/PaddleReader.hxx000066400000000000000000000040301324334165500210550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_PADDLE_READER #define TIA_PADDLE_READER #include "bspf.hxx" #include "Serializable.hxx" #include "Console.hxx" class PaddleReader : public Serializable { public: PaddleReader(); public: void reset(double timestamp); void vblank(uInt8 value, double timestamp); bool vblankDumped() const { return myIsDumped; } uInt8 inpt(double timestamp); void update(double value, double timestamp, ConsoleTiming consoleTiming); /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override { return "TIA_PaddleReader"; } private: void setConsoleTiming(ConsoleTiming timing); void updateCharge(double timestamp); private: double myUThresh; double myU; double myValue; double myTimestamp; ConsoleTiming myConsoleTiming; double myClockFreq; bool myIsDumped; static constexpr double R0 = 1.5e3, C = 68e-9, RPOT = 1e6, USUPP = 5; static constexpr double TRIPPOINT_LINES = 379; private: PaddleReader(const PaddleReader&) = delete; PaddleReader(PaddleReader&&) = delete; PaddleReader& operator=(const PaddleReader&) = delete; PaddleReader& operator=(PaddleReader&&) = delete; }; #endif // TIA_PADDLE_READER stella-5.1.1/src/emucore/tia/Player.cxx000066400000000000000000000321171324334165500177770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Player.hxx" #include "DrawCounterDecodes.hxx" #include "TIA.hxx" enum Count: Int8 { renderCounterOffset = -5, }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Player::Player(uInt32 collisionMask) : myCollisionMaskDisabled(collisionMask), myCollisionMaskEnabled(0xFFFF), myIsSuppressed(false), myDecodesOffset(0) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::reset() { myDecodes = DrawCounterDecodes::get().playerDecodes()[myDecodesOffset]; myHmmClocks = 0; myCounter = 0; myIsMoving = false; myIsRendering = false; myRenderCounter = 0; myPatternOld = 0; myPatternNew = 0; myIsReflected = 0; myIsDelaying = false; myColor = myObjectColor = myDebugColor = 0; myDebugEnabled = false; collision = myCollisionMaskDisabled; mySampleCounter = 0; myDividerPending = 0; myDividerChangeCounter = -1; setDivider(1); updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::grp(uInt8 pattern) { const uInt8 oldPatternNew = myPatternNew; myPatternNew = pattern; if (!myIsDelaying && myPatternNew != oldPatternNew) { myTIA->flushLineCache(); updatePattern(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::hmp(uInt8 value) { myHmmClocks = (value >> 4) ^ 0x08; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::nusiz(uInt8 value, bool hblank) { myDecodesOffset = value & 0x07; switch (myDecodesOffset) { case 5: myDividerPending = 2; break; case 7: myDividerPending = 4; break; default: myDividerPending = 1; break; } const uInt8* oldDecodes = myDecodes; myDecodes = DrawCounterDecodes::get().playerDecodes()[myDecodesOffset]; if ( myDecodes != oldDecodes && myIsRendering && (myRenderCounter - Count::renderCounterOffset) < 2 && !myDecodes[(myCounter - myRenderCounter + Count::renderCounterOffset + 159) % 160] ) { myIsRendering = false; } if (myDividerPending == myDivider) return; // The following is an effective description of the effects of NUSIZ during // decode and rendering. if (myIsRendering) { Int8 delta = myRenderCounter - Count::renderCounterOffset; switch ((myDivider << 4) | myDividerPending) { case 0x12: case 0x14: if (hblank) { if (delta < 4) setDivider(myDividerPending); else myDividerChangeCounter = (delta < 5 ? 1 : 0); } else { if (delta < 3) setDivider(myDividerPending); else myDividerChangeCounter = 1; } break; case 0x21: case 0x41: if (delta < (hblank ? 4 : 3)) { setDivider(myDividerPending); } else if (delta < (hblank ? 6 : 5)) { setDivider(myDividerPending); myRenderCounter--; } else { myDividerChangeCounter = (hblank ? 0 : 1); } break; case 0x42: case 0x24: if (myRenderCounter < 1 || (hblank && (myRenderCounter % myDivider == 1))) setDivider(myDividerPending); else myDividerChangeCounter = (myDivider - (myRenderCounter - 1) % myDivider); break; default: // should never happen setDivider(myDividerPending); break; } } else { setDivider(myDividerPending); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::resp(uInt8 counter) { myCounter = counter; // This tries to account for the effects of RESP during draw counter decode as // described in Andrew Towers' notes. Still room for tuning.' if (myIsRendering && (myRenderCounter - renderCounterOffset) < 4) myRenderCounter = renderCounterOffset + (counter - 157); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::refp(uInt8 value) { const bool oldIsReflected = myIsReflected; myIsReflected = (value & 0x08) > 0; if (oldIsReflected != myIsReflected) { myTIA->flushLineCache(); updatePattern(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::vdelp(uInt8 value) { const bool oldIsDelaying = myIsDelaying; myIsDelaying = (value & 0x01) > 0; if (oldIsDelaying != myIsDelaying) { myTIA->flushLineCache(); updatePattern(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::toggleEnabled(bool enabled) { const bool oldIsSuppressed = myIsSuppressed; myIsSuppressed = !enabled; if (oldIsSuppressed != myIsSuppressed) updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::toggleCollisions(bool enabled) { myCollisionMaskEnabled = enabled ? 0xFFFF : (0x8000 | myCollisionMaskDisabled); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::setColor(uInt8 color) { if (color != myObjectColor && myPattern) myTIA->flushLineCache(); myObjectColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::setDebugColor(uInt8 color) { myTIA->flushLineCache(); myDebugColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::enableDebugColors(bool enabled) { myTIA->flushLineCache(); myDebugEnabled = enabled; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::applyColorLoss() { myTIA->flushLineCache(); applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::startMovement() { myIsMoving = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Player::movementTick(uInt32 clock, bool apply) { if (clock == myHmmClocks) { myIsMoving = false; } if (myIsMoving && apply) tick(); return myIsMoving; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::tick() { if (!myIsRendering || myRenderCounter < myRenderCounterTripPoint) collision = myCollisionMaskDisabled; else collision = (myPattern & (1 << mySampleCounter)) ? myCollisionMaskEnabled : myCollisionMaskDisabled; if (myDecodes[myCounter]) { myIsRendering = true; mySampleCounter = 0; myRenderCounter = Count::renderCounterOffset; } else if (myIsRendering) { myRenderCounter++; switch (myDivider) { case 1: if (myRenderCounter > 0) mySampleCounter++; if (myRenderCounter >= 0 && myDividerChangeCounter >= 0 && myDividerChangeCounter-- == 0) setDivider(myDividerPending); break; default: if (myRenderCounter > 1 && (((myRenderCounter - 1) % myDivider) == 0)) mySampleCounter++; if (myRenderCounter > 0 && myDividerChangeCounter >= 0 && myDividerChangeCounter-- == 0) setDivider(myDividerPending); break; } if (mySampleCounter > 7) myIsRendering = false; } if (++myCounter >= 160) myCounter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::shufflePatterns() { const uInt8 oldPatternOld = myPatternOld; myPatternOld = myPatternNew; if (myIsDelaying && myPatternOld != oldPatternOld) { myTIA->flushLineCache(); updatePattern(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Player::getRespClock() const { switch (myDivider) { case 1: return (myCounter + 160 - 5) % 160; case 2: return (myCounter + 160 - 9) % 160; case 4: return (myCounter + 160 - 12) % 160; default: throw runtime_error("invalid width"); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::setGRPOld(uInt8 pattern) { myTIA->flushLineCache(); myPatternOld = pattern; updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::updatePattern() { if (myIsSuppressed) { myPattern = 0; return; } myPattern = myIsDelaying ? myPatternOld : myPatternNew; if (!myIsReflected) { myPattern = ( ((myPattern & 0x01) << 7) | ((myPattern & 0x02) << 5) | ((myPattern & 0x04) << 3) | ((myPattern & 0x08) << 1) | ((myPattern & 0x10) >> 1) | ((myPattern & 0x20) >> 3) | ((myPattern & 0x40) >> 5) | ((myPattern & 0x80) >> 7) ); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::setDivider(uInt8 divider) { myDivider = divider; myRenderCounterTripPoint = divider == 1 ? 0 : 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::applyColors() { if (!myDebugEnabled) { if (myTIA->colorLossActive()) myObjectColor |= 0x01; else myObjectColor &= 0xfe; myColor = myObjectColor; } else myColor = myDebugColor; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Player::getPosition() const { // Wide players are shifted by one pixel to the right const uInt8 shift = myDivider == 1 ? 0 : 1; // position = // current playfield x + // (current counter - 156 (the decode clock of copy 0)) + // clock count after decode until first pixel + // shift (accounts for wide player shift) + // 1 (it'll take another cycle after the decode for the rendter counter to start ticking) // // The result may be negative, so we add 160 and do the modulus -> 317 = 156 + 160 + 1 // // Mind the sign of renderCounterOffset: it's defined negative above return (317 - myCounter - Count::renderCounterOffset + shift + myTIA->getPosition()) % 160; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Player::setPosition(uInt8 newPosition) { myTIA->flushLineCache(); const uInt8 shift = myDivider == 1 ? 0 : 1; // See getPosition for an explanation myCounter = (317 - newPosition - Count::renderCounterOffset + shift + myTIA->getPosition()) % 160; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Player::save(Serializer& out) const { try { out.putString(name()); out.putInt(collision); out.putInt(myCollisionMaskDisabled); out.putInt(myCollisionMaskEnabled); out.putByte(myColor); out.putByte(myObjectColor); out.putByte(myDebugColor); out.putBool(myDebugEnabled); out.putBool(myIsSuppressed); out.putByte(myHmmClocks); out.putByte(myCounter); out.putBool(myIsMoving); out.putBool(myIsRendering); out.putByte(myRenderCounter); out.putByte(myRenderCounterTripPoint); out.putByte(myDivider); out.putByte(myDividerPending); out.putByte(mySampleCounter); out.putByte(myDividerChangeCounter); out.putByte(myDecodesOffset); out.putByte(myPatternOld); out.putByte(myPatternNew); out.putByte(myPattern); out.putBool(myIsReflected); out.putBool(myIsDelaying); } catch(...) { cerr << "ERROR: TIA_Player::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Player::load(Serializer& in) { try { if(in.getString() != name()) return false; collision = in.getInt(); myCollisionMaskDisabled = in.getInt(); myCollisionMaskEnabled = in.getInt(); myColor = in.getByte(); myObjectColor = in.getByte(); myDebugColor = in.getByte(); myDebugEnabled = in.getBool(); myIsSuppressed = in.getBool(); myHmmClocks = in.getByte(); myCounter = in.getByte(); myIsMoving = in.getBool(); myIsRendering = in.getBool(); myRenderCounter = in.getByte(); myRenderCounterTripPoint = in.getByte(); myDivider = in.getByte(); myDividerPending = in.getByte(); mySampleCounter = in.getByte(); myDividerChangeCounter = in.getByte(); myDecodesOffset = in.getByte(); myDecodes = DrawCounterDecodes::get().playerDecodes()[myDecodesOffset]; myPatternOld = in.getByte(); myPatternNew = in.getByte(); myPattern = in.getByte(); myIsReflected = in.getBool(); myIsDelaying = in.getBool(); applyColors(); } catch(...) { cerr << "ERROR: TIA_Player::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/tia/Player.hxx000066400000000000000000000060531324334165500200040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_PLAYER #define TIA_PLAYER #include "bspf.hxx" #include "Serializable.hxx" class TIA; class Player : public Serializable { public: Player(uInt32 collisionMask); public: void setTIA(TIA* tia) { myTIA = tia; } void reset(); void grp(uInt8 value); void hmp(uInt8 value); void nusiz(uInt8 value, bool hblank); void resp(uInt8 counter); void refp(uInt8 value); void vdelp(uInt8 value); void toggleEnabled(bool enabled); void toggleCollisions(bool enabled); void setColor(uInt8 color); void setDebugColor(uInt8 color); void enableDebugColors(bool enabled); void applyColorLoss(); void startMovement(); bool movementTick(uInt32 clock, bool apply); void tick(); uInt8 getClock() const { return myCounter; } bool isOn() const { return (collision & 0x8000); } uInt8 getColor() const { return myColor; } void shufflePatterns(); uInt8 getRespClock() const; uInt8 getPosition() const; void setPosition(uInt8 newPosition); uInt8 getGRPOld() const { return myPatternOld; } uInt8 getGRPNew() const { return myPatternNew; } void setGRPOld(uInt8 pattern); /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override { return "TIA_Player"; } public: uInt32 collision; private: void updatePattern(); void applyColors(); void setDivider(uInt8 divider); private: uInt32 myCollisionMaskDisabled; uInt32 myCollisionMaskEnabled; uInt8 myColor; uInt8 myObjectColor, myDebugColor; bool myDebugEnabled; bool myIsSuppressed; uInt8 myHmmClocks; uInt8 myCounter; bool myIsMoving; bool myIsRendering; Int8 myRenderCounter; Int8 myRenderCounterTripPoint; uInt8 myDivider; uInt8 myDividerPending; uInt8 mySampleCounter; Int8 myDividerChangeCounter; const uInt8* myDecodes; uInt8 myDecodesOffset; // needed for state saving uInt8 myPatternOld; uInt8 myPatternNew; uInt8 myPattern; bool myIsReflected; bool myIsDelaying; TIA* myTIA; private: Player(const Player&) = delete; Player(Player&&) = delete; Player& operator=(const Player&) = delete; Player& operator=(Player&&) = delete; }; #endif // TIA_PLAYER stella-5.1.1/src/emucore/tia/Playfield.cxx000066400000000000000000000212761324334165500204600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Playfield.hxx" #include "TIA.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Playfield::Playfield(uInt32 collisionMask) : myCollisionMaskDisabled(collisionMask), myCollisionMaskEnabled(0xFFFF), myIsSuppressed(false) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::reset() { myPattern = 0; myReflected = false; myRefp = false; myPf0 = 0; myPf1 = 0; myPf2 = 0; myObjectColor = myDebugColor = 0; myColorP0 = 0; myColorP1 = 0; myColorMode = ColorMode::normal; myDebugEnabled = false; collision = 0; updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::pf0(uInt8 value) { if (myPf0 == value >> 4) return; myTIA->flushLineCache(); myPattern = (myPattern & 0x000FFFF0) | (value >> 4); myPf0 = value >> 4; updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::pf1(uInt8 value) { if (myPf1 == value) return; myTIA->flushLineCache(); myPattern = (myPattern & 0x000FF00F) | ((value & 0x80) >> 3) | ((value & 0x40) >> 1) | ((value & 0x20) << 1) | ((value & 0x10) << 3) | ((value & 0x08) << 5) | ((value & 0x04) << 7) | ((value & 0x02) << 9) | ((value & 0x01) << 11); myPf1 = value; updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::pf2(uInt8 value) { if (myPf2 == value) return; myTIA->flushLineCache(); myPattern = (myPattern & 0x00000FFF) | (value << 12); myPf2 = value; updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::ctrlpf(uInt8 value) { const bool reflected = (value & 0x01) > 0; const ColorMode colorMode = (value & 0x06) == 0x02 ? ColorMode::score : ColorMode::normal; if (myReflected == reflected && myColorMode == colorMode) return; myTIA->flushLineCache(); myReflected = reflected; myColorMode = colorMode; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::toggleEnabled(bool enabled) { myIsSuppressed = !enabled; updatePattern(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::toggleCollisions(bool enabled) { myCollisionMaskEnabled = enabled ? 0xFFFF : (0x8000 | myCollisionMaskDisabled); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::setColor(uInt8 color) { if (color != myObjectColor && myColorMode == ColorMode::normal) myTIA->flushLineCache(); myObjectColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::setColorP0(uInt8 color) { if (color != myColorP0 && myColorMode == ColorMode::score) myTIA->flushLineCache(); myColorP0 = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::setColorP1(uInt8 color) { if (color != myColorP1 && myColorMode == ColorMode::score) myTIA->flushLineCache(); myColorP1 = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::setDebugColor(uInt8 color) { myTIA->flushLineCache(); // allow slight luminance variations without changing color if((color & 0xe) == 0xe) color -= 2; if((color & 0xe) == 0x0) color += 2; myDebugColor = color; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::enableDebugColors(bool enabled) { myTIA->flushLineCache(); myDebugEnabled = enabled; applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::applyColorLoss() { myTIA->flushLineCache(); applyColors(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::tick(uInt32 x) { myX = x; if (myX == 80 || myX == 0) myRefp = myReflected; if (x & 0x03) return; uInt32 currentPixel; if (myEffectivePattern == 0) { currentPixel = 0; } else if (x < 80) { currentPixel = myEffectivePattern & (1 << (x >> 2)); } else if (myRefp) { currentPixel = myEffectivePattern & (1 << (39 - (x >> 2))); } else { currentPixel = myEffectivePattern & (1 << ((x >> 2) - 20)); } collision = currentPixel ? myCollisionMaskEnabled : myCollisionMaskDisabled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::applyColors() { if (myDebugEnabled) myColorLeft = myColorRight = myDebugColor; else { switch (myColorMode) { case ColorMode::normal: if (myTIA->colorLossActive()) myColorLeft = myColorRight = myObjectColor |= 0x01; else myColorLeft = myColorRight = myObjectColor &= 0xfe; break; case ColorMode::score: if (myTIA->colorLossActive()) { myColorLeft = myColorP0 |= 0x01; myColorRight = myColorP1 |= 0x01; } else { myColorLeft = myColorP0 &= 0xfe; myColorRight = myColorP1 &= 0xfe; } break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 Playfield::getColor() const { if (!myDebugEnabled) return myX < 80 ? myColorLeft : myColorRight; else { if (myX < 80) { // left side: if(myX < 16) return myDebugColor - 2; // PF0 if(myX < 48) return myDebugColor; // PF1 } else { // right side: if(!myReflected) { if(myX < 80 + 16) return myDebugColor - 2; // PF0 if(myX < 80 + 48) return myDebugColor; // PF1 } else { if(myX >= 160 - 16) return myDebugColor - 2; // PF0 if(myX >= 160 - 48) return myDebugColor; // PF1 } } return myDebugColor + 2; // PF2 } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Playfield::updatePattern() { myEffectivePattern = myIsSuppressed ? 0 : myPattern; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Playfield::save(Serializer& out) const { try { out.putString(name()); out.putInt(collision); out.putInt(myCollisionMaskDisabled); out.putInt(myCollisionMaskEnabled); out.putBool(myIsSuppressed); out.putByte(myColorLeft); out.putByte(myColorRight); out.putByte(myColorP0); out.putByte(myColorP1); out.putByte(myObjectColor); out.putByte(myDebugColor); out.putBool(myDebugEnabled); out.putByte(myColorMode); out.putInt(myPattern); out.putInt(myEffectivePattern); out.putBool(myRefp); out.putBool(myReflected); out.putByte(myPf0); out.putByte(myPf1); out.putByte(myPf2); out.putInt(myX); } catch(...) { cerr << "ERROR: TIA_Playfield::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Playfield::load(Serializer& in) { try { if(in.getString() != name()) return false; collision = in.getInt(); myCollisionMaskDisabled = in.getInt(); myCollisionMaskEnabled = in.getInt(); myIsSuppressed = in.getBool(); myColorLeft = in.getByte(); myColorRight = in.getByte(); myColorP0 = in.getByte(); myColorP1 = in.getByte(); myObjectColor = in.getByte(); myDebugColor = in.getByte(); myDebugEnabled = in.getBool(); myColorMode = ColorMode(in.getByte()); myPattern = in.getInt(); myEffectivePattern = in.getInt(); myRefp = in.getBool(); myReflected = in.getBool(); myPf0 = in.getByte(); myPf1 = in.getByte(); myPf2 = in.getByte(); myX = in.getInt(); applyColors(); updatePattern(); } catch(...) { cerr << "ERROR: TIA_Playfield::load" << endl; return false; } return true; } stella-5.1.1/src/emucore/tia/Playfield.hxx000066400000000000000000000050251324334165500204570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_PLAYFIELD #define TIA_PLAYFIELD #include "Serializable.hxx" #include "bspf.hxx" class TIA; class Playfield : public Serializable { public: Playfield(uInt32 collisionMask); public: void setTIA(TIA* tia) { myTIA = tia; } void reset(); void pf0(uInt8 value); void pf1(uInt8 value); void pf2(uInt8 value); void ctrlpf(uInt8 value); void toggleEnabled(bool enabled); void toggleCollisions(bool enabled); void setColor(uInt8 color); void setColorP0(uInt8 color); void setColorP1(uInt8 color); void setDebugColor(uInt8 color); void enableDebugColors(bool enabled); void applyColorLoss(); void tick(uInt32 x); bool isOn() const { return (collision & 0x8000); } uInt8 getColor() const; /** Serializable methods (see that class for more information). */ bool save(Serializer& out) const override; bool load(Serializer& in) override; string name() const override { return "TIA_Playfield"; } public: uInt32 collision; private: enum ColorMode: uInt8 {normal, score}; private: void applyColors(); void updatePattern(); private: uInt32 myCollisionMaskDisabled; uInt32 myCollisionMaskEnabled; bool myIsSuppressed; uInt8 myColorLeft; uInt8 myColorRight; uInt8 myColorP0; uInt8 myColorP1; uInt8 myObjectColor, myDebugColor; bool myDebugEnabled; ColorMode myColorMode; uInt32 myPattern; uInt32 myEffectivePattern; bool myRefp; bool myReflected; uInt8 myPf0; uInt8 myPf1; uInt8 myPf2; uInt32 myX; TIA* myTIA; private: Playfield() = delete; Playfield(const Playfield&) = delete; Playfield(Playfield&&) = delete; Playfield& operator=(const Playfield&) = delete; Playfield& operator=(Playfield&&) = delete; }; #endif // TIA_PLAYFIELD stella-5.1.1/src/emucore/tia/TIA.cxx000066400000000000000000001324411324334165500171610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "TIA.hxx" #include "M6502.hxx" #include "Console.hxx" #include "Control.hxx" #include "Paddles.hxx" #include "DelayQueueIteratorImpl.hxx" #include "TIAConstants.hxx" #include "frame-manager/FrameManager.hxx" #ifdef DEBUGGER_SUPPORT #include "CartDebug.hxx" #endif enum CollisionMask: uInt32 { player0 = 0b0111110000000000, player1 = 0b0100001111000000, missile0 = 0b0010001000111000, missile1 = 0b0001000100100110, ball = 0b0000100010010101, playfield = 0b0000010001001011 }; enum Delay: uInt8 { hmove = 6, pf = 2, grp = 1, shufflePlayer = 1, shuffleBall = 1, hmp = 2, hmm = 2, hmbl = 2, hmclr = 2, refp = 1, enabl = 1, enam = 1, vblank = 1 }; enum ResxCounter: uInt8 { hblank = 159, lateHblank = 158, frame = 157 }; // This parameter still has room for tuning. If we go lower than 73, long005 will show // a slight artifact (still have to crosscheck on real hardware), if we go lower than // 70, the G.I. Joe will show an artifact (hole in roof). static constexpr uInt8 resxLateHblankThreshold = 73; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA::TIA(Console& console, Sound& sound, Settings& settings) : myConsole(console), mySound(sound), mySettings(settings), myFrameManager(nullptr), myPlayfield(~CollisionMask::playfield & 0x7FFF), myMissile0(~CollisionMask::missile0 & 0x7FFF), myMissile1(~CollisionMask::missile1 & 0x7FFF), myPlayer0(~CollisionMask::player0 & 0x7FFF), myPlayer1(~CollisionMask::player1 & 0x7FFF), myBall(~CollisionMask::ball & 0x7FFF), mySpriteEnabledBits(0xFF), myCollisionsEnabledBits(0xFF) { bool devSettings = mySettings.getBool("dev.settings"); myTIAPinsDriven = mySettings.getBool(devSettings ? "dev.tiadriven" : "plr.tiadriven"); myBackground.setTIA(this); myPlayfield.setTIA(this); myPlayer0.setTIA(this); myPlayer1.setTIA(this); myMissile0.setTIA(this); myMissile1.setTIA(this); myBall.setTIA(this); myEnableJitter = mySettings.getBool(devSettings ? "dev.tv.jitter" : "plr.tv.jitter"); myJitterFactor = mySettings.getInt(devSettings ? "dev.tv.jitter_recovery" : "plr.tv.jitter_recovery"); reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::setFrameManager(AbstractFrameManager *frameManager) { clearFrameManager(); myFrameManager = frameManager; myFrameManager->setHandlers( [this] () { onFrameStart(); }, [this] () { onFrameComplete(); } ); myFrameManager->enableJitter(myEnableJitter); myFrameManager->setJitterFactor(myJitterFactor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::clearFrameManager() { if (!myFrameManager) return; myFrameManager->clearHandlers(); myFrameManager = nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::reset() { myHctr = 0; myMovementInProgress = false; myExtendedHblank = false; myMovementClock = 0; myPriority = Priority::normal; myHstate = HState::blank; myCollisionMask = 0; myLinesSinceChange = 0; myCollisionUpdateRequired = false; myAutoFrameEnabled = false; myColorLossEnabled = myColorLossActive = false; myColorHBlank = 0; myLastCycle = 0; mySubClock = 0; myHctrDelta = 0; myXAtRenderingStart = 0; memset(myShadowRegisters, 0, 64); myBackground.reset(); myPlayfield.reset(); myMissile0.reset(); myMissile1.reset(); myPlayer0.reset(); myPlayer1.reset(); myBall.reset(); myInput0.reset(); myInput1.reset(); myTimestamp = 0; for (PaddleReader& paddleReader : myPaddleReaders) paddleReader.reset(myTimestamp); mySound.reset(); myDelayQueue.reset(); if (myFrameManager) myFrameManager->reset(); myCyclesAtFrameStart = 0; frameReset(); // Recalculate the size of the display // Must be done last, after all other items have reset enableFixedColors(mySettings.getBool(mySettings.getBool("dev.settings") ? "dev.debugcolors" : "plr.debugcolors")); setFixedColorPalette(mySettings.getString("tia.dbgcolors")); #ifdef DEBUGGER_SUPPORT createAccessBase(); #endif // DEBUGGER_SUPPORT } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::frameReset() { memset(myFramebuffer, 0, 160 * TIAConstants::frameBufferHeight); myAutoFrameEnabled = mySettings.getInt("framerate") <= 0; enableColorLoss(mySettings.getBool("dev.settings") ? "dev.colorloss" : "plr.colorloss"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::install(System& system) { installDelegate(system, *this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::installDelegate(System& system, Device& device) { // Remember which system I'm installed in mySystem = &system; // All accesses are to the given device System::PageAccess access(&device, System::PA_READWRITE); // Map all peek/poke to mirrors of TIA address space to this class // That is, all mirrors of ($00 - $3F) in the lower 4K of the 2600 // address space are mapped here for(uInt16 addr = 0; addr < 0x1000; addr += System::PAGE_SIZE) if((addr & TIA_BIT) == 0x0000) mySystem->setPageAccess(addr, access); mySystem->m6502().setOnHaltCallback( [this] () { onHalt(); } ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::save(Serializer& out) const { try { out.putString(name()); if(!mySound.save(out)) return false; if(!myDelayQueue.save(out)) return false; if(!myFrameManager->save(out)) return false; if(!myBackground.save(out)) return false; if(!myPlayfield.save(out)) return false; if(!myMissile0.save(out)) return false; if(!myMissile1.save(out)) return false; if(!myPlayer0.save(out)) return false; if(!myPlayer1.save(out)) return false; if(!myBall.save(out)) return false; for (const PaddleReader& paddleReader : myPaddleReaders) if(!paddleReader.save(out)) return false; if(!myInput0.save(out)) return false; if(!myInput1.save(out)) return false; out.putBool(myTIAPinsDriven); out.putInt(int(myHstate)); out.putInt(myHctr); out.putInt(myHctrDelta); out.putInt(myXAtRenderingStart); out.putBool(myCollisionUpdateRequired); out.putInt(myCollisionMask); out.putInt(myMovementClock); out.putBool(myMovementInProgress); out.putBool(myExtendedHblank); out.putInt(myLinesSinceChange); out.putInt(int(myPriority)); out.putByte(mySubClock); out.putLong(myLastCycle); out.putByte(mySpriteEnabledBits); out.putByte(myCollisionsEnabledBits); out.putByte(myColorHBlank); out.putDouble(myTimestamp); out.putBool(myAutoFrameEnabled); out.putByteArray(myShadowRegisters, 64); out.putLong(myCyclesAtFrameStart); } catch(...) { cerr << "ERROR: TIA::save" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::load(Serializer& in) { try { if(in.getString() != name()) return false; if(!mySound.load(in)) return false; if(!myDelayQueue.load(in)) return false; if(!myFrameManager->load(in)) return false; if(!myBackground.load(in)) return false; if(!myPlayfield.load(in)) return false; if(!myMissile0.load(in)) return false; if(!myMissile1.load(in)) return false; if(!myPlayer0.load(in)) return false; if(!myPlayer1.load(in)) return false; if(!myBall.load(in)) return false; for (PaddleReader& paddleReader : myPaddleReaders) if(!paddleReader.load(in)) return false; if(!myInput0.load(in)) return false; if(!myInput1.load(in)) return false; myTIAPinsDriven = in.getBool(); myHstate = HState(in.getInt()); myHctr = in.getInt(); myHctrDelta = in.getInt(); myXAtRenderingStart = in.getInt(); myCollisionUpdateRequired = in.getBool(); myCollisionMask = in.getInt(); myMovementClock = in.getInt(); myMovementInProgress = in.getBool(); myExtendedHblank = in.getBool(); myLinesSinceChange = in.getInt(); myPriority = Priority(in.getInt()); mySubClock = in.getByte(); myLastCycle = in.getLong(); mySpriteEnabledBits = in.getByte(); myCollisionsEnabledBits = in.getByte(); myColorHBlank = in.getByte(); myTimestamp = in.getDouble(); myAutoFrameEnabled = in.getBool(); in.getByteArray(myShadowRegisters, 64); myCyclesAtFrameStart = in.getLong(); } catch(...) { cerr << "ERROR: TIA::load" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::bindToControllers() { myConsole.leftController().setOnAnalogPinUpdateCallback( [this] (Controller::AnalogPin pin) { updateEmulation(); switch (pin) { case Controller::AnalogPin::Five: updatePaddle(1); break; case Controller::AnalogPin::Nine: updatePaddle(0); break; } } ); myConsole.rightController().setOnAnalogPinUpdateCallback( [this] (Controller::AnalogPin pin) { updateEmulation(); switch (pin) { case Controller::AnalogPin::Five: updatePaddle(3); break; case Controller::AnalogPin::Nine: updatePaddle(2); break; } } ); for (uInt8 i = 0; i < 4; i++) updatePaddle(i); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::peek(uInt16 address) { updateEmulation(); // If pins are undriven, we start with the last databus value // Otherwise, there is some randomness injected into the mix // In either case, we start out with D7 and D6 disabled (the only // valid bits in a TIA read), and selectively enable them uInt8 lastDataBusValue = !myTIAPinsDriven ? mySystem->getDataBusState() : mySystem->getDataBusState(0xFF); uInt8 result; switch (address & 0x0F) { case CXM0P: result = collCXM0P(); break; case CXM1P: result = collCXM1P(); break; case CXP0FB: result = collCXP0FB(); break; case CXP1FB: result = collCXP1FB(); break; case CXM0FB: result = collCXM0FB(); break; case CXM1FB: result = collCXM1FB(); break; case CXPPMM: result = collCXPPMM(); break; case CXBLPF: result = collCXBLPF(); break; case INPT0: updatePaddle(0); result = myPaddleReaders[0].inpt(myTimestamp) | (lastDataBusValue & 0x40); break; case INPT1: updatePaddle(1); result = myPaddleReaders[1].inpt(myTimestamp) | (lastDataBusValue & 0x40); break; case INPT2: updatePaddle(2); result = myPaddleReaders[2].inpt(myTimestamp) | (lastDataBusValue & 0x40); break; case INPT3: updatePaddle(3); result = myPaddleReaders[3].inpt(myTimestamp) | (lastDataBusValue & 0x40); break; case INPT4: result = myInput0.inpt(!myConsole.leftController().read(Controller::Six)) | (lastDataBusValue & 0x40); break; case INPT5: result = myInput1.inpt(!myConsole.rightController().read(Controller::Six)) | (lastDataBusValue & 0x40); break; default: result = 0; } return (result & 0xC0) | (lastDataBusValue & 0x3F); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::poke(uInt16 address, uInt8 value) { updateEmulation(); address &= 0x3F; switch (address) { case WSYNC: mySystem->m6502().requestHalt(); break; case RSYNC: flushLineCache(); applyRsync(); myShadowRegisters[address] = value; break; case VSYNC: myFrameManager->setVsync(value & 0x02); myShadowRegisters[address] = value; break; case VBLANK: myInput0.vblank(value); myInput1.vblank(value); for (PaddleReader& paddleReader : myPaddleReaders) paddleReader.vblank(value, myTimestamp); myDelayQueue.push(VBLANK, value, Delay::vblank); break; //////////////////////////////////////////////////////////// // FIXME - rework this when we add the new sound core case AUDV0: mySound.set(address, value, mySystem->cycles()); myShadowRegisters[address] = value; break; case AUDV1: mySound.set(address, value, mySystem->cycles()); myShadowRegisters[address] = value; break; case AUDF0: mySound.set(address, value, mySystem->cycles()); myShadowRegisters[address] = value; break; case AUDF1: mySound.set(address, value, mySystem->cycles()); myShadowRegisters[address] = value; break; case AUDC0: mySound.set(address, value, mySystem->cycles()); myShadowRegisters[address] = value; break; case AUDC1: mySound.set(address, value, mySystem->cycles()); myShadowRegisters[address] = value; break; //////////////////////////////////////////////////////////// case HMOVE: myDelayQueue.push(HMOVE, value, Delay::hmove); break; case COLUBK: myBackground.setColor(value & 0xFE); myShadowRegisters[address] = value; break; case COLUP0: value &= 0xFE; myPlayfield.setColorP0(value); myMissile0.setColor(value); myPlayer0.setColor(value); myShadowRegisters[address] = value; break; case COLUP1: value &= 0xFE; myPlayfield.setColorP1(value); myMissile1.setColor(value); myPlayer1.setColor(value); myShadowRegisters[address] = value; break; case CTRLPF: flushLineCache(); myPriority = (value & 0x04) ? Priority::pfp : (value & 0x02) ? Priority::score : Priority::normal; myPlayfield.ctrlpf(value); myBall.ctrlpf(value); myShadowRegisters[address] = value; break; case COLUPF: flushLineCache(); value &= 0xFE; myPlayfield.setColor(value); myBall.setColor(value); myShadowRegisters[address] = value; break; case PF0: { myDelayQueue.push(PF0, value, Delay::pf); #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); #endif break; } case PF1: { myDelayQueue.push(PF1, value, Delay::pf); #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); #endif break; } case PF2: { myDelayQueue.push(PF2, value, Delay::pf); #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::PGFX); #endif break; } case ENAM0: myDelayQueue.push(ENAM0, value, Delay::enam); break; case ENAM1: myDelayQueue.push(ENAM1, value, Delay::enam); break; case RESM0: flushLineCache(); myMissile0.resm(resxCounter(), myHstate == HState::blank); myShadowRegisters[address] = value; break; case RESM1: flushLineCache(); myMissile1.resm(resxCounter(), myHstate == HState::blank); myShadowRegisters[address] = value; break; case RESMP0: myMissile0.resmp(value, myPlayer0); myShadowRegisters[address] = value; break; case RESMP1: myMissile1.resmp(value, myPlayer1); myShadowRegisters[address] = value; break; case NUSIZ0: flushLineCache(); myMissile0.nusiz(value); myPlayer0.nusiz(value, myHstate == HState::blank); myShadowRegisters[address] = value; break; case NUSIZ1: flushLineCache(); myMissile1.nusiz(value); myPlayer1.nusiz(value, myHstate == HState::blank); myShadowRegisters[address] = value; break; case HMM0: myDelayQueue.push(HMM0, value, Delay::hmm); break; case HMM1: myDelayQueue.push(HMM1, value, Delay::hmm); break; case HMCLR: myDelayQueue.push(HMCLR, value, Delay::hmclr); break; case GRP0: { myDelayQueue.push(GRP0, value, Delay::grp); myDelayQueue.push(DummyRegisters::shuffleP1, 0, Delay::shufflePlayer); #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::GFX); #endif break; } case GRP1: { myDelayQueue.push(GRP1, value, Delay::grp); myDelayQueue.push(DummyRegisters::shuffleP0, 0, Delay::shufflePlayer); myDelayQueue.push(DummyRegisters::shuffleBL, 0, Delay::shuffleBall); #ifdef DEBUGGER_SUPPORT uInt16 dataAddr = mySystem->m6502().lastDataAddressForPoke(); if(dataAddr) mySystem->setAccessFlags(dataAddr, CartDebug::GFX); #endif break; } case RESP0: flushLineCache(); myPlayer0.resp(resxCounter()); myShadowRegisters[address] = value; break; case RESP1: flushLineCache(); myPlayer1.resp(resxCounter()); myShadowRegisters[address] = value; break; case REFP0: myDelayQueue.push(REFP0, value, Delay::refp); break; case REFP1: myDelayQueue.push(REFP1, value, Delay::refp); break; case VDELP0: myPlayer0.vdelp(value); myShadowRegisters[address] = value; break; case VDELP1: myPlayer1.vdelp(value); myShadowRegisters[address] = value; break; case HMP0: myDelayQueue.push(HMP0, value, Delay::hmp); break; case HMP1: myDelayQueue.push(HMP1, value, Delay::hmp); break; case ENABL: myDelayQueue.push(ENABL, value, Delay::enabl); break; case RESBL: flushLineCache(); myBall.resbl(resxCounter()); myShadowRegisters[address] = value; break; case VDELBL: myBall.vdelbl(value); myShadowRegisters[address] = value; break; case HMBL: myDelayQueue.push(HMBL, value, Delay::hmbl); break; case CXCLR: flushLineCache(); myCollisionMask = 0; myShadowRegisters[address] = value; break; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::saveDisplay(Serializer& out) const { try { out.putByteArray(myFramebuffer, 160*TIAConstants::frameBufferHeight); } catch(...) { cerr << "ERROR: TIA::saveDisplay" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::loadDisplay(Serializer& in) { try { // Reset frame buffer pointer and data in.getByteArray(myFramebuffer, 160*TIAConstants::frameBufferHeight); } catch(...) { cerr << "ERROR: TIA::loadDisplay" << endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::update() { mySystem->m6502().execute(25000); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::enableColorLoss(bool enabled) { bool allowColorLoss = consoleTiming() == ConsoleTiming::pal; if(allowColorLoss && enabled) { myColorLossEnabled = true; myColorLossActive = myFrameManager->scanlinesLastFrame() & 0x1; } else { myColorLossEnabled = myColorLossActive = false; myMissile0.applyColorLoss(); myMissile1.applyColorLoss(); myPlayer0.applyColorLoss(); myPlayer1.applyColorLoss(); myBall.applyColorLoss(); myPlayfield.applyColorLoss(); myBackground.applyColorLoss(); } return allowColorLoss; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::electronBeamPos(uInt32& x, uInt32& y) const { uInt8 clocks = clocksThisLine(); x = (clocks < 68) ? 0 : clocks - 68; y = myFrameManager->getY(); return isRendering(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleBit(TIABit b, uInt8 mode) { uInt8 mask; switch (mode) { case 0: mask = 0; break; case 1: mask = b; break; default: mask = (~mySpriteEnabledBits & b); break; } mySpriteEnabledBits = (mySpriteEnabledBits & ~b) | mask; myMissile0.toggleEnabled(mySpriteEnabledBits & TIABit::M0Bit); myMissile1.toggleEnabled(mySpriteEnabledBits & TIABit::M1Bit); myPlayer0.toggleEnabled(mySpriteEnabledBits & TIABit::P0Bit); myPlayer1.toggleEnabled(mySpriteEnabledBits & TIABit::P1Bit); myBall.toggleEnabled(mySpriteEnabledBits & TIABit::BLBit); myPlayfield.toggleEnabled(mySpriteEnabledBits & TIABit::PFBit); return mask; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleBits() { toggleBit(TIABit(0xFF), mySpriteEnabledBits > 0 ? 0 : 1); return mySpriteEnabledBits; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleCollision(TIABit b, uInt8 mode) { uInt8 mask; switch (mode) { case 0: mask = 0; break; case 1: mask = b; break; default: mask = (~myCollisionsEnabledBits & b); break; } myCollisionsEnabledBits = (myCollisionsEnabledBits & ~b) | mask; myMissile0.toggleCollisions(myCollisionsEnabledBits & TIABit::M0Bit); myMissile1.toggleCollisions(myCollisionsEnabledBits & TIABit::M1Bit); myPlayer0.toggleCollisions(myCollisionsEnabledBits & TIABit::P0Bit); myPlayer1.toggleCollisions(myCollisionsEnabledBits & TIABit::P1Bit); myBall.toggleCollisions(myCollisionsEnabledBits & TIABit::BLBit); myPlayfield.toggleCollisions(myCollisionsEnabledBits & TIABit::PFBit); return mask; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleCollisions() { toggleCollision(TIABit(0xFF), myCollisionsEnabledBits > 0 ? 0 : 1); return myCollisionsEnabledBits; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::enableFixedColors(bool enable) { // This will be called during reset at a point where no frame manager // instance is available, so we guard aginst this here. int layout = 0; if (myFrameManager) layout = myFrameManager->layout() == FrameLayout::pal ? 1 : 0; myMissile0.setDebugColor(myFixedColorPalette[layout][FixedObject::M0]); myMissile1.setDebugColor(myFixedColorPalette[layout][FixedObject::M1]); myPlayer0.setDebugColor(myFixedColorPalette[layout][FixedObject::P0]); myPlayer1.setDebugColor(myFixedColorPalette[layout][FixedObject::P1]); myBall.setDebugColor(myFixedColorPalette[layout][FixedObject::BL]); myPlayfield.setDebugColor(myFixedColorPalette[layout][FixedObject::PF]); myBackground.setDebugColor(FixedColor::BK_GREY); myMissile0.enableDebugColors(enable); myMissile1.enableDebugColors(enable); myPlayer0.enableDebugColors(enable); myPlayer1.enableDebugColors(enable); myBall.enableDebugColors(enable); myPlayfield.enableDebugColors(enable); myBackground.enableDebugColors(enable); myColorHBlank = enable ? FixedColor::HBLANK_WHITE : 0x00; return enable; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::setFixedColorPalette(const string& colors) { string s = colors; sort(s.begin(), s.end()); if(s != "bgopry") return false; for(int i = 0; i < 6; ++i) { switch(colors[i]) { case 'r': myFixedColorPalette[0][i] = FixedColor::NTSC_RED; myFixedColorPalette[1][i] = FixedColor::PAL_RED; myFixedColorNames[i] = "Red "; break; case 'o': myFixedColorPalette[0][i] = FixedColor::NTSC_ORANGE; myFixedColorPalette[1][i] = FixedColor::PAL_ORANGE; myFixedColorNames[i] = "Orange"; break; case 'y': myFixedColorPalette[0][i] = FixedColor::NTSC_YELLOW; myFixedColorPalette[1][i] = FixedColor::PAL_YELLOW; myFixedColorNames[i] = "Yellow"; break; case 'g': myFixedColorPalette[0][i] = FixedColor::NTSC_GREEN; myFixedColorPalette[1][i] = FixedColor::PAL_GREEN; myFixedColorNames[i] = "Green "; break; case 'b': myFixedColorPalette[0][i] = FixedColor::NTSC_BLUE; myFixedColorPalette[1][i] = FixedColor::PAL_BLUE; myFixedColorNames[i] = "Blue "; break; case 'p': myFixedColorPalette[0][i] = FixedColor::NTSC_PURPLE; myFixedColorPalette[1][i] = FixedColor::PAL_PURPLE; myFixedColorNames[i] = "Purple"; break; } } // If already in fixed debug colours mode, update the current palette if(usingFixedColors()) enableFixedColors(true); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::driveUnusedPinsRandom(uInt8 mode) { // If mode is 0 or 1, use it as a boolean (off or on) // Otherwise, return the state if (mode == 0 || mode == 1) { myTIAPinsDriven = bool(mode); mySettings.setValue(mySettings.getBool("dev.settings") ? "dev.tiadriven" : "plr.tiadriven", myTIAPinsDriven); } return myTIAPinsDriven; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TIA::toggleJitter(uInt8 mode) { switch (mode) { case 0: myEnableJitter = false; break; case 1: myEnableJitter = true; break; case 2: myEnableJitter = !myEnableJitter; break; default: throw runtime_error("invalid argument for toggleJitter"); } if (myFrameManager) myFrameManager->enableJitter(myEnableJitter); return myEnableJitter; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::setJitterRecoveryFactor(Int32 factor) { myJitterFactor = factor; if (myFrameManager) myFrameManager->setJitterFactor(myJitterFactor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - shared_ptr TIA::delayQueueIterator() const { return shared_ptr( new DelayQueueIteratorImpl(myDelayQueue) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA& TIA::updateScanline() { // Update frame by one scanline at a time uInt32 line = scanlines(); while (line == scanlines() && mySystem->m6502().execute(1)); return *this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA& TIA::updateScanlineByStep() { // Update frame by one CPU instruction/color clock mySystem->m6502().execute(1); return *this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TIA& TIA::updateScanlineByTrace(int target) { uInt32 count = 100; // only try up to 100 steps while (mySystem->m6502().getPC() != target && count-- && mySystem->m6502().execute(1)); return *this; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::registerValue(uInt8 reg) const { return reg < 64 ? myShadowRegisters[reg] : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::updateEmulation() { const uInt64 systemCycles = mySystem->cycles(); if (mySubClock > 2) throw runtime_error("subclock exceeds range"); const uInt32 cyclesToRun = 3 * uInt32(systemCycles - myLastCycle) + mySubClock; mySubClock = 0; myLastCycle = systemCycles; cycle(cyclesToRun); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::onFrameStart() { myXAtRenderingStart = 0; // Check for colour-loss emulation if (myColorLossEnabled) { // Only activate it when necessary, since changing colours in // the graphical object forces the TIA cached line to be flushed if (myFrameManager->scanlineParityChanged()) { myColorLossActive = myFrameManager->scanlinesLastFrame() & 0x1; myMissile0.applyColorLoss(); myMissile1.applyColorLoss(); myPlayer0.applyColorLoss(); myPlayer1.applyColorLoss(); myBall.applyColorLoss(); myPlayfield.applyColorLoss(); myBackground.applyColorLoss(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::onFrameComplete() { mySystem->m6502().stop(); myCyclesAtFrameStart = mySystem->cycles(); if (myXAtRenderingStart > 0) memset(myFramebuffer, 0, myXAtRenderingStart); // Blank out any extra lines not drawn this frame const Int32 missingScanlines = myFrameManager->missingScanlines(); if (missingScanlines > 0) memset(myFramebuffer + 160 * myFrameManager->getY(), 0, missingScanlines * 160); // Recalculate framerate, attempting to auto-correct for scanline 'jumps' if(myAutoFrameEnabled) myConsole.setFramerate(myFrameManager->frameRate()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::onHalt() { mySubClock += (228 - myHctr) % 228; mySystem->incrementCycles(mySubClock / 3); mySubClock %= 3; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::cycle(uInt32 colorClocks) { for (uInt32 i = 0; i < colorClocks; i++) { myDelayQueue.execute( [this] (uInt8 address, uInt8 value) {delayedWrite(address, value);} ); myCollisionUpdateRequired = false; if (myLinesSinceChange < 2) { tickMovement(); if (myHstate == HState::blank) tickHblank(); else tickHframe(); if (myCollisionUpdateRequired && !myFrameManager->vblank()) updateCollision(); } if (++myHctr >= 228) nextLine(); myTimestamp++; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::tickMovement() { if (!myMovementInProgress) return; if ((myHctr & 0x03) == 0) { const bool apply = myHstate == HState::blank; bool m = false; uInt8 movementCounter = myMovementClock > 15 ? 0 : myMovementClock; m = myMissile0.movementTick(movementCounter, myHctr, apply) || m; m = myMissile1.movementTick(movementCounter, myHctr, apply) || m; m = myPlayer0.movementTick(movementCounter, apply) || m; m = myPlayer1.movementTick(movementCounter, apply) || m; m = myBall.movementTick(movementCounter, apply) || m; myMovementInProgress = m; myCollisionUpdateRequired = m; myMovementClock++; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::tickHblank() { switch (myHctr) { case 0: myExtendedHblank = false; break; case 67: if (!myExtendedHblank) myHstate = HState::frame; break; case 75: if (myExtendedHblank) myHstate = HState::frame; break; } if (myExtendedHblank && myHctr > 67) myPlayfield.tick(myHctr - 68 - myHctrDelta); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::tickHframe() { const uInt32 y = myFrameManager->getY(); const uInt32 x = myHctr - 68 - myHctrDelta; myCollisionUpdateRequired = true; myPlayfield.tick(x); myMissile0.tick(myHctr); myMissile1.tick(myHctr); myPlayer0.tick(); myPlayer1.tick(); myBall.tick(); if (myFrameManager->isRendering()) renderPixel(x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::applyRsync() { const uInt32 x = myHctr > 68 ? myHctr - 68 : 0; myHctrDelta = 225 - myHctr; if (myFrameManager->isRendering()) memset(myFramebuffer + myFrameManager->getY() * 160 + x, 0, 160 - x); myHctr = 225; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::nextLine() { if (myLinesSinceChange >= 2) { cloneLastLine(); } myPlayfield.tick(0); myHctr = 0; if (!myMovementInProgress && myLinesSinceChange < 2) myLinesSinceChange++; myHstate = HState::blank; myHctrDelta = 0; myFrameManager->nextLine(); if (myFrameManager->isRendering() && myFrameManager->getY() == 0) flushLineCache(); mySystem->m6502().clearHaltRequest(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::cloneLastLine() { const auto y = myFrameManager->getY(); if (!myFrameManager->isRendering() || y == 0) return; uInt8* buffer = myFramebuffer; memcpy(buffer + y * 160, buffer + (y-1) * 160, 160); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::updateCollision() { myCollisionMask |= ( myPlayer0.collision & myPlayer1.collision & myMissile0.collision & myMissile1.collision & myBall.collision & myPlayfield.collision ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::renderPixel(uInt32 x, uInt32 y) { if (x >= 160) return; uInt8 color = 0; if (!myFrameManager->vblank()) { switch (myPriority) { case Priority::pfp: // CTRLPF D2=1, D1=ignored // Playfield has priority so ScoreBit isn't used // Priority from highest to lowest: // BL/PF => P0/M0 => P1/M1 => BK if (myPlayfield.isOn()) color = myPlayfield.getColor(); else if (myBall.isOn()) color = myBall.getColor(); else if (myPlayer0.isOn()) color = myPlayer0.getColor(); else if (myMissile0.isOn()) color = myMissile0.getColor(); else if (myPlayer1.isOn()) color = myPlayer1.getColor(); else if (myMissile1.isOn()) color = myMissile1.getColor(); else color = myBackground.getColor(); break; case Priority::score: // CTRLPF D2=0, D1=1 // Formally we have (priority from highest to lowest) // PF/P0/M0 => P1/M1 => BL => BK // for the first half and // P0/M0 => PF/P1/M1 => BL => BK // for the second half. However, the first ordering is equivalent // to the second (PF has the same color as P0/M0), so we can just // write if (myPlayer0.isOn()) color = myPlayer0.getColor(); else if (myMissile0.isOn()) color = myMissile0.getColor(); else if (myPlayfield.isOn()) color = myPlayfield.getColor(); else if (myPlayer1.isOn()) color = myPlayer1.getColor(); else if (myMissile1.isOn()) color = myMissile1.getColor(); else if (myBall.isOn()) color = myBall.getColor(); else color = myBackground.getColor(); break; case Priority::normal: // CTRLPF D2=0, D1=0 // Priority from highest to lowest: // P0/M0 => P1/M1 => BL/PF => BK if (myPlayer0.isOn()) color = myPlayer0.getColor(); else if (myMissile0.isOn()) color = myMissile0.getColor(); else if (myPlayer1.isOn()) color = myPlayer1.getColor(); else if (myMissile1.isOn()) color = myMissile1.getColor(); else if (myPlayfield.isOn()) color = myPlayfield.getColor(); else if (myBall.isOn()) color = myBall.getColor(); else color = myBackground.getColor(); break; } } myFramebuffer[y * 160 + x] = color; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::flushLineCache() { const bool wasCaching = myLinesSinceChange >= 2; myLinesSinceChange = 0; if (wasCaching) { const auto rewindCycles = myHctr; for (myHctr = 0; myHctr < rewindCycles; myHctr++) { if (myHstate == HState::blank) tickHblank(); else tickHframe(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::clearHmoveComb() { if (myFrameManager->isRendering() && myHstate == HState::blank) memset(myFramebuffer + myFrameManager->getY() * 160, myColorHBlank, 8); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::delayedWrite(uInt8 address, uInt8 value) { if (address < 64) myShadowRegisters[address] = value; switch (address) { case VBLANK: flushLineCache(); myFrameManager->setVblank(value & 0x02); break; case HMOVE: flushLineCache(); myMovementClock = 0; myMovementInProgress = true; if (!myExtendedHblank) { clearHmoveComb(); myExtendedHblank = true; } myMissile0.startMovement(); myMissile1.startMovement(); myPlayer0.startMovement(); myPlayer1.startMovement(); myBall.startMovement(); break; case PF0: myPlayfield.pf0(value); break; case PF1: myPlayfield.pf1(value); break; case PF2: myPlayfield.pf2(value); break; case HMM0: myMissile0.hmm(value); break; case HMM1: myMissile1.hmm(value); break; case HMCLR: // We must update the shadow registers for each HM object too myMissile0.hmm(0); myShadowRegisters[HMM0] = 0; myMissile1.hmm(0); myShadowRegisters[HMM1] = 0; myPlayer0.hmp(0); myShadowRegisters[HMP0] = 0; myPlayer1.hmp(0); myShadowRegisters[HMP1] = 0; myBall.hmbl(0); myShadowRegisters[HMBL] = 0; break; case GRP0: myPlayer0.grp(value); break; case GRP1: myPlayer1.grp(value); break; case DummyRegisters::shuffleP0: myPlayer0.shufflePatterns(); break; case DummyRegisters::shuffleP1: myPlayer1.shufflePatterns(); break; case DummyRegisters::shuffleBL: myBall.shuffleStatus(); break; case HMP0: myPlayer0.hmp(value); break; case HMP1: myPlayer1.hmp(value); break; case HMBL: myBall.hmbl(value); break; case REFP0: myPlayer0.refp(value); break; case REFP1: myPlayer1.refp(value); break; case ENABL: myBall.enabl(value); break; case ENAM0: myMissile0.enam(value); break; case ENAM1: myMissile1.enam(value); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::updatePaddle(uInt8 idx) { Int32 resistance; switch (idx) { case 0: resistance = myConsole.leftController().read(Controller::Nine); break; case 1: resistance = myConsole.leftController().read(Controller::Five); break; case 2: resistance = myConsole.rightController().read(Controller::Nine); break; case 3: resistance = myConsole.rightController().read(Controller::Five); break; default: throw runtime_error("invalid paddle index"); } myPaddleReaders[idx].update( (resistance == Controller::maximumResistance) ? -1 : (double(resistance) / Paddles::MAX_RESISTANCE), myTimestamp, consoleTiming() ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::resxCounter() { return myHstate == HState::blank ? (myHctr >= resxLateHblankThreshold ? ResxCounter::lateHblank : ResxCounter::hblank) : ResxCounter::frame; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::collCXM0P() const { return ( ((myCollisionMask & CollisionMask::missile0 & CollisionMask::player0) ? 0x40 : 0) | ((myCollisionMask & CollisionMask::missile0 & CollisionMask::player1) ? 0x80 : 0) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::collCXM1P() const { return ( ((myCollisionMask & CollisionMask::missile1 & CollisionMask::player1) ? 0x40 : 0) | ((myCollisionMask & CollisionMask::missile1 & CollisionMask::player0) ? 0x80 : 0) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::collCXP0FB() const { return ( ((myCollisionMask & CollisionMask::player0 & CollisionMask::ball) ? 0x40 : 0) | ((myCollisionMask & CollisionMask::player0 & CollisionMask::playfield) ? 0x80 : 0) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::collCXP1FB() const { return ( ((myCollisionMask & CollisionMask::player1 & CollisionMask::ball) ? 0x40 : 0) | ((myCollisionMask & CollisionMask::player1 & CollisionMask::playfield) ? 0x80 : 0) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::collCXM0FB() const { return ( ((myCollisionMask & CollisionMask::missile0 & CollisionMask::ball) ? 0x40 : 0) | ((myCollisionMask & CollisionMask::missile0 & CollisionMask::playfield) ? 0x80 : 0) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::collCXM1FB() const { return ( ((myCollisionMask & CollisionMask::missile1 & CollisionMask::ball) ? 0x40 : 0) | ((myCollisionMask & CollisionMask::missile1 & CollisionMask::playfield) ? 0x80 : 0) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::collCXPPMM() const { return ( ((myCollisionMask & CollisionMask::missile0 & CollisionMask::missile1) ? 0x40 : 0) | ((myCollisionMask & CollisionMask::player0 & CollisionMask::player1) ? 0x80 : 0) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::collCXBLPF() const { return (myCollisionMask & CollisionMask::ball & CollisionMask::playfield) ? 0x80 : 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP0PF() { myCollisionMask ^= (CollisionMask::player0 & CollisionMask::playfield); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP0BL() { myCollisionMask ^= (CollisionMask::player0 & CollisionMask::ball); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP0M1() { myCollisionMask ^= (CollisionMask::player0 & CollisionMask::missile1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP0M0() { myCollisionMask ^= (CollisionMask::player0 & CollisionMask::missile0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP0P1() { myCollisionMask ^= (CollisionMask::player0 & CollisionMask::player1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP1PF() { myCollisionMask ^= (CollisionMask::player1 & CollisionMask::playfield); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP1BL() { myCollisionMask ^= (CollisionMask::player1 & CollisionMask::ball); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP1M1() { myCollisionMask ^= (CollisionMask::player1 & CollisionMask::missile1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollP1M0() { myCollisionMask ^= (CollisionMask::player1 & CollisionMask::missile0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollM0PF() { myCollisionMask ^= (CollisionMask::missile0 & CollisionMask::playfield); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollM0BL() { myCollisionMask ^= (CollisionMask::missile0 & CollisionMask::ball); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollM0M1() { myCollisionMask ^= (CollisionMask::missile0 & CollisionMask::missile1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollM1PF() { myCollisionMask ^= (CollisionMask::missile1 & CollisionMask::playfield); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollM1BL() { myCollisionMask ^= (CollisionMask::missile1 & CollisionMask::ball); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::toggleCollBLPF() { myCollisionMask ^= (CollisionMask::ball & CollisionMask::playfield); } #ifdef DEBUGGER_SUPPORT // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::createAccessBase() { myAccessBase = make_unique(TIA_SIZE); memset(myAccessBase.get(), CartDebug::NONE, TIA_SIZE); myAccessDelay = make_unique(TIA_SIZE); memset(myAccessDelay.get(), TIA_DELAY, TIA_SIZE); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt8 TIA::getAccessFlags(uInt16 address) const { return myAccessBase[address & TIA_MASK]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TIA::setAccessFlags(uInt16 address, uInt8 flags) { // ignore none flag if (flags != CartDebug::NONE) { if (flags == CartDebug::WRITE) { // the first two write accesses are assumed as initialization if (myAccessDelay[address & TIA_MASK]) myAccessDelay[address & TIA_MASK]--; else myAccessBase[address & TIA_MASK] |= flags; } else myAccessBase[address & TIA_READ_MASK] |= flags; } } #endif // DEBUGGER_SUPPORT stella-5.1.1/src/emucore/tia/TIA.hxx000066400000000000000000000544321324334165500171710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_TIA #define TIA_TIA #include "bspf.hxx" #include "Console.hxx" #include "Sound.hxx" #include "Settings.hxx" #include "Device.hxx" #include "Serializer.hxx" #include "TIAConstants.hxx" #include "DelayQueue.hxx" #include "DelayQueueIterator.hxx" #include "frame-manager/AbstractFrameManager.hxx" #include "FrameLayout.hxx" #include "Background.hxx" #include "Playfield.hxx" #include "Missile.hxx" #include "Player.hxx" #include "Ball.hxx" #include "LatchedInput.hxx" #include "PaddleReader.hxx" #include "DelayQueueIterator.hxx" #include "Control.hxx" #include "System.hxx" /** This class is a device that emulates the Television Interface Adaptor found in the Atari 2600 and 7800 consoles. The Television Interface Adaptor is an integrated circuit designed to interface between an eight bit microprocessor and a television video modulator. It converts eight bit parallel data into serial outputs for the color, luminosity, and composite sync required by a video modulator. This class outputs the serial data into a frame buffer which can then be displayed on screen. @author Christian Speckner (DirtyHairy) and Stephen Anthony */ class TIA : public Device { public: /** * These dummy register addresses are used to represent the delayed * old / new register swap on writing GRPx and ENABL in the DelayQueue (see below). */ enum DummyRegisters: uInt8 { shuffleP0 = 0xF0, shuffleP1 = 0xF1, shuffleBL = 0xF2 }; /** * Possible palette entries for objects in "fixed debug color mode". */ enum FixedColor { NTSC_RED = 0x30, NTSC_ORANGE = 0x38, NTSC_YELLOW = 0x1c, NTSC_GREEN = 0xc4, NTSC_BLUE = 0x9e, NTSC_PURPLE = 0x66, PAL_RED = 0x62, PAL_ORANGE = 0x4a, PAL_YELLOW = 0x2e, PAL_GREEN = 0x34, PAL_BLUE = 0xbc, PAL_PURPLE = 0xa6, BK_GREY = 0x0a, HBLANK_WHITE = 0x0e }; public: friend class TIADebug; friend class RiotDebug; /** Create a new TIA for the specified console @param console The console the TIA is associated with @param sound The sound object the TIA is associated with @param settings The settings object for this TIA device */ TIA(Console& console, Sound& sound, Settings& settings); virtual ~TIA() = default; public: /** * Configure the frame manager. */ void setFrameManager(AbstractFrameManager *frameManager); /** * Clear the configured frame manager and deteach the lifecycle callbacks. */ void clearFrameManager(); /** Reset device to its power-on state. */ void reset() override; /** Reset frame to current YStart/Height properties. */ void frameReset(); /** Install TIA in the specified system. Invoked by the system when the TIA is attached to it. @param system The system the device should install itself in */ void install(System& system) override; /** Get the byte at the specified address. @return The byte at the specified address */ uInt8 peek(uInt16 address) override; /** Change the byte at the specified address to the given value. @param address The address where the value should be stored @param value The value to be stored at the address @return True if the poke changed the device address space, else false */ bool poke(uInt16 address, uInt8 value) override; /** Install TIA in the specified system and device. Invoked by the system when the TIA is attached to it. All devices which invoke this method take responsibility for chaining requests back to *this* device. @param system The system the device should install itself in @param device The device responsible for this address space */ void installDelegate(System& system, Device& device); /** Bind to controllers. */ void bindToControllers(); /** The following are very similar to save() and load(), except they do a 'deeper' save of the display data itself. Normally, the internal framebuffer doesn't need to be saved to a state file, since the file already contains all the information needed to re-create it, starting from scanline 0. In effect, when a state is loaded, the framebuffer is empty, and the next call to update() generates valid framebuffer data. However, state files saved from the debugger need more information, such as the exact state of the internal framebuffer itself *before* we call update(), including if the display was in partial frame mode. Essentially, a normal state save has 'frame resolution', whereas the debugger state save has 'cycle resolution', and hence needs more information. The methods below save/load this extra info, and eliminate having to save approx. 50K to normal state files. */ bool saveDisplay(Serializer& out) const; bool loadDisplay(Serializer& in); /** This method should be called at an interval corresponding to the desired frame rate to update the TIA. Invoking this method will update the graphics buffer and generate the corresponding audio samples. */ void update(); /** Returns a pointer to the internal frame buffer. */ uInt8* frameBuffer() { return static_cast(myFramebuffer); } /** Answers dimensional info about the framebuffer. */ uInt32 width() const { return 160; } uInt32 height() const { return myFrameManager->height(); } uInt32 ystart() const { return myFrameManager->ystart(); } /** Changes the current Height/YStart properties. Note that calls to these method(s) must be eventually followed by ::frameReset() for the changes to take effect. */ void setHeight(uInt32 height) { myFrameManager->setFixedHeight(height); } void setYStart(uInt32 ystart) { myFrameManager->setYstart(ystart); } void setLayout(FrameLayout layout) { myFrameManager->setLayout(layout); } FrameLayout frameLayout() const { return myFrameManager->layout(); } /** Answers the timing of the console currently in use. */ ConsoleTiming consoleTiming() const { return myConsole.timing(); } /** Enables/disables auto-frame calculation. If enabled, the TIA re-adjusts the framerate at regular intervals. @param enabled Whether to enable or disable all auto-frame calculation */ void enableAutoFrame(bool enabled) { myAutoFrameEnabled = enabled; } /** Enables/disables color-loss for PAL modes only. @param enabled Whether to enable or disable PAL color-loss mode */ bool enableColorLoss(bool enabled); /** Answers whether color-loss is enabled. @return Colour-loss is enabled */ bool colorLossEnabled() const { return myColorLossEnabled; } /** Answers whether colour-loss is applicable for the current frame. @return Colour-loss is active for this frame */ bool colorLossActive() const { return myColorLossActive; } /** Answers the current color clock we've gotten to on this scanline. @return The current color clock */ uInt32 clocksThisLine() const { return myHctr - myHctrDelta; } /** Answers the total number of scanlines the TIA generated in producing the current frame buffer. For partial frames, this will be the current scanline. @return The total number of scanlines generated */ uInt32 scanlines() const { return myFrameManager->scanlines(); } /** Answers the total number of scanlines the TIA generated in the previous frame. @return The total number of scanlines generated in the last frame. */ uInt32 scanlinesLastFrame() const { return myFrameManager->scanlinesLastFrame(); } /** Answers the total system cycles from the start of the emulation. */ uInt64 cycles() const { return uInt64(mySystem->cycles()); } /** Answers the frame count from the start of the emulation. */ uInt32 frameCount() const { return myFrameManager->frameCount(); } /** Answers the system cycles from the start of the current frame. */ uInt32 frameCycles() const { return uInt32(mySystem->cycles() - myCyclesAtFrameStart); } /** Answers whether the TIA is currently in being rendered (we're in between the start and end of drawing a frame). @return If the frame is in rendering mode */ bool isRendering() const { return myFrameManager->isRendering(); } /** Answers the current position of the virtual 'electron beam' used when drawing the TIA image in debugger mode. @return The x/y coordinates of the scanline electron beam, and whether it is in the visible/viewable area of the screen */ bool electronBeamPos(uInt32& x, uInt32& y) const; /** Enables/disable/toggle the specified (or all) TIA bit(s). Note that disabling a graphical object also disables its collisions. @param mode 1/0 indicates on/off, and values greater than 1 mean flip the bit from its current state @return Whether the bit was enabled or disabled */ bool toggleBit(TIABit b, uInt8 mode = 2); bool toggleBits(); /** Enables/disable/toggle the specified (or all) TIA bit collision(s). @param mode 1/0 indicates on/off, and values greater than 1 mean flip the collision from its current state @return Whether the collision was enabled or disabled */ bool toggleCollision(TIABit b, uInt8 mode = 2); bool toggleCollisions(); /** Enables/disable/toggle/query 'fixed debug colors' mode. @param enable Whether to enable fixed debug colors mode @return Whether the mode was enabled or disabled */ bool enableFixedColors(bool enable); bool toggleFixedColors() { return enableFixedColors(!usingFixedColors()); } bool usingFixedColors() const { return myColorHBlank != 0x00; } /** Sets the color of each object in 'fixed debug colors' mode. Note that this doesn't enable/disable fixed colors; it simply updates the palette that is used. @param colors Each character in the 6-char string represents the first letter of the color to use for P0/M0/P1/M1/PF/BL, respectively. @return True if colors were changed successfully, else false */ bool setFixedColorPalette(const string& colors); /** Enable/disable/query state of 'undriven/floating TIA pins'. @param mode 1/0 indicates on/off, otherwise return the current state @return Whether the mode was enabled or disabled */ bool driveUnusedPinsRandom(uInt8 mode = 2); /** Enables/disable/toggle 'scanline jittering' mode, and set the recovery 'factor'. @param mode 1/0 indicates on/off, otherwise flip from its current state @return Whether the mode was enabled or disabled */ bool toggleJitter(uInt8 mode = 2); void setJitterRecoveryFactor(Int32 factor); /** This method should be called to update the TIA with a new scanline. */ TIA& updateScanline(); /** This method should be called to update the TIA with a new partial scanline by stepping one CPU instruction. */ TIA& updateScanlineByStep(); /** This method should be called to update the TIA with a new partial scanline by tracing to target address. */ TIA& updateScanlineByTrace(int target); /** Retrieve the last value written to a certain register. */ uInt8 registerValue(uInt8 reg) const; /** Get the current x value. */ uInt8 getPosition() const { uInt8 realHctr = myHctr - myHctrDelta; return (realHctr < 68) ? 0 : (realHctr - 68); } /** Flush the line cache after an externally triggered state change (e.g. a register write). */ void flushLineCache(); /** Create a new delayQueueIterator for the debugger. */ shared_ptr delayQueueIterator() const; /** Save the current state of this device to the given Serializer. @param out The Serializer object to use @return False on any errors, else true */ bool save(Serializer& out) const override; /** Load the current state of this device from the given Serializer. @param in The Serializer object to use @return False on any errors, else true */ bool load(Serializer& in) override; /** Get a descriptor for the device name (used in error checking). @return The name of the object */ string name() const override { return "TIA"; } /** * Run and forward TIA emulation to the current system clock. */ void updateEmulation(); private: /** * During each line, the TIA cycles through these two states. */ enum HState {blank, frame}; /** * The three different modes of the priority encoder. Check TIA::renderPixel * for a precise definition. */ enum Priority {pfp, score, normal}; /** * Palette and indices for fixed debug colors. */ enum FixedObject { P0, M0, P1, M1, PF, BL }; FixedColor myFixedColorPalette[2][6]; string myFixedColorNames[6]; private: /** * This callback is invoked by FrameManager when a new frame starts. */ void onFrameStart(); /** * This callback is invoked by FrameManager when the current frame completes. */ void onFrameComplete(); /** * Called when the CPU enters halt state (RDY pulled low). Execution continues * immediatelly afterwards, so we have to adjust the system clock to account * for the cycles the 6502 spent in halt state. */ void onHalt(); /** * Execute colorClocks cycles of TIA simulation. */ void cycle(uInt32 colorClocks); /** * Advance the movement logic by a single clock. */ void tickMovement(); /** * Advance a single clock during hblank. */ void tickHblank(); /** * Advance a single clock duing the visible part of the scanline. */ void tickHframe(); /** * Execute a RSYNC. */ void applyRsync(); /** * Update the collision bitfield. */ void updateCollision(); /** * Render the current pixel into the framebuffer. */ void renderPixel(uInt32 x, uInt32 y); /** * Clear the first 8 pixels of a scanline with black if we are in hblank * (called during HMOVE). */ void clearHmoveComb(); /** * Advance a line and update our state accordingly. */ void nextLine(); /** * Clone the last line. Called in nextLine if TIA state was unchanged. */ void cloneLastLine(); /** * Execute a delayed write. Called when the DelayQueue is pumped. */ void delayedWrite(uInt8 address, uInt8 value); /** * Update all paddle readout circuits to the current controller state. */ void updatePaddle(uInt8 idx); /** * Get the target counter value during a RESx. This essentially depends on * the position in the current scanline. */ uInt8 resxCounter(); /** * Get the result of the specified collision register. */ uInt8 collCXM0P() const; uInt8 collCXM1P() const; uInt8 collCXP0FB() const; uInt8 collCXP1FB() const; uInt8 collCXM0FB() const; uInt8 collCXM1FB() const; uInt8 collCXPPMM() const; uInt8 collCXBLPF() const; /** Toggle the specified collision bits */ void toggleCollP0PF(); void toggleCollP0BL(); void toggleCollP0M1(); void toggleCollP0M0(); void toggleCollP0P1(); void toggleCollP1PF(); void toggleCollP1BL(); void toggleCollP1M1(); void toggleCollP1M0(); void toggleCollM0PF(); void toggleCollM0BL(); void toggleCollM0M1(); void toggleCollM1PF(); void toggleCollM1BL(); void toggleCollBLPF(); #ifdef DEBUGGER_SUPPORT void createAccessBase(); /** * Query the given address type for the associated disassembly flags. * * @param address The address to query */ uInt8 getAccessFlags(uInt16 address) const override; /** * Change the given address to use the given disassembly flags. * * @param address The address to modify * @param flags A bitfield of DisasmType directives for the given address */ void setAccessFlags(uInt16 address, uInt8 flags) override; #endif // DEBUGGER_SUPPORT private: Console& myConsole; Sound& mySound; Settings& mySettings; /** * The length of the delay queue (maximum number of clocks delay) */ static constexpr unsigned delayQueueLength = 16; /** * The size of the delay queue (maximum number of writes scheduled in a single slot). */ static constexpr unsigned delayQueueSize = 16; /** * A list of delayed writes that are queued up for future execution. Delayed * writes can be both actual writes whose effect is delayed by one or more clocks * on real hardware and delayed side effects of certain operations (GRPx!). */ DelayQueue myDelayQueue; /** * The frame manager is responsible for detecting frame boundaries and the visible * region of each frame. */ AbstractFrameManager *myFrameManager; /** * The various TIA objects. */ Background myBackground; Playfield myPlayfield; Missile myMissile0; Missile myMissile1; Player myPlayer0; Player myPlayer1; Ball myBall; /** * The paddle readout circuits. */ PaddleReader myPaddleReaders[4]; /** * Circuits for the "latched inputs". */ LatchedInput myInput0; LatchedInput myInput1; // Pointer to the internal color-index-based frame buffer uInt8 myFramebuffer[160 * TIAConstants::frameBufferHeight]; /** * Setting this to true injects random values into undefined reads. */ bool myTIAPinsDriven; /** * The current "line state" --- either hblank or frame. */ HState myHstate; /** * Master line counter */ uInt8 myHctr; /** * Delta between master line counter and actual color clock. Nonzero after * RSYNC (before the scanline terminates) */ Int32 myHctrDelta; /** * Electron beam x at rendering start (used for blanking out any pixels from * the last frame that are not overwritten) */ uInt8 myXAtRenderingStart; /** * Do we need to update the collision mask this clock? */ bool myCollisionUpdateRequired; /** * The collision latches are represented by 15 bits in a bitfield. */ uInt32 myCollisionMask; /** * The movement clock counts the extra ticks sent to the objects during * movement. */ uInt32 myMovementClock; /** * Movement mode --- are we sending movement clocks? */ bool myMovementInProgress; /** * Do we have an extended hblank this line? Get set by strobing HMOVE and * cleared when the line wraps. */ bool myExtendedHblank; /** * Counts the number of line wraps since the last external TIA state change. * If at least two line breaks have passed, the TIA will suspend simulation * and just reuse the last line instead. */ uInt32 myLinesSinceChange; /** * The current mode of the priority encoder. */ Priority myPriority; /** * The index of the last CPU cycle that was included in the simulation. */ uInt64 myLastCycle; /** * Keeps track of a possible fractional number of clocks that still need * to be simulated. */ uInt8 mySubClock; /** * Bitmasks that track which sprites / collisions are enabled / disabled. */ uInt8 mySpriteEnabledBits; uInt8 myCollisionsEnabledBits; /** * The color used to highlight HMOVE blanks (if enabled). */ uInt8 myColorHBlank; /** * The total number of color clocks since emulation started. This is a * double a) to avoid overflows and b) as it will enter floating point * expressions in the paddle readout simulation anyway. */ double myTimestamp; /** * The "shadow registers" track the last written register value for the * debugger. */ uInt8 myShadowRegisters[64]; /** * Automatic framerate correction based on number of scanlines. */ bool myAutoFrameEnabled; /** * Indicates if color loss should be enabled or disabled. Color loss * occurs on PAL-like systems when the previous frame contains an odd * number of scanlines. */ bool myColorLossEnabled; bool myColorLossActive; /** * System cycles at the end of the previous frame / beginning of next frame. */ uInt64 myCyclesAtFrameStart; /** * The frame manager can change during our lifetime, so we buffer those two. */ bool myEnableJitter; uInt8 myJitterFactor; #ifdef DEBUGGER_SUPPORT // The arrays containing information about every byte of TIA // indicating whether and how (RW) it is used. BytePtr myAccessBase; // The array used to skip the first two TIA access trackings BytePtr myAccessDelay; #endif // DEBUGGER_SUPPORT static constexpr uInt16 TIA_SIZE = 0x40, TIA_MASK = TIA_SIZE - 1, TIA_READ_MASK = 0x0f, TIA_BIT = 0x080, TIA_DELAY = 2; private: TIA() = delete; TIA(const TIA&) = delete; TIA(TIA&&) = delete; TIA& operator=(const TIA&) = delete; TIA& operator=(TIA&&) = delete; }; #endif // TIA_TIA stella-5.1.1/src/emucore/tia/TIAConstants.hxx000066400000000000000000000136771324334165500210740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_CONSTANTS_HXX #define TIA_CONSTANTS_HXX #include "bspf.hxx" namespace TIAConstants { constexpr uInt32 frameBufferHeight = 320; constexpr uInt32 minYStart = 1, maxYStart = 64; constexpr uInt32 minViewableHeight = 210, maxViewableHeight = 256; constexpr uInt32 initialGarbageFrames = 10; } enum TIABit { P0Bit = 0x01, // Bit for Player 0 M0Bit = 0x02, // Bit for Missle 0 P1Bit = 0x04, // Bit for Player 1 M1Bit = 0x08, // Bit for Missle 1 BLBit = 0x10, // Bit for Ball PFBit = 0x20, // Bit for Playfield ScoreBit = 0x40, // Bit for Playfield score mode PriorityBit = 0x80 // Bit for Playfield priority }; enum TIAColor { BKColor = 0, // Color index for Background PFColor = 1, // Color index for Playfield P0Color = 2, // Color index for Player 0 P1Color = 3, // Color index for Player 1 M0Color = 4, // Color index for Missle 0 M1Color = 5, // Color index for Missle 1 BLColor = 6, // Color index for Ball HBLANKColor = 7 // Color index for HMove blank area }; enum class CollisionBit { M0P1 = 1 << 0, // Missle0 - Player1 collision M0P0 = 1 << 1, // Missle0 - Player0 collision M1P0 = 1 << 2, // Missle1 - Player0 collision M1P1 = 1 << 3, // Missle1 - Player1 collision P0PF = 1 << 4, // Player0 - Playfield collision P0BL = 1 << 5, // Player0 - Ball collision P1PF = 1 << 6, // Player1 - Playfield collision P1BL = 1 << 7, // Player1 - Ball collision M0PF = 1 << 8, // Missle0 - Playfield collision M0BL = 1 << 9, // Missle0 - Ball collision M1PF = 1 << 10, // Missle1 - Playfield collision M1BL = 1 << 11, // Missle1 - Ball collision BLPF = 1 << 12, // Ball - Playfield collision P0P1 = 1 << 13, // Player0 - Player1 collision M0M1 = 1 << 14 // Missle0 - Missle1 collision }; // TIA Write/Read register names enum TIARegister { VSYNC = 0x00, // Write: vertical sync set-clear (D1) VBLANK = 0x01, // Write: vertical blank set-clear (D7-6,D1) WSYNC = 0x02, // Write: wait for leading edge of hrz. blank (strobe) RSYNC = 0x03, // Write: reset hrz. sync counter (strobe) NUSIZ0 = 0x04, // Write: number-size player-missle 0 (D5-0) NUSIZ1 = 0x05, // Write: number-size player-missle 1 (D5-0) COLUP0 = 0x06, // Write: color-lum player 0 (D7-1) COLUP1 = 0x07, // Write: color-lum player 1 (D7-1) COLUPF = 0x08, // Write: color-lum playfield (D7-1) COLUBK = 0x09, // Write: color-lum background (D7-1) CTRLPF = 0x0a, // Write: cntrl playfield ballsize & coll. (D5-4,D2-0) REFP0 = 0x0b, // Write: reflect player 0 (D3) REFP1 = 0x0c, // Write: reflect player 1 (D3) PF0 = 0x0d, // Write: playfield register byte 0 (D7-4) PF1 = 0x0e, // Write: playfield register byte 1 (D7-0) PF2 = 0x0f, // Write: playfield register byte 2 (D7-0) RESP0 = 0x10, // Write: reset player 0 (strobe) RESP1 = 0x11, // Write: reset player 1 (strobe) RESM0 = 0x12, // Write: reset missle 0 (strobe) RESM1 = 0x13, // Write: reset missle 1 (strobe) RESBL = 0x14, // Write: reset ball (strobe) AUDC0 = 0x15, // Write: audio control 0 (D3-0) AUDC1 = 0x16, // Write: audio control 1 (D4-0) AUDF0 = 0x17, // Write: audio frequency 0 (D4-0) AUDF1 = 0x18, // Write: audio frequency 1 (D3-0) AUDV0 = 0x19, // Write: audio volume 0 (D3-0) AUDV1 = 0x1a, // Write: audio volume 1 (D3-0) GRP0 = 0x1b, // Write: graphics player 0 (D7-0) GRP1 = 0x1c, // Write: graphics player 1 (D7-0) ENAM0 = 0x1d, // Write: graphics (enable) missle 0 (D1) ENAM1 = 0x1e, // Write: graphics (enable) missle 1 (D1) ENABL = 0x1f, // Write: graphics (enable) ball (D1) HMP0 = 0x20, // Write: horizontal motion player 0 (D7-4) HMP1 = 0x21, // Write: horizontal motion player 1 (D7-4) HMM0 = 0x22, // Write: horizontal motion missle 0 (D7-4) HMM1 = 0x23, // Write: horizontal motion missle 1 (D7-4) HMBL = 0x24, // Write: horizontal motion ball (D7-4) VDELP0 = 0x25, // Write: vertical delay player 0 (D0) VDELP1 = 0x26, // Write: vertical delay player 1 (D0) VDELBL = 0x27, // Write: vertical delay ball (D0) RESMP0 = 0x28, // Write: reset missle 0 to player 0 (D1) RESMP1 = 0x29, // Write: reset missle 1 to player 1 (D1) HMOVE = 0x2a, // Write: apply horizontal motion (strobe) HMCLR = 0x2b, // Write: clear horizontal motion registers (strobe) CXCLR = 0x2c, // Write: clear collision latches (strobe) CXM0P = 0x00, // Read collision: D7=(M0,P1); D6=(M0,P0) CXM1P = 0x01, // Read collision: D7=(M1,P0); D6=(M1,P1) CXP0FB = 0x02, // Read collision: D7=(P0,PF); D6=(P0,BL) CXP1FB = 0x03, // Read collision: D7=(P1,PF); D6=(P1,BL) CXM0FB = 0x04, // Read collision: D7=(M0,PF); D6=(M0,BL) CXM1FB = 0x05, // Read collision: D7=(M1,PF); D6=(M1,BL) CXBLPF = 0x06, // Read collision: D7=(BL,PF); D6=(unused) CXPPMM = 0x07, // Read collision: D7=(P0,P1); D6=(M0,M1) INPT0 = 0x08, // Read pot port: D7 INPT1 = 0x09, // Read pot port: D7 INPT2 = 0x0a, // Read pot port: D7 INPT3 = 0x0b, // Read pot port: D7 INPT4 = 0x0c, // Read P1 joystick trigger: D7 INPT5 = 0x0d // Read P2 joystick trigger: D7 }; #endif // TIA_CONSTANTS_HXX stella-5.1.1/src/emucore/tia/frame-manager/000077500000000000000000000000001324334165500205155ustar00rootroot00000000000000stella-5.1.1/src/emucore/tia/frame-manager/AbstractFrameManager.cxx000066400000000000000000000105611324334165500252550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "AbstractFrameManager.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AbstractFrameManager::AbstractFrameManager() : myLayout(FrameLayout::pal), myOnFrameStart(nullptr), myOnFrameComplete(nullptr) { layout(FrameLayout::ntsc); reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::reset() { myIsRendering = false; myVsync = false; myVblank = false; myCurrentFrameTotalLines = 0; myCurrentFrameFinalLines = 0; myPreviousFrameFinalLines = 0; myTotalFrames = 0; myFrameRate = 0; myFrameRate = 60.0; onReset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::nextLine() { myCurrentFrameTotalLines++; onNextLine(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::setHandlers( callback frameStartCallback, callback frameCompletionCallback ) { myOnFrameStart = frameStartCallback; myOnFrameComplete = frameCompletionCallback; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::clearHandlers() { myOnFrameStart = myOnFrameComplete = nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::setVblank(bool vblank) { if (vblank == myVblank) return; myVblank = vblank; onSetVblank(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::setVsync(bool vsync) { if (vsync == myVsync) return; myVsync = vsync; onSetVsync(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::notifyFrameStart() { if (myOnFrameStart) myOnFrameStart(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::notifyFrameComplete() { myPreviousFrameFinalLines = myCurrentFrameFinalLines; myCurrentFrameFinalLines = myCurrentFrameTotalLines; myCurrentFrameTotalLines = 0; myTotalFrames++; if (myOnFrameComplete) myOnFrameComplete(); myFrameRate = (layout() == FrameLayout::pal ? 15600.0 : 15720.0) / myCurrentFrameFinalLines; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AbstractFrameManager::layout(FrameLayout layout) { if (layout == myLayout) return; myLayout = layout; onLayoutChange(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool AbstractFrameManager::save(Serializer& out) const { try { out.putString(name()); out.putBool(myIsRendering); out.putBool(myVsync); out.putBool(myVblank); out.putInt(myCurrentFrameTotalLines); out.putInt(myCurrentFrameFinalLines); out.putInt(myPreviousFrameFinalLines); out.putInt(myTotalFrames); out.putInt(uInt32(myLayout)); out.putDouble(myFrameRate); return onSave(out); } catch(...) { cerr << "ERROR: AbstractFrameManager::save" << endl; return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool AbstractFrameManager::load(Serializer& in) { try { if (in.getString() != name()) return false; myIsRendering = in.getBool(); myVsync = in.getBool(); myVblank = in.getBool(); myCurrentFrameTotalLines = in.getInt(); myCurrentFrameFinalLines = in.getInt(); myPreviousFrameFinalLines = in.getInt(); myTotalFrames = in.getInt(); myLayout = FrameLayout(in.getInt()); myFrameRate = float(in.getDouble()); return onLoad(in); } catch(...) { cerr << "ERROR: AbstractFrameManager::load" << endl; return false; } } stella-5.1.1/src/emucore/tia/frame-manager/AbstractFrameManager.hxx000066400000000000000000000164571324334165500252740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_ABSTRACT_FRAME_MANAGER #define TIA_ABSTRACT_FRAME_MANAGER #include #include "Serializable.hxx" #include "FrameLayout.hxx" class AbstractFrameManager : public Serializable { public: using callback = std::function; public: AbstractFrameManager(); public: /** * Configure the various handler callbacks. */ void setHandlers( callback frameStartCallback, callback frameCompletionCallback ); /** * Clear the configured handler callbacks. */ void clearHandlers(); /** * Reset. */ void reset(); /** * Called by TIA to notify the start of the next scanline. */ void nextLine(); /** * Called by TIA on VBLANK writes. */ void setVblank(bool vblank); /** * Called by TIA on VSYNC writes. */ void setVsync(bool vsync); /** * Should the TIA render its frame? This is buffered in a flag for * performance reasons; descendants must update the flag. */ bool isRendering() const { return myIsRendering; } /** * Is vsync on? */ bool vsync() const { return myVsync; } /** * Is vblank on? */ bool vblank() const { return myVblank; } /** * The number of scanlines in the last finished frame. */ uInt32 scanlinesLastFrame() const { return myCurrentFrameFinalLines; } /** * Did the number of scanlines switch between even / odd (used for color loss * emulation). */ bool scanlineParityChanged() const { return (myPreviousFrameFinalLines & 0x1) != (myCurrentFrameFinalLines & 0x1); } /** * The total number of frames. 32 bit should be good for > 2 years :) */ uInt32 frameCount() const { return myTotalFrames; } /** * The configured (our autodetected) frame layout (PAL / NTSC). */ FrameLayout layout() const { return myLayout; } /** * The current frame rate. This is calculated dynamically from the number of * scanlines in the last frames and used to control sleep time in the * dispatch loop. */ float frameRate() const { return myFrameRate; } /** * Save state. */ bool save(Serializer& out) const override; /** * Restore state. */ bool load(Serializer& in) override; public: // The following methods are implement as noops and should be overriden as // required. All of these are irrelevant if nothing is displayed (during // autodetect). /** * The jitter factor determines the time jitter simulation takes to recover. */ virtual void setJitterFactor(uInt8 factor) {} /** * Is jitter simulation enabled? */ virtual bool jitterEnabled() const { return false; } /** * Enable jitter simulation */ virtual void enableJitter(bool enabled) {} /** * The scanline difference between the last two frames. Used in the TIA to * clear any scanlines that were not repainted. */ virtual Int32 missingScanlines() const { return 0; } /** * Frame height. */ virtual uInt32 height() const { return 0; } /** * Configure a fixed frame height (the default is determined by the frame * layout). */ virtual void setFixedHeight(uInt32 height) {} /** * The current y coordinate (valid only during rendering). */ virtual uInt32 getY() const { return 0; } /** * The current number of scanlines in the current frame (including invisible * lines). */ virtual uInt32 scanlines() const { return 0; } /** * Configure the ystart value. */ virtual void setYstart(uInt32 ystart) {} /** * The configured ystart value. */ virtual uInt32 ystart() const { return 0; } /** * Set the frame layout. This may be a noop (on the autodetection manager). */ virtual void setLayout(FrameLayout mode) {} protected: // The following are template methods that can be implemented to hook into // the frame logic. /** * Called if vblank changes. */ virtual void onSetVblank() {} /** * Called if vsync changes. */ virtual void onSetVsync() {} /** * Called if the next line is signalled, after the internal bookkeeping has * been updated. */ virtual void onNextLine() {} /** * Called on reset (after the base class has reset). */ virtual void onReset() {} /** * Called after a frame layout change. */ virtual void onLayoutChange() {} /** * Called during state save (after the base class has serialized its state). */ virtual bool onSave(Serializer& out) const { throw runtime_error("cannot be serialized"); } /** * Called during state restore (after the base class has restored its state). */ virtual bool onLoad(Serializer& in) { throw runtime_error("cannot be serialized"); } /** * This needs to be overriden if state serialization is implemented * (unnecesary in autodetect managers). */ string name() const override { throw runtime_error("state serialization is not implemented!"); } protected: // These need to be called in order to drive the frame lifecycle of the // emulation. /** * Signal frame start. */ void notifyFrameStart(); /** * Signal frame stop. */ void notifyFrameComplete(); /** * The internal setter to update the frame layout. */ void layout(FrameLayout layout); protected: /** * Rendering flag. */ bool myIsRendering; /** * Vsync flag. */ bool myVsync; /** * Vblank flag. */ bool myVblank; /** * Current scanline count in the current frame. */ uInt32 myCurrentFrameTotalLines; /** * Total number of scanlines in the last complete frame. */ uInt32 myCurrentFrameFinalLines; /** * Total number of scanlines in the second last complete frame. */ uInt32 myPreviousFrameFinalLines; /** * Total frame count. */ uInt32 myTotalFrames; /** * Frame rate (see above.) */ float myFrameRate; private: /** * Current frame layout. */ FrameLayout myLayout; /** * The various lifecycle callbacks. */ callback myOnFrameStart; callback myOnFrameComplete; private: AbstractFrameManager(const AbstractFrameManager&) = delete; AbstractFrameManager(AbstractFrameManager&&) = delete; AbstractFrameManager& operator=(const AbstractFrameManager&); AbstractFrameManager& operator=(AbstractFrameManager&&); }; #endif // TIA_ABSTRACT_FRAME_MANAGER stella-5.1.1/src/emucore/tia/frame-manager/FrameLayoutDetector.cxx000066400000000000000000000112351324334165500251650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "FrameLayoutDetector.hxx" #include "TIAConstants.hxx" /** * Misc. numeric constants used in the algorithm. */ enum Metrics: uInt32 { // ideal frame heights frameLinesNTSC = 262, frameLinesPAL = 312, // number of scanlines to wait for vsync to start and stop (exceeding ideal frame height) waitForVsync = 100, // tolerance window around ideal frame size for TV mode detection tvModeDetectionTolerance = 20, // these frames will not be considered for detection initialGarbageFrames = TIAConstants::initialGarbageFrames }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameLayout FrameLayoutDetector::detectedLayout() const{ // We choose the mode that was detected for the majority of frames. return myPalFrames > myNtscFrames ? FrameLayout::pal : FrameLayout::ntsc; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameLayoutDetector::onReset() { myState = State::waitForVsyncStart; myNtscFrames = myPalFrames = 0; myLinesWaitingForVsyncToStart = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameLayoutDetector::onSetVsync() { if (myVsync) setState(State::waitForVsyncEnd); else setState(State::waitForVsyncStart); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameLayoutDetector::onNextLine() { const uInt32 frameLines = layout() == FrameLayout::ntsc ? Metrics::frameLinesNTSC : Metrics::frameLinesPAL; switch (myState) { case State::waitForVsyncStart: // We start counting the number of "lines spent while waiting for vsync start" from // the "ideal" frame size (corrected by the three scanlines spent in vsync). if (myCurrentFrameTotalLines > frameLines - 3 || myTotalFrames == 0) myLinesWaitingForVsyncToStart++; if (myLinesWaitingForVsyncToStart > Metrics::waitForVsync) setState(State::waitForVsyncEnd); break; case State::waitForVsyncEnd: if (++myLinesWaitingForVsyncToStart > Metrics::waitForVsync) setState(State::waitForVsyncStart); break; default: throw runtime_error("cannot happen"); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameLayoutDetector::setState(State state) { if (state == myState) return; myState = state; myLinesWaitingForVsyncToStart = 0; switch (myState) { case State::waitForVsyncEnd: break; case State::waitForVsyncStart: finalizeFrame(); notifyFrameStart(); break; default: throw new runtime_error("cannot happen"); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameLayoutDetector::finalizeFrame() { notifyFrameComplete(); if (myTotalFrames <= Metrics::initialGarbageFrames) return; // Calculate the delta between scanline count and the sweet spot for the respective // frame layouts const uInt32 deltaNTSC = abs(Int32(myCurrentFrameFinalLines) - Int32(frameLinesNTSC)), deltaPAL = abs(Int32(myCurrentFrameFinalLines) - Int32(frameLinesPAL)); // Does the scanline count fall into one of our tolerance windows? -> use it if (std::min(deltaNTSC, deltaPAL) <= Metrics::tvModeDetectionTolerance) layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal); else if ( // If scanline count is odd and lies between the PAL and NTSC windows we assume // it is NTSC (it would cause color loss on PAL CRTs) (myCurrentFrameFinalLines < frameLinesPAL) && (myCurrentFrameFinalLines > frameLinesNTSC) && (myCurrentFrameFinalLines % 2) ) layout(FrameLayout::ntsc); else // Take the nearest layout if all else fails layout(deltaNTSC <= deltaPAL ? FrameLayout::ntsc : FrameLayout::pal); switch (layout()) { case FrameLayout::ntsc: myNtscFrames++; break; case FrameLayout::pal: myPalFrames++; break; default: throw runtime_error("cannot happen"); } } stella-5.1.1/src/emucore/tia/frame-manager/FrameLayoutDetector.hxx000066400000000000000000000051621324334165500251740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_FRAME_LAYOUT_DETECTOR #define TIA_FRAME_LAYOUT_DETECTOR #include "AbstractFrameManager.hxx" #include "FrameLayout.hxx" /** * This frame manager performs frame layout autodetection. It counts the scanlines * in each frame and assigns guesses the frame layout from this. */ class FrameLayoutDetector: public AbstractFrameManager { public: FrameLayoutDetector() = default; public: /** * Return the detected frame layout. */ FrameLayout detectedLayout() const; protected: /** * Hook into vsync changes. */ void onSetVsync() override; /** * Hook into reset. */ void onReset() override; /** * Hook into line changes. */ void onNextLine() override; private: /** * This frame manager only tracks frame boundaries, so we have only two states. */ enum State { // Wait for VSYNC to be enabled. waitForVsyncStart, // Wait for VSYNC to be disabled. waitForVsyncEnd }; private: /** * Change state and change internal state accordingly. */ void setState(State state); /** * Finalize the current frame and guess frame layout from the scanline count. */ void finalizeFrame(); private: /** * The current state. */ State myState; /** * The total number of frames detected as the respective frame layout. */ uInt32 myNtscFrames, myPalFrames; /** * We count the number of scanlines we spend waiting for vsync to be * toggled. If a threshold is exceeded, we force the transition. */ uInt32 myLinesWaitingForVsyncToStart; private: FrameLayoutDetector(const FrameLayoutDetector&) = delete; FrameLayoutDetector(FrameLayoutDetector&&) = delete; FrameLayoutDetector& operator=(const FrameLayoutDetector&) = delete; FrameLayoutDetector& operator=(FrameLayoutDetector&&) = delete; }; #endif // TIA_FRAME_LAYOUT_DETECTOR stella-5.1.1/src/emucore/tia/frame-manager/FrameManager.cxx000066400000000000000000000147171324334165500236000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ // #define TIA_FRAMEMANAGER_DEBUG_LOG #include #include "FrameManager.hxx" enum Metrics: uInt32 { vblankNTSC = 37, vblankPAL = 45, kernelNTSC = 192, kernelPAL = 228, overscanNTSC = 30, overscanPAL = 36, vsync = 3, maxLinesVsync = 50, visibleOverscan = 20, initialGarbageFrames = TIAConstants::initialGarbageFrames }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FrameManager::FrameManager() : myHeight(0), myYStart(0) { onLayoutChange(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::onReset() { myState = State::waitForVsyncStart; myLineInState = 0; myTotalFrames = 0; myVsyncLines = 0; myY = 0; myStableFrameLines = -1; myStableFrameHeightCountdown = 0; myJitterEmulation.reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::onNextLine() { Int32 jitter; State previousState = myState; myLineInState++; switch (myState) { case State::waitForVsyncStart: if ((myCurrentFrameTotalLines > myFrameLines - 3) || myTotalFrames == 0) myVsyncLines++; if (myVsyncLines > Metrics::maxLinesVsync) setState(State::waitForFrameStart); break; case State::waitForVsyncEnd: if (++myVsyncLines > Metrics::maxLinesVsync) setState(State::waitForFrameStart); break; case State::waitForFrameStart: jitter = (myJitterEnabled && myTotalFrames > Metrics::initialGarbageFrames) ? myJitterEmulation.jitter() : 0; if (myLineInState >= (myYStart + jitter)) setState(State::frame); break; case State::frame: if (myLineInState >= myHeight) { myLastY = ystart() + myY; // Last line drawn in this frame setState(State::waitForVsyncStart); } break; default: throw runtime_error("frame manager: invalid state"); } if (myState == State::frame && previousState == State::frame) myY++; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Int32 FrameManager::missingScanlines() const { if (myLastY == myYStart + myY) return 0; else { return myHeight - myY; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::setYstart(uInt32 ystart) { myYStart = ystart; myJitterEmulation.setYStart(ystart); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::onSetVsync() { if (myState == State::waitForVsyncEnd) setState(State::waitForFrameStart); else setState(State::waitForVsyncEnd); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::setState(FrameManager::State state) { if (myState == state) return; myState = state; myLineInState = 0; switch (myState) { case State::waitForFrameStart: notifyFrameComplete(); if (myTotalFrames > Metrics::initialGarbageFrames) myJitterEmulation.frameComplete(myCurrentFrameFinalLines); notifyFrameStart(); myVsyncLines = 0; break; case State::frame: myVsyncLines = 0; myY = 0; break; default: break; } updateIsRendering(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::onLayoutChange() { switch (layout()) { case FrameLayout::ntsc: myVblankLines = Metrics::vblankNTSC; myKernelLines = Metrics::kernelNTSC; myOverscanLines = Metrics::overscanNTSC; break; case FrameLayout::pal: myVblankLines = Metrics::vblankPAL; myKernelLines = Metrics::kernelPAL; myOverscanLines = Metrics::overscanPAL; break; default: throw runtime_error("frame manager: invalid TV mode"); } myFrameLines = Metrics::vsync + myVblankLines + myKernelLines + myOverscanLines; if (myFixedHeight == 0) myHeight = myKernelLines + Metrics::visibleOverscan; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::setFixedHeight(uInt32 height) { myFixedHeight = height; myHeight = myFixedHeight > 0 ? myFixedHeight : (myKernelLines + Metrics::visibleOverscan); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FrameManager::updateIsRendering() { myIsRendering = myState == State::frame; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameManager::onSave(Serializer& out) const { if (!myJitterEmulation.save(out)) return false; out.putInt(uInt32(myState)); out.putInt(myLineInState); out.putInt(myVsyncLines); out.putInt(myY); out.putInt(myLastY); out.putInt(myVblankLines); out.putInt(myKernelLines); out.putInt(myOverscanLines); out.putInt(myFrameLines); out.putInt(myHeight); out.putInt(myFixedHeight); out.putInt(myYStart); out.putBool(myJitterEnabled); out.putInt(myStableFrameLines); out.putInt(myStableFrameHeightCountdown); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FrameManager::onLoad(Serializer& in) { if (!myJitterEmulation.load(in)) return false; myState = State(in.getInt()); myLineInState = in.getInt(); myVsyncLines = in.getInt(); myY = in.getInt(); myLastY = in.getInt(); myVblankLines = in.getInt(); myKernelLines = in.getInt(); myOverscanLines = in.getInt(); myFrameLines = in.getInt(); myHeight = in.getInt(); myFixedHeight = in.getInt(); myYStart = in.getInt(); myJitterEnabled = in.getBool(); myStableFrameLines = in.getInt(); myStableFrameHeightCountdown = in.getInt(); return true; } stella-5.1.1/src/emucore/tia/frame-manager/FrameManager.hxx000066400000000000000000000054321324334165500235770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_FRAME_MANAGER #define TIA_FRAME_MANAGER #include "AbstractFrameManager.hxx" #include "TIAConstants.hxx" #include "bspf.hxx" #include "JitterEmulation.hxx" class FrameManager: public AbstractFrameManager { public: FrameManager(); public: void setJitterFactor(uInt8 factor) override { myJitterEmulation.setJitterFactor(factor); } bool jitterEnabled() const override { return myJitterEnabled; } void enableJitter(bool enabled) override { myJitterEnabled = enabled; } uInt32 height() const override { return myHeight; } void setFixedHeight(uInt32 height) override; uInt32 getY() const override { return myY; } uInt32 scanlines() const override { return myCurrentFrameTotalLines; } Int32 missingScanlines() const override; void setYstart(uInt32 ystart) override; uInt32 ystart() const override { return myYStart; } void setLayout(FrameLayout mode) override { layout(mode); } void onSetVsync() override; void onNextLine() override; void onReset() override; void onLayoutChange() override; bool onSave(Serializer& out) const override; bool onLoad(Serializer& in) override; string name() const override { return "TIA_FrameManager"; } private: enum State { waitForVsyncStart, waitForVsyncEnd, waitForFrameStart, frame }; private: void updateAutodetectedLayout(); void setState(State state); void updateIsRendering(); private: State myState; uInt32 myLineInState; uInt32 myVsyncLines; uInt32 myY, myLastY; uInt32 myVblankLines; uInt32 myKernelLines; uInt32 myOverscanLines; uInt32 myFrameLines; uInt32 myHeight; uInt32 myFixedHeight; uInt32 myYStart; bool myJitterEnabled; Int32 myStableFrameLines; uInt8 myStableFrameHeightCountdown; JitterEmulation myJitterEmulation; private: FrameManager(const FrameManager&) = delete; FrameManager(FrameManager&&) = delete; FrameManager& operator=(const FrameManager&) = delete; FrameManager& operator=(FrameManager&&) = delete; }; #endif // TIA_FRAME_MANAGER stella-5.1.1/src/emucore/tia/frame-manager/JitterEmulation.cxx000066400000000000000000000073751324334165500243740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "JitterEmulation.hxx" enum Metrics: uInt32 { framesForStableHeight = 2, framesUntilDestabilization = 10, minDeltaForJitter = 3, maxJitter = 50 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JitterEmulation::JitterEmulation() : myYStart(0) {} // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JitterEmulation::reset() { myLastFrameScanlines = 0; myStableFrameFinalLines = -1; myStableFrames = 0; myStabilizationCounter = 0; myDestabilizationCounter = 0; myJitter = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JitterEmulation::frameComplete(uInt32 scanlineCount) { if (Int32(scanlineCount) != myStableFrameFinalLines) { if (myDestabilizationCounter++ > Metrics::framesUntilDestabilization) myStableFrameFinalLines = -1; if (scanlineCount == myLastFrameScanlines) { if (++myStabilizationCounter >= Metrics::framesForStableHeight) { if (myStableFrameFinalLines > 0) updateJitter(scanlineCount - myStableFrameFinalLines); myStableFrameFinalLines = scanlineCount; myDestabilizationCounter = 0; } } else myStabilizationCounter = 0; } else myDestabilizationCounter = 0; myLastFrameScanlines = scanlineCount; if (myJitter > 0) myJitter = std::max(myJitter - myJitterFactor, 0); if (myJitter < 0) myJitter = std::min(myJitter + myJitterFactor, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JitterEmulation::updateJitter(Int32 scanlineDifference) { if (uInt32(abs(scanlineDifference)) < Metrics::minDeltaForJitter) return; Int32 jitter = std::min(scanlineDifference, Metrics::maxJitter); jitter = std::max(jitter, -myYStart); if (jitter > 0) jitter += myJitterFactor; if (jitter < 0) jitter -= myJitterFactor; if (abs(jitter) > abs(myJitter)) myJitter = jitter; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool JitterEmulation::save(Serializer& out) const { try { out.putString(name()); out.putInt(myLastFrameScanlines); out.putInt(myStableFrameFinalLines); out.putInt(myStableFrames); out.putInt(myStabilizationCounter); out.putInt(myDestabilizationCounter); out.putInt(myJitter); out.putInt(myJitterFactor); out.putInt(myYStart); } catch(...) { cerr << "ERROR: JitterEmulation::save" << std::endl; return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool JitterEmulation::load(Serializer& in) { try { if (in.getString() != name()) return false; myLastFrameScanlines = in.getInt(); myStableFrameFinalLines = in.getInt(); myStableFrames = in.getInt(); myStabilizationCounter = in.getInt(); myDestabilizationCounter = in.getInt(); myJitter = in.getInt(); myJitterFactor = in.getInt(); myYStart = in.getInt(); } catch (...) { cerr << "ERROR: JitterEmulation::load" << std::endl; return false; } return true; } stella-5.1.1/src/emucore/tia/frame-manager/JitterEmulation.hxx000066400000000000000000000036411324334165500243710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_JITTER_EMULATION #define TIA_JITTER_EMULATION #include "bspf.hxx" #include "Serializable.hxx" class JitterEmulation: public Serializable { public: JitterEmulation(); public: void reset(); void frameComplete(uInt32 scanlineCount); void setJitterFactor(Int32 factor) { myJitterFactor = factor; } Int32 jitter() const { return myJitter; } void setYStart(uInt32 ystart) { myYStart = ystart; } /** * Save state. */ bool save(Serializer& out) const override; /** * Restore state. */ bool load(Serializer& in) override; string name() const override { return "JitterEmulation"; } private: void updateJitter(Int32 scanlineDifference); private: uInt32 myLastFrameScanlines; Int32 myStableFrameFinalLines; uInt32 myStableFrames; uInt32 myStabilizationCounter; uInt32 myDestabilizationCounter; Int32 myJitter; Int32 myJitterFactor; uInt32 myYStart; private: JitterEmulation(const JitterEmulation&) = delete; JitterEmulation(JitterEmulation&&) = delete; JitterEmulation& operator=(const JitterEmulation&) = delete; JitterEmulation& operator=(JitterEmulation&&) = delete; }; #endif // TIA_JITTER_EMULATION stella-5.1.1/src/emucore/tia/frame-manager/YStartDetector.cxx000066400000000000000000000154721324334165500241720ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "YStartDetector.hxx" #include "TIAConstants.hxx" /** * Misc. numeric constants used in the algorithm. */ enum Metrics: uInt32 { // ideal world frame sizes frameLinesNTSC = 262, frameLinesPAL = 312, // the ideal vblank zone vblankNTSC = 37, vblankPAL = 45, // number of scanlines to wait for vsync to start (exceeding after the ideal frame size) and stop waitForVsync = 50, // max lines underscan maxUnderscan = 10, // max lines deviations from detected ystart before we switch back to floating maxVblankViolations = 2, // switch to fixed mode after this number of stable frames (+1) minStableVblankFrames = 1, // no transitions to fixed mode will happend during those initialGarbageFrames = TIAConstants::initialGarbageFrames }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 YStartDetector::detectedYStart() const { return myLastVblankLines; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void YStartDetector::onReset() { myState = State::waitForVsyncStart; myVblankMode = VblankMode::floating; myLinesWaitingForVsyncToStart = 0; myCurrentVblankLines = 0; myLastVblankLines = 0; myVblankViolations = 0; myStableVblankFrames = 0; myVblankViolated = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void YStartDetector::onSetVsync() { if (myVsync) setState(State::waitForVsyncEnd); else setState(State::waitForFrameStart); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void YStartDetector::onNextLine() { const uInt32 frameLines = layout() == FrameLayout::ntsc ? Metrics::frameLinesNTSC : Metrics::frameLinesPAL; switch (myState) { case State::waitForVsyncStart: // We start counting the number of "lines spent while waiting for vsync start" from // the "ideal" frame size (corrected by the three scanlines spent in vsync). if (myCurrentFrameTotalLines > frameLines - 3 || myTotalFrames == 0) myLinesWaitingForVsyncToStart++; if (myLinesWaitingForVsyncToStart > Metrics::waitForVsync) setState(State::waitForVsyncEnd); break; case State::waitForVsyncEnd: if (++myLinesWaitingForVsyncToStart > Metrics::waitForVsync) setState(State::waitForFrameStart); break; case State::waitForFrameStart: if (shouldTransitionToFrame()) setState(State::waitForVsyncStart); else myCurrentVblankLines++; break; default: throw runtime_error("cannot happen"); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool YStartDetector::shouldTransitionToFrame() { uInt32 vblankLines = layout() == FrameLayout::pal ? Metrics::vblankPAL : Metrics::vblankNTSC; // Are we free to transition as per vblank cycle? bool shouldTransition = myCurrentVblankLines + 1 >= (myVblank ? vblankLines : vblankLines - Metrics::maxUnderscan); // Do we **actually** transition? This depends on what mode we are in. bool transition = false; switch (myVblankMode) { // Floating mode: we still are looking for a stable frame start case VblankMode::floating: // Are we free to transition? if (shouldTransition) { // Is this same scanline in which the transition ocurred last frame? if (myTotalFrames > Metrics::initialGarbageFrames && myCurrentVblankLines == myLastVblankLines) // Yes? -> Increase the number of stable frames myStableVblankFrames++; else // No? -> Frame start shifted again, set the number of consecutive stable frames to zero myStableVblankFrames = 0; // Save the transition point for checking on it next frame myLastVblankLines = myCurrentVblankLines; // In floating mode, we transition whenever we can. transition = true; } // Transition to locked mode if we saw enough stable frames in a row. if (myStableVblankFrames >= Metrics::minStableVblankFrames) { myVblankMode = VblankMode::locked; myVblankViolations = 0; } break; // Locked mode: always transition at the same point, but check whether this is actually the // detected transition point and revert state if applicable case VblankMode::locked: // Have we reached the transition point? if (myCurrentVblankLines == myLastVblankLines) { // Are we free to transition per the algorithm and didn't observe an violation before? // (aka did the algorithm tell us to transition before reaching the actual line) if (shouldTransition && !myVblankViolated) // Reset the number of irregular frames (if any) myVblankViolations = 0; else { // Record a violation if it wasn't recorded before if (!myVblankViolated) myVblankViolations++; myVblankViolated = true; } // transition transition = true; // The algorithm tells us to transition although we haven't reached the trip line before } else if (shouldTransition) { // Record a violation if it wasn't recorded before if (!myVblankViolated) myVblankViolations++; myVblankViolated = true; } // Revert to floating mode if there were too many irregular frames in a row if (myVblankViolations > Metrics::maxVblankViolations) { myVblankMode = VblankMode::floating; myStableVblankFrames = 0; } break; default: throw runtime_error("cannot happen"); } return transition; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void YStartDetector::setState(State state) { if (state == myState) return; myState = state; myLinesWaitingForVsyncToStart = 0; switch (state) { case State::waitForVsyncEnd: break; case State::waitForVsyncStart: notifyFrameComplete(); notifyFrameStart(); break; case State::waitForFrameStart: myVblankViolated = false; myCurrentVblankLines = 0; break; default: throw new runtime_error("cannot happen"); } } stella-5.1.1/src/emucore/tia/frame-manager/YStartDetector.hxx000066400000000000000000000070111324334165500241650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIA_YSTART_DETECTOR #define TIA_YSTART_DETECTOR #include "AbstractFrameManager.hxx" /** * This frame manager detects ystart from the first line with vblank = off. */ class YStartDetector: public AbstractFrameManager { public: YStartDetector() = default; public: /** * Getter for the detected ystart value */ uInt32 detectedYStart() const; /** * We require frame layout to be set from outside. */ void setLayout(FrameLayout layout) override { this->layout(layout); } protected: /** * We need to track vsync changes. */ void onSetVsync() override; /** * Reset hook. */ void onReset() override; /** * The workhorse. */ void onNextLine() override; private: /** * Our various states. */ enum State { // Wait for vsync on waitForVsyncStart, // Wait for vsync off waitForVsyncEnd, // Wait for the visible frame to start waitForFrameStart }; /** * Have we settled on a frame start? */ enum VblankMode { // We have settled on a frame start and have some hysteresis before we return to floating locked, // We are actively looking for the frame to start floating }; private: /** * Side effects for state transitions. */ void setState(State state); /** * Perform detection and decide whether the frame starts now. */ bool shouldTransitionToFrame(); private: /** * State. */ State myState; /** * locked / floating */ VblankMode myVblankMode; /** * Counts the scanlines that we wait for vsync to start. */ uInt32 myLinesWaitingForVsyncToStart; /** * The number of lines we are currently waiting for the frame to start (and vblank to end). */ uInt32 myCurrentVblankLines; /** * The number of vblank lines on the last frame. */ uInt32 myLastVblankLines; /** * Count "vblank violations" in fixed mode (the number of consecutive frames where ystart * differs from the previously detected value). Once a trip point is reached, we transition * back to floating mode. */ uInt32 myVblankViolations; /** * The number of frames in floating mode with stable ystart. Once a trip point is reacted, * we transition to fixed mode */ uInt32 myStableVblankFrames; /** * Tracks deviations from the determined ystart value during a fixed mode frame in order to * avoid double counting. */ bool myVblankViolated; private: YStartDetector(const YStartDetector&) = delete; YStartDetector(YStartDetector&&) = delete; YStartDetector& operator=(const YStartDetector&) = delete; YStartDetector& operator=(YStartDetector&&) = delete; }; #endif // TIA_YSTART_DETECTOR stella-5.1.1/src/emucore/tia/frame-manager/module.mk000066400000000000000000000006441324334165500223370ustar00rootroot00000000000000MODULE := src/emucore/tia/frame-manager MODULE_OBJS := \ src/emucore/tia/frame-manager/FrameManager.o \ src/emucore/tia/frame-manager/AbstractFrameManager.o \ src/emucore/tia/frame-manager/FrameLayoutDetector.o \ src/emucore/tia/frame-manager/YStartDetector.o \ src/emucore/tia/frame-manager/JitterEmulation.o MODULE_DIRS += \ src/emucore/tia/frame-manager # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/emucore/tia/module.mk000066400000000000000000000006331324334165500176330ustar00rootroot00000000000000MODULE := src/emucore/tia MODULE_OBJS := \ src/emucore/tia/TIA.o \ src/emucore/tia/Playfield.o \ src/emucore/tia/DrawCounterDecodes.o \ src/emucore/tia/Missile.o \ src/emucore/tia/Player.o \ src/emucore/tia/Ball.o \ src/emucore/tia/Background.o \ src/emucore/tia/LatchedInput.o \ src/emucore/tia/PaddleReader.o MODULE_DIRS += \ src/emucore/tia # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/gui/000077500000000000000000000000001324334165500143635ustar00rootroot00000000000000stella-5.1.1/src/gui/AboutDialog.cxx000066400000000000000000000200771324334165500173070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Dialog.hxx" #include "OSystem.hxx" #include "Version.hxx" #include "Widget.hxx" #include "Font.hxx" #include "AboutDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AboutDialog::AboutDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font) : Dialog(osystem, parent), myPage(1), myNumPages(4), myLinesPerPage(13) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos; WidgetArray wid; // Set real dimensions _w = 55 * fontWidth + 8; _h = 15 * lineHeight + 20; // Add Previous, Next and Close buttons xpos = 10; ypos = _h - buttonHeight - 10; myPrevButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Previous", GuiObject::kPrevCmd); myPrevButton->clearFlags(WIDGET_ENABLED); wid.push_back(myPrevButton); xpos += buttonWidth + 7; myNextButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Next", GuiObject::kNextCmd); wid.push_back(myNextButton); xpos = _w - buttonWidth - 10; ButtonWidget* b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Close", GuiObject::kCloseCmd); wid.push_back(b); addOKWidget(b); addCancelWidget(b); xpos = 5; ypos = 5; myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - 10, fontHeight, "", TextAlign::Center); myTitle->setTextColor(kTextColorEm); xpos = 10; ypos += lineHeight + 4; for(int i = 0; i < myLinesPerPage; i++) { myDesc.push_back(new StaticTextWidget(this, font, xpos, ypos, _w - 20, fontHeight, "", TextAlign::Left)); myDescStr.push_back(""); ypos += fontHeight; } addToFocusList(wid); } // The following commands can be put at the start of a line (all subject to change): // \C, \L, \R -- set center/left/right alignment // \c0 - \c5 -- set a custom color: // 0 normal text (green) // 1 highlighted text (light green) // 2 light border (light gray) // 3 dark border (dark gray) // 4 background (black) // 5 emphasized text (red) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AboutDialog::updateStrings(int page, int lines, string& title) { int i = 0; auto ADD_ATEXT = [&](const string& d) { myDescStr[i] = d; i++; }; auto ADD_ALINE = [&]() { ADD_ATEXT(""); }; switch(page) { case 1: title = string("Stella ") + STELLA_VERSION; ADD_ATEXT("\\CA multi-platform Atari 2600 VCS emulator"); ADD_ATEXT(string("\\C\\c2Features: ") + instance().features()); ADD_ATEXT(string("\\C\\c2") + instance().buildInfo()); ADD_ALINE(); ADD_ATEXT("\\CCopyright (C) 1995-2018 The Stella Team"); ADD_ATEXT("\\C(https://stella-emu.github.io)"); ADD_ALINE(); ADD_ATEXT("\\CStella is now DonationWare!"); ADD_ATEXT("\\C(https://stella-emu.github.io/donations.html)"); ADD_ALINE(); ADD_ATEXT("\\CStella is free software released under the GNU GPL."); ADD_ATEXT("\\CSee manual for further details."); break; case 2: title = "The Stella Team"; ADD_ATEXT("\\L\\c0"" Stephen Anthony"); ADD_ATEXT("\\L\\c2"" Lead developer, current maintainer for the"); ADD_ATEXT("\\L\\c2"" Linux/OSX and Windows ports "); ADD_ATEXT("\\L\\c0"" Christian Speckner"); ADD_ATEXT("\\L\\c2"" Emulation core development, TIA core"); ADD_ATEXT("\\L\\c0"" Eckhard Stolberg"); ADD_ATEXT("\\L\\c2"" Emulation core development"); ADD_ATEXT("\\L\\c0"" Thomas Jentzsch"); ADD_ATEXT("\\L\\c2"" Emulation core development, jack-of-all-trades"); ADD_ATEXT("\\L\\c0"" Brian Watson"); ADD_ATEXT("\\L\\c2"" Emulation core enhancement, debugger support"); ADD_ATEXT("\\L\\c0"" Bradford W. Mott"); ADD_ATEXT("\\L\\c2"" Original author of Stella"); break; case 3: title = "Contributors"; ADD_ATEXT("\\L\\c0"" See https://stella-emu.github.io/credits.html for"); ADD_ATEXT("\\L\\c0"" people that have contributed to Stella."); ADD_ALINE(); ADD_ATEXT("\\L\\c0"" Thanks to the ScummVM project for the GUI code."); ADD_ALINE(); ADD_ATEXT("\\L\\c0"" Thanks to Ian Bogost and the Georgia Tech"); ADD_ATEXT("\\L\\c0"" Atari Team for the CRT Simulation effects."); break; case 4: title = "Cast of thousands"; ADD_ATEXT("\\L\\c0""Special thanks to AtariAge for introducing the"); ADD_ATEXT("\\L\\c0""Atari 2600 to a whole new generation."); ADD_ATEXT("\\L\\c2"" http://www.atariage.com"); ADD_ALINE(); ADD_ATEXT("\\L\\c0""Finally, a huge thanks to the original Atari 2600"); ADD_ATEXT("\\L\\c0""VCS team for giving us the magic, and to the"); ADD_ATEXT("\\L\\c0""homebrew developers for keeping the magic alive."); break; } while(i < lines) ADD_ALINE(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AboutDialog::displayInfo() { string titleStr; updateStrings(myPage, myLinesPerPage, titleStr); myTitle->setLabel(titleStr); for(int i = 0; i < myLinesPerPage; i++) { const char* str = myDescStr[i].c_str(); TextAlign align = TextAlign::Center; uInt32 color = kTextColor; while (str[0] == '\\') { switch (str[1]) { case 'C': align = TextAlign::Center; break; case 'L': align = TextAlign::Left; break; case 'R': align = TextAlign::Right; break; case 'c': switch (str[2]) { case '0': color = kTextColor; break; case '1': color = kTextColorHi; break; case '2': color = kColor; break; case '3': color = kShadowColor; break; case '4': color = kBGColor; break; case '5': color = kTextColorEm; break; default: break; } str++; break; default: break; } str += 2; } myDesc[i]->setAlign(align); myDesc[i]->setTextColor(color); myDesc[i]->setLabel(str); } // Redraw entire dialog _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AboutDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kNextCmd: myPage++; if(myPage >= myNumPages) myNextButton->clearFlags(WIDGET_ENABLED); if(myPage >= 2) myPrevButton->setFlags(WIDGET_ENABLED); displayInfo(); break; case GuiObject::kPrevCmd: myPage--; if(myPage <= myNumPages) myNextButton->setFlags(WIDGET_ENABLED); if(myPage <= 1) myPrevButton->clearFlags(WIDGET_ENABLED); displayInfo(); break; default: Dialog::handleCommand(sender, cmd, data, 0); } } stella-5.1.1/src/gui/AboutDialog.hxx000066400000000000000000000034611324334165500173120ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ABOUT_DIALOG_HXX #define ABOUT_DIALOG_HXX class OSystem; class DialogContainer; class CommandSender; class ButtonWidget; class StaticTextWidget; #include "Dialog.hxx" class AboutDialog : public Dialog { public: AboutDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); virtual ~AboutDialog() = default; private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void updateStrings(int page, int lines, string& title); void displayInfo(); void loadConfig() override { displayInfo(); } private: ButtonWidget* myNextButton; ButtonWidget* myPrevButton; StaticTextWidget* myTitle; vector myDesc; vector myDescStr; int myPage; int myNumPages; int myLinesPerPage; private: // Following constructors and assignment operators not supported AboutDialog() = delete; AboutDialog(const AboutDialog&) = delete; AboutDialog(AboutDialog&&) = delete; AboutDialog& operator=(const AboutDialog&) = delete; AboutDialog& operator=(AboutDialog&&) = delete; }; #endif stella-5.1.1/src/gui/AudioDialog.cxx000066400000000000000000000160761324334165500173020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "Console.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "Font.hxx" #include "Menu.hxx" #include "OSystem.hxx" #include "PopUpWidget.hxx" #include "Settings.hxx" #include "Sound.hxx" #include "Widget.hxx" #include "AudioDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AudioDialog::AudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font) : Dialog(osystem, parent) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos; int lwidth = font.getStringWidth("Sample Size (*) "), pwidth = font.getStringWidth("512 bytes"); WidgetArray wid; VariantList items; // Set real dimensions _w = 35 * fontWidth + 10; _h = 7 * (lineHeight + 4) + 10; // Volume xpos = 3 * fontWidth; ypos = 10; myVolumeSlider = new SliderWidget(this, font, xpos, ypos, 6*fontWidth, lineHeight, "Volume ", lwidth, kVolumeChanged); myVolumeSlider->setMinValue(1); myVolumeSlider->setMaxValue(100); wid.push_back(myVolumeSlider); myVolumeLabel = new StaticTextWidget(this, font, xpos + myVolumeSlider->getWidth() + 4, ypos + 1, 3*fontWidth, fontHeight, "", TextAlign::Left); myVolumeLabel->setFlags(WIDGET_CLEARBG); ypos += lineHeight + 4; // Fragment size VarList::push_back(items, "128 bytes", "128"); VarList::push_back(items, "256 bytes", "256"); VarList::push_back(items, "512 bytes", "512"); VarList::push_back(items, "1 KB", "1024"); VarList::push_back(items, "2 KB", "2048"); VarList::push_back(items, "4 KB", "4096"); myFragsizePopup = new PopUpWidget(this, font, xpos, ypos, pwidth + myVolumeLabel->getWidth() - 4, lineHeight, items, "Sample size (*) ", lwidth); wid.push_back(myFragsizePopup); ypos += lineHeight + 4; // Output frequency items.clear(); VarList::push_back(items, "11025 Hz", "11025"); VarList::push_back(items, "22050 Hz", "22050"); VarList::push_back(items, "31400 Hz", "31400"); VarList::push_back(items, "44100 Hz", "44100"); VarList::push_back(items, "48000 Hz", "48000"); myFreqPopup = new PopUpWidget(this, font, xpos, ypos, pwidth + myVolumeLabel->getWidth() - 4, lineHeight, items, "Frequency (*) ", lwidth); wid.push_back(myFreqPopup); ypos += lineHeight + 4; // Enable sound xpos = (_w - (font.getStringWidth("Enable sound") + 10)) / 2; ypos += 4; mySoundEnableCheckbox = new CheckboxWidget(this, font, xpos, ypos, "Enable sound", kSoundEnableChanged); wid.push_back(mySoundEnableCheckbox); // Add message concerning usage ypos += lineHeight + 12; const GUI::Font& infofont = instance().frameBuffer().infoFont(); new StaticTextWidget(this, infofont, 10, ypos, font.getStringWidth("(*) Requires application restart"), fontHeight, "(*) Requires application restart", TextAlign::Left); // Add Defaults, OK and Cancel buttons ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioDialog::loadConfig() { // Volume myVolumeSlider->setValue(instance().settings().getInt("volume")); myVolumeLabel->setLabel(instance().settings().getString("volume")); // Fragsize myFragsizePopup->setSelected(instance().settings().getString("fragsize"), "512"); // Output frequency myFreqPopup->setSelected(instance().settings().getString("freq"), "31400"); // Enable sound bool b = instance().settings().getBool("sound"); mySoundEnableCheckbox->setState(b); // Make sure that mutually-exclusive items are not enabled at the same time handleSoundEnableChange(b); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioDialog::saveConfig() { Settings& settings = instance().settings(); // Volume settings.setValue("volume", myVolumeSlider->getValue()); instance().sound().setVolume(myVolumeSlider->getValue()); // Fragsize settings.setValue("fragsize", myFragsizePopup->getSelectedTag().toString()); // Output frequency settings.setValue("freq", myFreqPopup->getSelectedTag().toString()); // Enable/disable sound (requires a restart to take effect) instance().sound().setEnabled(mySoundEnableCheckbox->getState()); // Only force a re-initialization when necessary, since it can // be a time-consuming operation if(instance().hasConsole()) instance().console().initializeAudio(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioDialog::setDefaults() { myVolumeSlider->setValue(100); myVolumeLabel->setLabel("100"); myFragsizePopup->setSelected("512", ""); myFreqPopup->setSelected("31400", ""); mySoundEnableCheckbox->setState(true); // Make sure that mutually-exclusive items are not enabled at the same time handleSoundEnableChange(true); _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioDialog::handleSoundEnableChange(bool active) { myVolumeSlider->setEnabled(active); myVolumeLabel->setEnabled(active); myFragsizePopup->setEnabled(active); myFreqPopup->setEnabled(active); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void AudioDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; case kVolumeChanged: myVolumeLabel->setValue(myVolumeSlider->getValue()); break; case kSoundEnableChanged: handleSoundEnableChange(data == 1); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/gui/AudioDialog.hxx000066400000000000000000000036331324334165500173020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef AUDIO_DIALOG_HXX #define AUDIO_DIALOG_HXX class CommandSender; class Dialog; class DialogContainer; class PopUpWidget; class SliderWidget; class StaticTextWidget; class CheckboxWidget; class OSystem; #include "bspf.hxx" class AudioDialog : public Dialog { public: AudioDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); virtual ~AudioDialog() = default; private: void loadConfig() override; void saveConfig() override; void setDefaults() override; void handleSoundEnableChange(bool active); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: enum { kVolumeChanged = 'ADvc', kSoundEnableChanged = 'ADse' }; SliderWidget* myVolumeSlider; StaticTextWidget* myVolumeLabel; PopUpWidget* myFragsizePopup; PopUpWidget* myFreqPopup; CheckboxWidget* mySoundEnableCheckbox; private: // Following constructors and assignment operators not supported AudioDialog() = delete; AudioDialog(const AudioDialog&) = delete; AudioDialog(AudioDialog&&) = delete; AudioDialog& operator=(const AudioDialog&) = delete; AudioDialog& operator=(AudioDialog&&) = delete; }; #endif stella-5.1.1/src/gui/BrowserDialog.cxx000066400000000000000000000154571324334165500176660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "FSNode.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "FileListWidget.hxx" #include "Widget.hxx" #include "Font.hxx" #include "BrowserDialog.hxx" /* We want to use this as a general directory selector at some point... possible uses * - to select the data dir for a game * - to select the place where save games are stored * - others??? */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BrowserDialog::BrowserDialog(GuiObject* boss, const GUI::Font& font, int max_w, int max_h) : Dialog(boss->instance(), boss->parent()), CommandSender(boss), _cmd(0), _mode(FileSave) { // Set real dimensions _w = max_w; _h = max_h; const int lineHeight = font.getLineHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4, selectHeight = lineHeight + 8; int xpos, ypos; ButtonWidget* b; xpos = 10; ypos = 4; _title = new StaticTextWidget(this, font, xpos, ypos, _w - 2 * xpos, lineHeight, "", TextAlign::Center); // Current path - TODO: handle long paths ? ypos += lineHeight + 4; _currentPath = new StaticTextWidget(this, font, xpos, ypos, _w - 2 * xpos, lineHeight, "", TextAlign::Left); // Add file list ypos += lineHeight + 4; _fileList = new FileListWidget(this, font, xpos, ypos, _w - 2 * xpos, _h - selectHeight - buttonHeight - ypos - 20); _fileList->setEditable(false); addFocusWidget(_fileList); // Add currently selected item ypos += _fileList->getHeight() + 4; _type = new StaticTextWidget(this, font, xpos, ypos+2, font.getStringWidth("Name "), lineHeight, "Name", TextAlign::Center); _selected = new EditTextWidget(this, font, xpos + _type->getWidth(), ypos, _w - _type->getWidth() - 2 * xpos, lineHeight, ""); _selected->setEditable(false); addFocusWidget(_selected); // Buttons _goUpButton = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Go up", kGoUpCmd); addFocusWidget(_goUpButton); _basedirButton = new ButtonWidget(this, font, 15 + buttonWidth, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Base Dir", kBaseDirCmd); addFocusWidget(_basedirButton); #ifndef BSPF_MAC_OSX b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, buttonWidth, buttonHeight, "Choose", kChooseCmd); addFocusWidget(b); addOKWidget(b); b = new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10, buttonWidth, buttonHeight, "Cancel", GuiObject::kCloseCmd); addFocusWidget(b); addCancelWidget(b); #else b = new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, buttonWidth, buttonHeight, "Cancel", GuiObject::kCloseCmd); addFocusWidget(b); addCancelWidget(b); b = new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10, buttonWidth, buttonHeight, "Choose", kChooseCmd); addFocusWidget(b); addOKWidget(b); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BrowserDialog::show(const string& title, const string& startpath, BrowserDialog::ListMode mode, int cmd, const string& ext) { _title->setLabel(title); _cmd = cmd; _mode = mode; switch(_mode) { case FileLoad: _fileList->setFileListMode(FilesystemNode::kListAll); _fileList->setFileExtension(ext); _selected->setEditable(false); break; case FileSave: _fileList->setFileListMode(FilesystemNode::kListAll); _fileList->setFileExtension(ext); _selected->setEditable(false); // FIXME - disable user input for now break; case Directories: _fileList->setFileListMode(FilesystemNode::kListDirectoriesOnly); _selected->setEditable(false); break; } // Set start path _fileList->setLocation(FilesystemNode(startpath)); updateUI(); // Finally, open the dialog after it has been fully updated open(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const FilesystemNode& BrowserDialog::getResult() const { if(_mode == FileLoad || _mode == FileSave) return _fileList->selected(); else return _fileList->currentDir(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BrowserDialog::updateUI() { // Only hilite the 'up' button if there's a parent directory _goUpButton->setEnabled(_fileList->currentDir().hasParent()); // Update the path display _currentPath->setLabel(_fileList->currentDir().getShortPath()); // Enable/disable OK button based on current mode bool enable = _mode == Directories || !_fileList->selected().isDirectory(); _okWidget->setEnabled(enable); if(!_fileList->selected().isDirectory()) _selected->setText(_fileList->getSelectedString()); else _selected->setText(""); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void BrowserDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case kChooseCmd: case FileListWidget::ItemActivated: // Send a signal to the calling class that a selection has been made // Since we aren't derived from a widget, we don't have a 'data' or 'id' if(_cmd) sendCommand(_cmd, -1, -1); close(); break; case kGoUpCmd: _fileList->selectParent(); break; case kBaseDirCmd: _fileList->setLocation(FilesystemNode(instance().baseDir())); break; case FileListWidget::ItemChanged: updateUI(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/gui/BrowserDialog.hxx000066400000000000000000000047411324334165500176650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef BROWSER_DIALOG_HXX #define BROWSER_DIALOG_HXX class GuiObject; class ButtonWidget; class EditTextWidget; class FileListWidget; class StaticTextWidget; class FilesystemNode; #include "Dialog.hxx" #include "Command.hxx" #include "bspf.hxx" class BrowserDialog : public Dialog, public CommandSender { public: enum ListMode { FileLoad, // File selector, no input from user FileSave, // File selector, filename changable by user Directories // Directories only, no input from user }; public: BrowserDialog(GuiObject* boss, const GUI::Font& font, int max_w, int max_h); virtual ~BrowserDialog() = default; /** Place the browser window onscreen, using the given attributes */ void show(const string& title, const string& startpath, BrowserDialog::ListMode mode, int cmd, const string& ext = ""); /** Get resulting file node (called after receiving kChooseCmd) */ const FilesystemNode& getResult() const; private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void updateUI(); private: enum { kChooseCmd = 'CHOS', kGoUpCmd = 'GOUP', kBaseDirCmd = 'BADR' }; int _cmd; FileListWidget* _fileList; StaticTextWidget* _currentPath; StaticTextWidget* _title; StaticTextWidget* _type; EditTextWidget* _selected; ButtonWidget* _goUpButton; ButtonWidget* _basedirButton; BrowserDialog::ListMode _mode; private: // Following constructors and assignment operators not supported BrowserDialog() = delete; BrowserDialog(const BrowserDialog&) = delete; BrowserDialog(BrowserDialog&&) = delete; BrowserDialog& operator=(const BrowserDialog&) = delete; BrowserDialog& operator=(BrowserDialog&&) = delete; }; #endif stella-5.1.1/src/gui/CheckListWidget.cxx000066400000000000000000000135711324334165500201330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Dialog.hxx" #include "FBSurface.hxx" #include "ScrollBarWidget.hxx" #include "CheckListWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheckListWidget::CheckListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : ListWidget(boss, font, x, y, w, h, false) // disable quick select { int ypos = _y + 2; // rowheight is determined by largest item on a line, // possibly meaning that number of rows will change _fontHeight = std::max(_fontHeight, CheckboxWidget::boxSize()); _rows = h / _fontHeight; // Create a CheckboxWidget for each row in the list CheckboxWidget* t = nullptr; for(int i = 0; i < _rows; ++i) { t = new CheckboxWidget(boss, font, _x + 2, ypos, "", CheckboxWidget::kCheckActionCmd); t->setTextColor(kTextColor); t->setTarget(this); t->setID(i); ypos += _fontHeight; _checkList.push_back(t); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckListWidget::setList(const StringList& list, const BoolArray& state) { _list = list; _stateList = state; assert(_list.size() == _stateList.size()); // Enable all checkboxes for(int i = 0; i < _rows; ++i) _checkList[i]->setFlags(WIDGET_ENABLED); // Then turn off any extras if(int(_stateList.size()) < _rows) for(int i = int(_stateList.size()); i < _rows; ++i) _checkList[i]->clearFlags(WIDGET_ENABLED); ListWidget::recalc(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckListWidget::setLine(int line, const string& str, const bool& state) { if(line >= int(_list.size())) return; _list[line] = str; _stateList[line] = state; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckListWidget::drawWidget(bool hilite) { //cerr << "CheckListWidget::drawWidget\n"; FBSurface& s = _boss->dialog().surface(); int i, pos, len = int(_list.size()); // Draw a thin frame around the list and to separate columns s.hLine(_x, _y, _x + _w - 1, kColor); s.hLine(_x, _y + _h - 1, _x + _w - 1, kShadowColor); s.vLine(_x, _y, _y + _h - 1, kColor); s.vLine(_x + CheckboxWidget::boxSize() + 5, _y, _y + _h - 1, kColor); // Draw the list items for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++) { // Draw checkboxes for correct lines (takes scrolling into account) _checkList[i]->setState(_stateList[pos]); _checkList[i]->setDirty(); _checkList[i]->draw(); const int y = _y + 2 + _fontHeight * i + 2; uInt32 textColor = kTextColor; GUI::Rect r(getEditRect()); // Draw the selected item inverted, on a highlighted background. if (_selectedItem == pos) { if(_hasFocus && !_editMode) { s.fillRect(_x + r.left - 3, _y + 1 + _fontHeight * i, _w - r.left, _fontHeight, kTextColorHi); textColor = kTextColorInv; } else s.frameRect(_x + r.left - 3, _y + 1 + _fontHeight * i, _w - r.left, _fontHeight, kTextColorHi); } if (_selectedItem == pos && _editMode) { adjustOffset(); s.drawString(_font, editString(), _x + r.left, y, r.width(), kTextColor, TextAlign::Left, -_editScrollOffset, false); } else s.drawString(_font, _list[pos], _x + r.left, y, r.width(), textColor); } // Only draw the caret while editing, and if it's in the current viewport if(_editMode && (_selectedItem >= _scrollBar->_currentPos) && (_selectedItem < _scrollBar->_currentPos + _rows)) drawCaret(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect CheckListWidget::getEditRect() const { GUI::Rect r(2, 1, _w, _fontHeight); const int yoffset = (_selectedItem - _currentPos) * _fontHeight, xoffset = CheckboxWidget::boxSize() + 10; r.top += yoffset; r.bottom += yoffset; r.left += xoffset; r.right -= xoffset - 15; return r; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CheckListWidget::getState(int line) { if(line >= 0 && line < int(_stateList.size())) return _stateList[line]; else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool CheckListWidget::handleEvent(Event::Type e) { switch(e) { case Event::UISelect: // Simulate a mouse button click _checkList[ListWidget::getSelected()]->handleMouseUp(0, 0, MouseButton::LEFT, 0); return true; default: return ListWidget::handleEvent(e); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case CheckboxWidget::kCheckActionCmd: { // Figure out which line has been checked int line = _currentPos + id; _stateList[line] = bool(data); // Let the boss know about it sendCommand(CheckListWidget::kListItemChecked, line, _id); break; } default: ListWidget::handleCommand(sender, cmd, data, id); break; } } stella-5.1.1/src/gui/CheckListWidget.hxx000066400000000000000000000041271324334165500201350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CHECK_LIST_WIDGET_HXX #define CHECK_LIST_WIDGET_HXX class CheckboxWidget; #include "ListWidget.hxx" using CheckboxArray = vector; /** CheckListWidget */ class CheckListWidget : public ListWidget { public: enum { kListItemChecked = 'LIct' /* checkbox toggled on current line*/ }; enum CheckStyle { XFill, SolidFill }; public: CheckListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~CheckListWidget() = default; void setStyle(CheckStyle style); void setList(const StringList& list, const BoolArray& state); void setLine(int line, const string& str, const bool& state); bool getState(int line); bool getSelectedState() { return getState(_selectedItem); } private: bool handleEvent(Event::Type e) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void drawWidget(bool hilite) override; GUI::Rect getEditRect() const override; protected: BoolArray _stateList; CheckboxArray _checkList; private: // Following constructors and assignment operators not supported CheckListWidget() = delete; CheckListWidget(const CheckListWidget&) = delete; CheckListWidget(CheckListWidget&&) = delete; CheckListWidget& operator=(const CheckListWidget&) = delete; CheckListWidget& operator=(CheckListWidget&&) = delete; }; #endif stella-5.1.1/src/gui/ColorWidget.cxx000066400000000000000000000043351324334165500173360ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Command.hxx" #include "Dialog.hxx" #include "FBSurface.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "ColorWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ColorWidget::ColorWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, int cmd) : Widget(boss, font, x, y, w, h), CommandSender(boss), _color(0), _cmd(cmd), _crossGrid(false) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ColorWidget::setColor(int color) { _color = color; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ColorWidget::drawWidget(bool hilite) { FBSurface& s = dialog().surface(); // Draw a thin frame around us. #ifndef FLAT_UI s.hLine(_x, _y, _x + _w - 1, kColor); s.hLine(_x, _y +_h, _x + _w - 1, kShadowColor); s.vLine(_x, _y, _y+_h, kColor); s.vLine(_x + _w - 1, _y, _y +_h - 1, kShadowColor); #else s.frameRect(_x, _y, _w, _h + 1, kColor); #endif // Show the currently selected color s.fillRect(_x+1, _y+1, _w-2, _h-1, isEnabled() ? _color : kWidColor); // Cross out the grid? if(_crossGrid) { #ifndef FLAT_UI for(uInt32 row = 1; row < 4; ++row) s.hLine(_x, _y + (row * _h/4), _x + _w - 2, kColor); #else s.line(_x + 1, _y + 1, _x + _w - 2, _y + _h - 1, kColor); s.line(_x + _w - 2, _y + 1, _x + 1, _y + _h - 1, kColor); #endif } } stella-5.1.1/src/gui/ColorWidget.hxx000066400000000000000000000034421324334165500173410ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef COLOR_WIDGET_HXX #define COLOR_WIDGET_HXX class ColorDialog; class GuiObject; #include "Widget.hxx" #include "Command.hxx" /** Displays a color from the TIA palette. This class will eventually be expanded with a TIA palette table, to set the color visually. @author Stephen Anthony */ class ColorWidget : public Widget, public CommandSender { friend class ColorDialog; public: ColorWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, int cmd = 0); virtual ~ColorWidget() = default; void setColor(int color); int getColor() const { return _color; } void setCrossed(bool enable) { _crossGrid = enable; } protected: void drawWidget(bool hilite) override; protected: int _color; int _cmd; bool _crossGrid; private: // Following constructors and assignment operators not supported ColorWidget() = delete; ColorWidget(const ColorWidget&) = delete; ColorWidget(ColorWidget&&) = delete; ColorWidget& operator=(const ColorWidget&) = delete; ColorWidget& operator=(ColorWidget&&) = delete; }; #endif stella-5.1.1/src/gui/ComboDialog.cxx000066400000000000000000000114251324334165500172710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "EventHandler.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "Widget.hxx" #include "Font.hxx" #include "ComboDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ComboDialog::ComboDialog(GuiObject* boss, const GUI::Font& font, const VariantList& combolist) : Dialog(boss->instance(), boss->parent()), myComboEvent(Event::NoType) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos; WidgetArray wid; // Set real dimensions _w = 35 * fontWidth + 10; _h = 11 * (lineHeight + 4) + 10; xpos = ypos = 5; // Get maximum width of popupwidget int pwidth = 0; for(const auto& s: combolist) pwidth = std::max(font.getStringWidth(s.first), pwidth); // Label for dialog, indicating which combo is being changed myComboName = new StaticTextWidget(this, font, xpos, ypos, _w - xpos - 10, fontHeight, "", TextAlign::Center); ypos += (lineHeight + 4) + 5; // Add event popup for 8 events auto ADD_EVENT_POPUP = [&](int idx, const string& label) { myEvents[idx] = new PopUpWidget(this, font, xpos, ypos, pwidth, lineHeight, combolist, label); wid.push_back(myEvents[idx]); ypos += lineHeight + 4; }; xpos = 10; myEvents[0] = nullptr; ADD_EVENT_POPUP(0, "Event 1 "); myEvents[1] = nullptr; ADD_EVENT_POPUP(1, "Event 2 "); myEvents[2] = nullptr; ADD_EVENT_POPUP(2, "Event 3 "); myEvents[3] = nullptr; ADD_EVENT_POPUP(3, "Event 4 "); myEvents[4] = nullptr; ADD_EVENT_POPUP(4, "Event 5 "); myEvents[5] = nullptr; ADD_EVENT_POPUP(5, "Event 6 "); myEvents[6] = nullptr; ADD_EVENT_POPUP(6, "Event 7 "); myEvents[7] = nullptr; ADD_EVENT_POPUP(7, "Event 8 "); // Add Defaults, OK and Cancel buttons ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ComboDialog::show(Event::Type event, const string& name) { // Make sure the event is allowed if(event >= Event::Combo1 && event <= Event::Combo16) { myComboEvent = event; myComboName->setLabel("Add events for " + name); open(); } else myComboEvent = Event::NoType; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ComboDialog::loadConfig() { StringList events = instance().eventHandler().getComboListForEvent(myComboEvent); uInt32 size = std::min(uInt32(events.size()), 8u); for(uInt32 i = 0; i < size; ++i) myEvents[i]->setSelected("", events[i]); // Fill any remaining items to 'None' if(size < 8) for(uInt32 i = size; i < 8; ++i) myEvents[i]->setSelected("None", "-1"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ComboDialog::saveConfig() { StringList events; for(int i = 0; i < 8; ++i) events.push_back(myEvents[i]->getSelectedTag().toString()); instance().eventHandler().setComboListForEvent(myComboEvent, events); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ComboDialog::setDefaults() { for(int i = 0; i < 8; ++i) myEvents[i]->setSelected("None", "-1"); _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ComboDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/gui/ComboDialog.hxx000066400000000000000000000033531324334165500172770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef COMBO_DIALOG_HXX #define COMBO_DIALOG_HXX class PopUpWidget; class EditTextWidget; class StaticTextWidget; class OSystem; #include "Dialog.hxx" #include "bspf.hxx" class ComboDialog : public Dialog { public: ComboDialog(GuiObject* boss, const GUI::Font& font, const VariantList& combolist); virtual ~ComboDialog() = default; /** Place the dialog onscreen and center it */ void show(Event::Type event, const string& name); private: void loadConfig() override; void saveConfig() override; void setDefaults() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: Event::Type myComboEvent; StaticTextWidget* myComboName; PopUpWidget* myEvents[8]; private: // Following constructors and assignment operators not supported ComboDialog() = delete; ComboDialog(const ComboDialog&) = delete; ComboDialog(ComboDialog&&) = delete; ComboDialog& operator=(const ComboDialog&) = delete; ComboDialog& operator=(ComboDialog&&) = delete; }; #endif stella-5.1.1/src/gui/Command.hxx000066400000000000000000000034021324334165500164710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef COMMAND_HXX #define COMMAND_HXX #include "bspf.hxx" /** Allows base GUI objects to send and receive commands. @author Stephen Anthony */ class CommandReceiver; class CommandSender; class CommandReceiver { friend class CommandSender; public: virtual ~CommandReceiver() = default; protected: virtual void handleCommand(CommandSender* sender, int cmd, int data, int id) { } }; class CommandSender { // TODO - allow for multiple targets, i.e. store targets in a list // and add methods addTarget/removeTarget. public: CommandSender(CommandReceiver* target) : _target(target) { } virtual ~CommandSender() = default; void setTarget(CommandReceiver* target) { _target = target; } CommandReceiver* getTarget() const { return _target; } virtual void sendCommand(int cmd, int data, int id) { if(_target && cmd) _target->handleCommand(this, cmd, data, id); } protected: CommandReceiver* _target; }; #endif stella-5.1.1/src/gui/CommandDialog.cxx000066400000000000000000000124621324334165500176120ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Console.hxx" #include "TIA.hxx" #include "Switches.hxx" #include "Dialog.hxx" #include "Font.hxx" #include "EventHandler.hxx" #include "OSystem.hxx" #include "Widget.hxx" #include "CommandDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent) : Dialog(osystem, parent) { const GUI::Font& font = instance().frameBuffer().font(); const int buttonWidth = font.getStringWidth("Right Diff B") + 20, buttonHeight = font.getLineHeight() + 6, rowHeight = font.getLineHeight() + 10; // Set real dimensions _w = 3 * (buttonWidth + 5) + 20; _h = 6 * rowHeight + 15; WidgetArray wid; ButtonWidget* b[16]; int xoffset = 10, yoffset = 10; auto ADD_CD_BUTTON = [&](const string& label, int cmd) { ButtonWidget* bw = new ButtonWidget(this, font, xoffset, yoffset, buttonWidth, buttonHeight, label, cmd); xoffset += buttonWidth + 6; return bw; }; // Row 1 b[0] = ADD_CD_BUTTON("Select", kSelectCmd); b[4] = ADD_CD_BUTTON("Left Diff A", kLeftDiffACmd); b[8] = ADD_CD_BUTTON("Save State", kSaveStateCmd); // Row 2 xoffset = 10; yoffset += buttonHeight + 3; b[1] = ADD_CD_BUTTON("Reset", kResetCmd); b[5] = ADD_CD_BUTTON("Left Diff B", kLeftDiffBCmd); b[9] = ADD_CD_BUTTON("State Slot", kStateSlotCmd); // Row 3 xoffset = 10; yoffset += buttonHeight + 3; b[2] = ADD_CD_BUTTON("Color TV", kColorCmd); b[6] = ADD_CD_BUTTON("Right Diff A", kRightDiffACmd); b[10] = ADD_CD_BUTTON("Load State", kLoadStateCmd); // Row 4 xoffset = 10; yoffset += buttonHeight + 3; b[3] = ADD_CD_BUTTON("B/W TV", kBWCmd); b[7] = ADD_CD_BUTTON("Right Diff B", kRightDiffBCmd); b[11] = ADD_CD_BUTTON("Snapshot", kSnapshotCmd); // Row 5 xoffset = 10; yoffset += buttonHeight + 3; b[12] = ADD_CD_BUTTON("NTSC/PAL", kFormatCmd); b[13] = ADD_CD_BUTTON("Palette", kPaletteCmd); b[14] = ADD_CD_BUTTON("Reload ROM", kReloadRomCmd); // Row 6 xoffset = 10 + buttonWidth + 6; yoffset += buttonHeight + 3; b[15] = ADD_CD_BUTTON("Exit Game", kExitCmd); for(int i = 0; i < 16; ++i) wid.push_back(b[i]); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CommandDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { bool consoleCmd = false, stateCmd = false; Event::Type event = Event::NoType; switch(cmd) { case kSelectCmd: event = Event::ConsoleSelect; consoleCmd = true; break; case kResetCmd: event = Event::ConsoleReset; consoleCmd = true; break; case kColorCmd: event = Event::ConsoleColor; consoleCmd = true; break; case kBWCmd: event = Event::ConsoleBlackWhite; consoleCmd = true; break; case kLeftDiffACmd: event = Event::ConsoleLeftDiffA; consoleCmd = true; break; case kLeftDiffBCmd: event = Event::ConsoleLeftDiffB; consoleCmd = true; break; case kRightDiffACmd: event = Event::ConsoleRightDiffA; consoleCmd = true; break; case kRightDiffBCmd: event = Event::ConsoleRightDiffB; consoleCmd = true; break; case kSaveStateCmd: event = Event::SaveState; consoleCmd = true; break; case kStateSlotCmd: event = Event::ChangeState; stateCmd = true; break; case kLoadStateCmd: event = Event::LoadState; consoleCmd = true; break; case kSnapshotCmd: instance().eventHandler().leaveMenuMode(); instance().eventHandler().handleEvent(Event::TakeSnapshot, 1); break; case kFormatCmd: instance().eventHandler().leaveMenuMode(); instance().console().toggleFormat(); break; case kPaletteCmd: instance().eventHandler().leaveMenuMode(); instance().console().togglePalette(); break; case kReloadRomCmd: instance().eventHandler().leaveMenuMode(); instance().reloadConsole(); break; case kExitCmd: instance().eventHandler().handleEvent(Event::LauncherMode, 1); break; } // Console commands show be performed right away, after leaving the menu // State commands require you to exit the menu manually if(consoleCmd) { instance().eventHandler().leaveMenuMode(); instance().eventHandler().handleEvent(event, 1); instance().console().switches().update(); instance().console().tia().update(); instance().eventHandler().handleEvent(event, 0); } else if(stateCmd) instance().eventHandler().handleEvent(event, 1); } stella-5.1.1/src/gui/CommandDialog.hxx000066400000000000000000000037261324334165500176220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef COMMAND_DIALOG_HXX #define COMMAND_DIALOG_HXX class Properties; class CommandSender; class DialogContainer; class OSystem; #include "Dialog.hxx" class CommandDialog : public Dialog { public: CommandDialog(OSystem& osystem, DialogContainer& parent); virtual ~CommandDialog() = default; protected: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; enum { kSelectCmd = 'Csel', kResetCmd = 'Cres', kColorCmd = 'Ccol', kBWCmd = 'Cbwt', kLeftDiffACmd = 'Clda', kLeftDiffBCmd = 'Cldb', kRightDiffACmd = 'Crda', kRightDiffBCmd = 'Crdb', kSaveStateCmd = 'Csst', kStateSlotCmd = 'Ccst', kLoadStateCmd = 'Clst', kSnapshotCmd = 'Csnp', kFormatCmd = 'Cfmt', kPaletteCmd = 'Cpal', kReloadRomCmd = 'Crom', kExitCmd = 'Clex' }; enum { kNumRows = 4, kNumCols = 4 }; private: // Following constructors and assignment operators not supported CommandDialog() = delete; CommandDialog(const CommandDialog&) = delete; CommandDialog(CommandDialog&&) = delete; CommandDialog& operator=(const CommandDialog&) = delete; CommandDialog& operator=(CommandDialog&&) = delete; }; #endif stella-5.1.1/src/gui/CommandMenu.cxx000066400000000000000000000017311324334165500173140ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Dialog.hxx" #include "CommandDialog.hxx" #include "CommandMenu.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CommandMenu::CommandMenu(OSystem& osystem) : DialogContainer(osystem) { myBaseDialog = new CommandDialog(myOSystem, *this); } stella-5.1.1/src/gui/CommandMenu.hxx000066400000000000000000000025531324334165500173240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef COMMAND_MENU_HXX #define COMMAND_MENU_HXX class Properties; class OSystem; #include "DialogContainer.hxx" /** The base dialog for common commands in Stella. @author Stephen Anthony */ class CommandMenu : public DialogContainer { public: /** Create a new menu stack */ CommandMenu(OSystem& osystem); virtual ~CommandMenu() = default; private: // Following constructors and assignment operators not supported CommandMenu() = delete; CommandMenu(const CommandMenu&) = delete; CommandMenu(CommandMenu&&) = delete; CommandMenu& operator=(const CommandMenu&) = delete; CommandMenu& operator=(CommandMenu&&) = delete; }; #endif stella-5.1.1/src/gui/ConfigPathDialog.cxx000066400000000000000000000245451324334165500202630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "BrowserDialog.hxx" #include "EditTextWidget.hxx" #include "FSNode.hxx" #include "Font.hxx" #include "LauncherDialog.hxx" #include "PopUpWidget.hxx" #include "Settings.hxx" #include "ConfigPathDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ConfigPathDialog::ConfigPathDialog( OSystem& osystem, DialogContainer& parent, const GUI::Font& font, GuiObject* boss) : Dialog(osystem, parent), CommandSender(boss), myFont(font), myBrowser(nullptr), myIsGlobal(boss != nullptr) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), buttonWidth = font.getStringWidth("Properties file") + 20, buttonHeight = font.getLineHeight() + 4; const int vBorder = 8; const int hBorder = 10; int xpos, ypos; WidgetArray wid; ButtonWidget* b; // Set real dimensions _w = 56 * fontWidth + 8; _h = 9 * (lineHeight + 4) + 10; xpos = hBorder; ypos = vBorder; // ROM path ButtonWidget* romButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "ROM path" + ELLIPSIS, kChooseRomDirCmd); wid.push_back(romButton); xpos += buttonWidth + 10; myRomPath = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(myRomPath); // Cheat file xpos = hBorder; ypos += romButton->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Cheat file" + ELLIPSIS, kChooseCheatFileCmd); wid.push_back(b); xpos += buttonWidth + 10; myCheatFile = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(myCheatFile); // Palette file xpos = hBorder; ypos += b->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Palette file" + ELLIPSIS, kChoosePaletteFileCmd); wid.push_back(b); xpos += buttonWidth + 10; myPaletteFile = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(myPaletteFile); // Properties file xpos = hBorder; ypos += b->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Properties file" + ELLIPSIS, kChoosePropsFileCmd); wid.push_back(b); xpos += buttonWidth + 10; myPropsFile = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(myPropsFile); // State directory xpos = hBorder; ypos += b->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "State path" + ELLIPSIS, kChooseStateDirCmd); wid.push_back(b); xpos += buttonWidth + 10; myStatePath = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(myStatePath); // NVRAM directory xpos = hBorder; ypos += b->getHeight() + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "NVRAM path" + ELLIPSIS, kChooseNVRamDirCmd); wid.push_back(b); xpos += buttonWidth + 10; myNVRamPath = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(myNVRamPath); // Add Defaults, OK and Cancel buttons b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, font.getStringWidth("Defaults") + 20, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); // All ROM settings are disabled while in game mode if(!myIsGlobal) { romButton->clearFlags(WIDGET_ENABLED); myRomPath->setEditable(false); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ConfigPathDialog::~ConfigPathDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ConfigPathDialog::loadConfig() { const Settings& settings = instance().settings(); myRomPath->setText(settings.getString("romdir")); myCheatFile->setText(settings.getString("cheatfile")); myPaletteFile->setText(settings.getString("palettefile")); myPropsFile->setText(settings.getString("propsfile")); myNVRamPath->setText(settings.getString("nvramdir")); myStatePath->setText(settings.getString("statedir")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ConfigPathDialog::saveConfig() { instance().settings().setValue("romdir", myRomPath->getText()); instance().settings().setValue("cheatfile", myCheatFile->getText()); instance().settings().setValue("palettefile", myPaletteFile->getText()); instance().settings().setValue("propsfile", myPropsFile->getText()); instance().settings().setValue("statedir", myStatePath->getText()); instance().settings().setValue("nvramdir", myNVRamPath->getText()); // Flush changes to disk and inform the OSystem instance().saveConfig(); instance().setConfigPaths(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ConfigPathDialog::setDefaults() { FilesystemNode node; const string& basedir = instance().baseDir(); node = FilesystemNode("~"); myRomPath->setText(node.getShortPath()); const string& cheatfile = basedir + "stella.cht"; node = FilesystemNode(cheatfile); myCheatFile->setText(node.getShortPath()); const string& palettefile = basedir + "stella.pal"; node = FilesystemNode(palettefile); myPaletteFile->setText(node.getShortPath()); const string& propsfile = basedir + "stella.pro"; node = FilesystemNode(propsfile); myPropsFile->setText(node.getShortPath()); const string& nvramdir = basedir + "nvram"; node = FilesystemNode(nvramdir); myNVRamPath->setText(node.getShortPath()); const string& statedir = basedir + "state"; node = FilesystemNode(statedir); myStatePath->setText(node.getShortPath()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ConfigPathDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case GuiObject::kOKCmd: saveConfig(); close(); if(myIsGlobal) // Let the boss know romdir has changed sendCommand(LauncherDialog::kRomDirChosenCmd, 0, 0); break; case GuiObject::kDefaultsCmd: setDefaults(); break; case kChooseRomDirCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary createBrowser(); myBrowser->show("Select ROM directory", myRomPath->getText(), BrowserDialog::Directories, LauncherDialog::kRomDirChosenCmd); break; case kChooseCheatFileCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary createBrowser(); myBrowser->show("Select cheat file", myCheatFile->getText(), BrowserDialog::FileLoad, kCheatFileChosenCmd); break; case kChoosePaletteFileCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary createBrowser(); myBrowser->show("Select palette file", myPaletteFile->getText(), BrowserDialog::FileLoad, kPaletteFileChosenCmd); break; case kChoosePropsFileCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary createBrowser(); myBrowser->show("Select properties file", myPropsFile->getText(), BrowserDialog::FileLoad, kPropsFileChosenCmd); break; case kChooseNVRamDirCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary createBrowser(); myBrowser->show("Select NVRAM directory", myNVRamPath->getText(), BrowserDialog::Directories, kNVRamDirChosenCmd); break; case kChooseStateDirCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary createBrowser(); myBrowser->show("Select state directory", myStatePath->getText(), BrowserDialog::Directories, kStateDirChosenCmd); break; case LauncherDialog::kRomDirChosenCmd: myRomPath->setText(myBrowser->getResult().getShortPath()); break; case kCheatFileChosenCmd: myCheatFile->setText(myBrowser->getResult().getShortPath()); break; case kPaletteFileChosenCmd: myPaletteFile->setText(myBrowser->getResult().getShortPath()); break; case kPropsFileChosenCmd: myPropsFile->setText(myBrowser->getResult().getShortPath()); break; case kNVRamDirChosenCmd: myNVRamPath->setText(myBrowser->getResult().getShortPath()); break; case kStateDirChosenCmd: myStatePath->setText(myBrowser->getResult().getShortPath()); break; case LauncherDialog::kReloadRomDirCmd: sendCommand(LauncherDialog::kReloadRomDirCmd, 0, 0); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ConfigPathDialog::createBrowser() { uInt32 w = 0, h = 0; getResizableBounds(w, h); // Create file browser dialog if(!myBrowser || uInt32(myBrowser->getWidth()) != w || uInt32(myBrowser->getHeight()) != h) myBrowser = make_unique(this, myFont, w, h); } stella-5.1.1/src/gui/ConfigPathDialog.hxx000066400000000000000000000055341324334165500202650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CONFIG_PATH_DIALOG_HXX #define CONFIG_PATH_DIALOG_HXX class OSystem; class GuiObject; class DialogContainer; class BrowserDialog; class CheckboxWidget; class PopUpWidget; class EditTextWidget; class SliderWidget; class StaticTextWidget; #include "Dialog.hxx" #include "Command.hxx" class ConfigPathDialog : public Dialog, public CommandSender { public: ConfigPathDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, GuiObject* boss); virtual ~ConfigPathDialog(); private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void createBrowser(); void loadConfig() override; void saveConfig() override; void setDefaults() override; private: enum { kChooseRomDirCmd = 'LOrm', // rom select kChooseStateDirCmd = 'LOsd', // state dir kChooseCheatFileCmd = 'LOcf', // cheatfile (stella.cht) kChoosePaletteFileCmd = 'LOpf', // palette file (stella.pal) kChoosePropsFileCmd = 'LOpr', // properties file (stella.pro) kChooseNVRamDirCmd = 'LOnv', // nvram (flash/eeprom) dir kStateDirChosenCmd = 'LOsc', // state dir changed kCheatFileChosenCmd = 'LOcc', // cheatfile changed kPaletteFileChosenCmd = 'LOpc', // palette file changed kPropsFileChosenCmd = 'LOrc', // properties file changed kNVRamDirChosenCmd = 'LOnc' // nvram (flash/eeprom) dir changed }; const GUI::Font& myFont; // Config paths EditTextWidget* myRomPath; EditTextWidget* myStatePath; EditTextWidget* myNVRamPath; EditTextWidget* myCheatFile; EditTextWidget* myPaletteFile; EditTextWidget* myPropsFile; unique_ptr myBrowser; // Indicates if this dialog is used for global (vs. in-game) settings bool myIsGlobal; private: // Following constructors and assignment operators not supported ConfigPathDialog() = delete; ConfigPathDialog(const ConfigPathDialog&) = delete; ConfigPathDialog(ConfigPathDialog&&) = delete; ConfigPathDialog& operator=(const ConfigPathDialog&) = delete; ConfigPathDialog& operator=(ConfigPathDialog&&) = delete; }; #endif stella-5.1.1/src/gui/ConsoleBFont.hxx000066400000000000000000001137051324334165500174560ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Generated by src/tools/convbdf on Sat Aug 24 11:39:18 2013. //============================================================================ #ifndef CONSOLEB_FONT_DATA_HXX #define CONSOLEB_FONT_DATA_HXX #include "Font.hxx" /* Font information: name: 8x13B-ISO8859-1 facename: -Misc-Fixed-Bold-R-Normal--13-120-75-75-C-80-ISO8859-1 w x h: 8x13 bbx: 8 13 0 -2 size: 97 ascent: 11 descent: 2 first char: 30 (0x1e) last char: 126 (0x7e) default char: 30 (0x1e) proportional: no Public domain font. Share and enjoy. */ namespace GUI { // Font character bitmap data. static const uInt16 consoleB_font_bits[] = { /* MODIFIED Character 29 (0x1d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | | |XX XX XX| |XX XX XX| | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0b1101101100000000, 0b1101101100000000, 0x0000, 0x0000, /* MODIFIED Character 30 (0x1e): large centered rounded rectangle width 8 bbx ( 8, 13, 0, -2 ) +--------+ | **** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | **** | +--------+ */ 0x3c00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x3c00, /* MODIFIED Character 31 (0x1f): large centered circle width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | **** | | ****** | | ****** | | **** | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x7e00, 0x7e00, 0x3c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 32 (0x20): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 33 (0x21): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | ** | | ** | | | | | +--------+ */ 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x1800, 0x1800, 0x0000, 0x0000, /* Character 34 (0x22): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x6c00, 0x6c00, 0x6c00, 0x6c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 35 (0x23): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ** ** | | ** ** | |******* | |******* | | ** ** | |******* | |******* | | ** ** | | ** ** | | | | | +--------+ */ 0x0000, 0x0000, 0x6c00, 0x6c00, 0xfe00, 0xfe00, 0x6c00, 0xfe00, 0xfe00, 0x6c00, 0x6c00, 0x0000, 0x0000, /* Character 36 (0x24): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | * | | ***** | |** * ** | |** * | |**** | | ***** | | **** | | * ** | |** * ** | | ***** | | * | | | +--------+ */ 0x0000, 0x1000, 0x7c00, 0xd600, 0xd000, 0xf000, 0x7c00, 0x1e00, 0x1600, 0xd600, 0x7c00, 0x1000, 0x0000, /* Character 37 (0x25): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |*** ** | |* * ** | |*** ** | | ** | | ** | | ** | | ** | | ** *** | |** * * | |** *** | | | | | +--------+ */ 0x0000, 0xe600, 0xa600, 0xec00, 0x1800, 0x1800, 0x3000, 0x3000, 0x6e00, 0xca00, 0xce00, 0x0000, 0x0000, /* Character 38 (0x26): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | **** | |** ** | |** ** | | **** | |** *** | |** ** | | ****** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7800, 0xcc00, 0xcc00, 0x7800, 0xce00, 0xcc00, 0x7e00, 0x0000, 0x0000, /* Character 39 (0x27): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | ** | | ** | | ** | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 40 (0x28): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | +--------+ */ 0x0000, 0x0c00, 0x1800, 0x3000, 0x3000, 0x6000, 0x6000, 0x6000, 0x3000, 0x3000, 0x1800, 0x0c00, 0x0000, /* Character 41 (0x29): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | +--------+ */ 0x0000, 0x6000, 0x3000, 0x1800, 0x1800, 0x0c00, 0x0c00, 0x0c00, 0x1800, 0x1800, 0x3000, 0x6000, 0x0000, /* Character 42 (0x2a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | * | | * | |******* | | *** | | *** | | ** ** | | * * | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x1000, 0x1000, 0xfe00, 0x3800, 0x3800, 0x6c00, 0x4400, 0x0000, 0x0000, 0x0000, /* Character 43 (0x2b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | ** | | ** | | ****** | | ****** | | ** | | ** | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x7e00, 0x7e00, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 44 (0x2c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | **** | | *** | | *** | | ** | | ** | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x1c00, 0x1c00, 0x1800, 0x3000, 0x0000, /* Character 45 (0x2d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | ****** | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 46 (0x2e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | ** | | **** | | ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x3c00, 0x1800, 0x0000, 0x0000, /* Character 47 (0x2f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | * | | ** | | ** | | ** | | ** | | ** | | ** | |** | |** | |* | | | | | +--------+ */ 0x0000, 0x0200, 0x0600, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0xc000, 0xc000, 0x8000, 0x0000, 0x0000, /* Character 48 (0x30): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | *** | | ** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | ** ** | | *** | | | | | +--------+ */ 0x0000, 0x3800, 0x6c00, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0x6c00, 0x3800, 0x0000, 0x0000, /* Character 49 (0x31): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | *** | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | +--------+ */ 0x0000, 0x1800, 0x3800, 0x7800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x7e00, 0x0000, 0x0000, /* Character 50 (0x32): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |** ** | |** ** | | ** | | ** | | ** | | ** | | ** | |** | |******* | | | | | +--------+ */ 0x0000, 0x7c00, 0xc600, 0xc600, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0xc000, 0xfe00, 0x0000, 0x0000, /* Character 51 (0x33): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |******* | | ** | | ** | | ** | | **** | | ** | | ** | | ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0xfe00, 0x0600, 0x0c00, 0x1800, 0x3c00, 0x0600, 0x0600, 0x0600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 52 (0x34): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | *** | | **** | | ** ** | |** ** | |** ** | |******* | | ** | | ** | | ** | | | | | +--------+ */ 0x0000, 0x0c00, 0x1c00, 0x3c00, 0x6c00, 0xcc00, 0xcc00, 0xfe00, 0x0c00, 0x0c00, 0x0c00, 0x0000, 0x0000, /* Character 53 (0x35): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |******* | |** | |** | |****** | |*** ** | | ** | | ** | | ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0xfe00, 0xc000, 0xc000, 0xfc00, 0xe600, 0x0600, 0x0600, 0x0600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 54 (0x36): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | **** | | ** | |** | |** | |****** | |*** ** | |** ** | |** ** | |*** ** | | ***** | | | | | +--------+ */ 0x0000, 0x3c00, 0x6000, 0xc000, 0xc000, 0xfc00, 0xe600, 0xc600, 0xc600, 0xe600, 0x7c00, 0x0000, 0x0000, /* Character 55 (0x37): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |******* | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | +--------+ */ 0x0000, 0xfe00, 0x0600, 0x0600, 0x0c00, 0x1800, 0x1800, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, /* Character 56 (0x38): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |** ** | |** ** | |** ** | | ***** | |** ** | |** ** | |** ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0x7c00, 0xc600, 0xc600, 0xc600, 0x7c00, 0xc600, 0xc600, 0xc600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 57 (0x39): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |** *** | |** ** | |** ** | |** *** | | ****** | | ** | | ** | | ** | | **** | | | | | +--------+ */ 0x0000, 0x7c00, 0xce00, 0xc600, 0xc600, 0xce00, 0x7e00, 0x0600, 0x0600, 0x0c00, 0x7800, 0x0000, 0x0000, /* Character 58 (0x3a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | ** | | **** | | ** | | | | | | ** | | **** | | ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x1800, 0x3c00, 0x1800, 0x0000, 0x0000, 0x1800, 0x3c00, 0x1800, 0x0000, 0x0000, /* Character 59 (0x3b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | ** | | **** | | ** | | | | **** | | *** | | *** | | ** | | ** | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x1800, 0x3c00, 0x1800, 0x0000, 0x3c00, 0x1c00, 0x1c00, 0x1800, 0x3000, 0x0000, /* Character 60 (0x3c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0000, 0x0000, /* Character 61 (0x3d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | ****** | | | | | | ****** | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x0000, 0x0000, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 62 (0x3e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | +--------+ */ 0x0000, 0x0000, 0x6000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x0000, 0x0000, /* Character 63 (0x3f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |** ** | |** ** | | ** | | ** | | ** | | ** | | | | ** | | ** | | | | | +--------+ */ 0x0000, 0x7c00, 0xc600, 0xc600, 0x0600, 0x0c00, 0x1800, 0x1800, 0x0000, 0x1800, 0x1800, 0x0000, 0x0000, /* Character 64 (0x40): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ***** | |******* | |** *** | |** **** | |** * * | |** * * | |** **** | |*** | | ****** | | | | | +--------+ */ 0x0000, 0x0000, 0x7c00, 0xfe00, 0xce00, 0xde00, 0xd200, 0xd200, 0xde00, 0xe000, 0x7e00, 0x0000, 0x0000, /* Character 65 (0x41): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | *** | | ***** | |** ** | |** ** | |** ** | |******* | |** ** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0x3800, 0x7c00, 0xc600, 0xc600, 0xc600, 0xfe00, 0xc600, 0xc600, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 66 (0x42): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |****** | | ** ** | | ** ** | | ** ** | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | |****** | | | | | +--------+ */ 0x0000, 0xfc00, 0x6600, 0x6600, 0x6600, 0x7c00, 0x6600, 0x6600, 0x6600, 0x6600, 0xfc00, 0x0000, 0x0000, /* Character 67 (0x43): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |*** ** | |** ** | |** | |** | |** | |** | |** ** | |*** ** | | ***** | | | | | +--------+ */ 0x0000, 0x7c00, 0xe600, 0xc600, 0xc000, 0xc000, 0xc000, 0xc000, 0xc600, 0xe600, 0x7c00, 0x0000, 0x0000, /* Character 68 (0x44): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | |****** | | | | | +--------+ */ 0x0000, 0xfc00, 0x6600, 0x6600, 0x6600, 0x6600, 0x6600, 0x6600, 0x6600, 0x6600, 0xfc00, 0x0000, 0x0000, /* Character 69 (0x45): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |******* | |** | |** | |** | |***** | |** | |** | |** | |** | |******* | | | | | +--------+ */ 0x0000, 0xfe00, 0xc000, 0xc000, 0xc000, 0xf800, 0xc000, 0xc000, 0xc000, 0xc000, 0xfe00, 0x0000, 0x0000, /* Character 70 (0x46): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |******* | |** | |** | |** | |***** | |** | |** | |** | |** | |** | | | | | +--------+ */ 0x0000, 0xfe00, 0xc000, 0xc000, 0xc000, 0xf800, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0x0000, 0x0000, /* Character 71 (0x47): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |** ** | |** ** | |** | |** | |** | |** *** | |** ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0x7c00, 0xc600, 0xc600, 0xc000, 0xc000, 0xc000, 0xce00, 0xc600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 72 (0x48): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** ** | |** ** | |** ** | |** ** | |******* | |** ** | |** ** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0xc600, 0xc600, 0xc600, 0xc600, 0xfe00, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 73 (0x49): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | **** | | | | | +--------+ */ 0x0000, 0x3c00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x3c00, 0x0000, 0x0000, /* Character 74 (0x4a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | *** | | ** | | ** | | ** | | ** | | ** | | ** | |** ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0x0e00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0xc600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 75 (0x4b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** ** | |** ** | |** ** | |** ** | |**** | |**** | |** ** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0xc600, 0xc600, 0xcc00, 0xd800, 0xf000, 0xf000, 0xd800, 0xcc00, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 76 (0x4c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** | |** | |** | |** | |** | |** | |** | |** | |** * | |******* | | | | | +--------+ */ 0x0000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0xc200, 0xfe00, 0x0000, 0x0000, /* Character 77 (0x4d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** ** | |** ** | |*** *** | |******* | |** * ** | |** ** | |** ** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0xc600, 0xc600, 0xee00, 0xfe00, 0xd600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 78 (0x4e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** ** | |** ** | |*** ** | |*** ** | |**** ** | |** **** | |** *** | |** *** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0xc600, 0xc600, 0xe600, 0xe600, 0xf600, 0xde00, 0xce00, 0xce00, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 79 (0x4f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0x7c00, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 80 (0x50): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |****** | |** ** | |** ** | |** ** | |** ** | |****** | |** | |** | |** | |** | | | | | +--------+ */ 0x0000, 0xfc00, 0xc600, 0xc600, 0xc600, 0xc600, 0xfc00, 0xc000, 0xc000, 0xc000, 0xc000, 0x0000, 0x0000, /* Character 81 (0x51): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** **** | | ***** | | ** | | | +--------+ */ 0x0000, 0x7c00, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xde00, 0x7c00, 0x0600, 0x0000, /* Character 82 (0x52): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |****** | |** ** | |** ** | |** ** | |****** | |***** | |** ** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0xfc00, 0xc600, 0xc600, 0xc600, 0xfc00, 0xf800, 0xcc00, 0xcc00, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 83 (0x53): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | |** ** | |** ** | |** | | ***** | | ** | | ** | |** ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0x7c00, 0xc600, 0xc600, 0xc000, 0x7c00, 0x0600, 0x0600, 0xc600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 84 (0x54): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ****** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | +--------+ */ 0x0000, 0x7e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, /* Character 85 (0x55): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 86 (0x56): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** ** | |** ** | |** ** | |** ** | | * * | | ** ** | | ** ** | | *** | | *** | | * | | | | | +--------+ */ 0x0000, 0xc600, 0xc600, 0xc600, 0xc600, 0x4400, 0x6c00, 0x6c00, 0x3800, 0x3800, 0x1000, 0x0000, 0x0000, /* Character 87 (0x57): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** * ** | |** * ** | |******* | | ** ** | | | | | +--------+ */ 0x0000, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xd600, 0xd600, 0xfe00, 0x6c00, 0x0000, 0x0000, /* Character 88 (0x58): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** ** | |** ** | | ** ** | | ** ** | | *** | | *** | | ** ** | | ** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0xc600, 0xc600, 0x6c00, 0x6c00, 0x3800, 0x3800, 0x6c00, 0x6c00, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 89 (0x59): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** ** | | ** ** | | ** ** | | **** | | **** | | ** | | ** | | ** | | ** | | ** | | | | | +--------+ */ 0x0000, 0x6600, 0x6600, 0x6600, 0x3c00, 0x3c00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, /* Character 90 (0x5a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |******* | | ** | | ** | | ** | | ** | | ** | | ** | |** | |** | |******* | | | | | +--------+ */ 0x0000, 0xfe00, 0x0600, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0xc000, 0xc000, 0xfe00, 0x0000, 0x0000, /* Character 91 (0x5b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ***** | | | +--------+ */ 0x0000, 0x7c00, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7c00, 0x0000, /* Character 92 (0x5c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |* | |** | |** | | ** | | ** | | ** | | ** | | ** | | ** | | * | | | | | +--------+ */ 0x0000, 0x8000, 0xc000, 0xc000, 0x6000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0600, 0x0200, 0x0000, 0x0000, /* Character 93 (0x5d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ***** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ***** | | | +--------+ */ 0x0000, 0x7c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x7c00, 0x0000, /* Character 94 (0x5e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | * | | *** | | ** ** | |** ** | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x1000, 0x3800, 0x6c00, 0xc600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 95 (0x5f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | | | | | | |******* | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe00, 0x0000, /* Character 96 (0x60): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | ** | | ** | | | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x3000, 0x1800, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 97 (0x61): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | ***** | | ** | | ****** | |** ** | |** ** | |** *** | | *** ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0x0600, 0x7e00, 0xc600, 0xc600, 0xce00, 0x7600, 0x0000, 0x0000, /* Character 98 (0x62): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** | |** | |** | |** *** | |*** ** | |** ** | |** ** | |** ** | |*** ** | |** *** | | | | | +--------+ */ 0x0000, 0xc000, 0xc000, 0xc000, 0xdc00, 0xe600, 0xc600, 0xc600, 0xc600, 0xe600, 0xdc00, 0x0000, 0x0000, /* Character 99 (0x63): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | ***** | |*** ** | |** | |** | |** | |*** ** | | ***** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0xe600, 0xc000, 0xc000, 0xc000, 0xe600, 0x7c00, 0x0000, 0x0000, /* Character 100 (0x64): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | ** | | ** | | *** ** | |** *** | |** ** | |** ** | |** ** | |** *** | | *** ** | | | | | +--------+ */ 0x0000, 0x0600, 0x0600, 0x0600, 0x7600, 0xce00, 0xc600, 0xc600, 0xc600, 0xce00, 0x7600, 0x0000, 0x0000, /* Character 101 (0x65): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | ***** | |** ** | |** ** | |******* | |** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0xc600, 0xc600, 0xfe00, 0xc000, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 102 (0x66): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | **** | | ** ** | | ** | | ** | | ** | |****** | | ** | | ** | | ** | | ** | | | | | +--------+ */ 0x0000, 0x3c00, 0x6600, 0x6000, 0x6000, 0x6000, 0xfc00, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, /* Character 103 (0x67): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | ****** | |** ** | |** ** | |** ** | | **** | |**** | | ***** | |** ** | | ***** | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0xcc00, 0xcc00, 0xcc00, 0x7800, 0xf000, 0x7c00, 0xc600, 0x7c00, /* Character 104 (0x68): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** | |** | |** | |** *** | |*** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0xc000, 0xc000, 0xc000, 0xdc00, 0xe600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 105 (0x69): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ** | | ** | | | | *** | | ** | | ** | | ** | | ** | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x1800, 0x1800, 0x0000, 0x3800, 0x1800, 0x1800, 0x1800, 0x1800, 0x3c00, 0x0000, 0x0000, /* Character 106 (0x6a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ** | | ** | | | | *** | | ** | | ** | | ** | | ** | |** ** | |** ** | | ***** | +--------+ */ 0x0000, 0x0000, 0x0600, 0x0600, 0x0000, 0x0e00, 0x0600, 0x0600, 0x0600, 0x0600, 0xc600, 0xc600, 0x7c00, /* Character 107 (0x6b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | |** | |** | |** | |** ** | |** ** | |**** | |**** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0xc000, 0xc000, 0xc000, 0xcc00, 0xd800, 0xf000, 0xf000, 0xd800, 0xcc00, 0xc600, 0x0000, 0x0000, /* Character 108 (0x6c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | *** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | **** | | | | | +--------+ */ 0x0000, 0x3800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x3c00, 0x0000, 0x0000, /* Character 109 (0x6d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | ** ** | |******* | |** * ** | |** * ** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6c00, 0xfe00, 0xd600, 0xd600, 0xc600, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 110 (0x6e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |** *** | |*** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xdc00, 0xe600, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 111 (0x6f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | ***** | |** ** | |** ** | |** ** | |** ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 112 (0x70): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |** *** | |*** ** | |** ** | |** ** | |** ** | |*** ** | |** *** | |** | |** | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xdc00, 0xe600, 0xc600, 0xc600, 0xc600, 0xe600, 0xdc00, 0xc000, 0xc000, /* Character 113 (0x71): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | *** ** | |** *** | |** ** | |** ** | |** ** | |** *** | | *** ** | | ** | | ** | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7600, 0xce00, 0xc600, 0xc600, 0xc600, 0xce00, 0x7600, 0x0600, 0x0600, /* Character 114 (0x72): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |** *** | |*** ** | |** | |** | |** | |** | |** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xdc00, 0xe600, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0x0000, 0x0000, /* Character 115 (0x73): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | ***** | |** ** | | ** | | *** | | ** | |** ** | | ***** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0xc600, 0x6000, 0x3800, 0x0c00, 0xc600, 0x7c00, 0x0000, 0x0000, /* Character 116 (0x74): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | ** | | ** | | ** | |****** | | ** | | ** | | ** | | ** ** | | **** | | | | | +--------+ */ 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0xfc00, 0x6000, 0x6000, 0x6000, 0x6600, 0x3c00, 0x0000, 0x0000, /* Character 117 (0x75): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |** ** | |** ** | |** ** | |** ** | |** ** | |** *** | | *** ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xc600, 0xc600, 0xc600, 0xc600, 0xc600, 0xce00, 0x7600, 0x0000, 0x0000, /* Character 118 (0x76): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |** ** | |** ** | |** ** | |** ** | | ** ** | | ** ** | | *** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xc600, 0xc600, 0xc600, 0xc600, 0x6c00, 0x6c00, 0x3800, 0x0000, 0x0000, /* Character 119 (0x77): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |** ** | |** ** | |** ** | |** * ** | |** * ** | |******* | | ** ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xc600, 0xc600, 0xc600, 0xd600, 0xd600, 0xfe00, 0x6c00, 0x0000, 0x0000, /* Character 120 (0x78): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |** ** | |** ** | | ** ** | | *** | | ** ** | |** ** | |** ** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xc600, 0xc600, 0x6c00, 0x3800, 0x6c00, 0xc600, 0xc600, 0x0000, 0x0000, /* Character 121 (0x79): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |** ** | |** ** | |** ** | |** ** | |** *** | | *** ** | | ** | |** ** | | ***** | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xc600, 0xc600, 0xc600, 0xc600, 0xce00, 0x7600, 0x0600, 0xc600, 0x7c00, /* Character 122 (0x7a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | |******* | | ** | | ** | | ** | | ** | |** | |******* | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xfe00, 0x0c00, 0x1800, 0x3000, 0x6000, 0xc000, 0xfe00, 0x0000, 0x0000, /* Character 123 (0x7b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | **** | | ** | | ** | | ** | | ** | | *** | | ** | | ** | | ** | | ** | | **** | | | +--------+ */ 0x0000, 0x1e00, 0x3000, 0x3000, 0x3000, 0x1800, 0x7000, 0x1800, 0x3000, 0x3000, 0x3000, 0x1e00, 0x0000, /* Character 124 (0x7c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | +--------+ */ 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, /* Character 125 (0x7d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | **** | | ** | | ** | | ** | | ** | | *** | | ** | | ** | | ** | | ** | | **** | | | +--------+ */ 0x0000, 0x7800, 0x0c00, 0x0c00, 0x0c00, 0x1800, 0x0e00, 0x1800, 0x0c00, 0x0c00, 0x0c00, 0x7800, 0x0000, /* Character 126 (0x7e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | *** * | |******* | |* *** | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x7200, 0xfe00, 0x9c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; /* Exported structure definition. */ static const FontDesc consoleBDesc = { "8x13B-ISO8859-1", 8, 13, 8, 13, 0, -2, 11, 29, 98, consoleB_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ nullptr, /* fixed bbox*/ 32, // Originally 30 sizeof(consoleB_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-5.1.1/src/gui/ConsoleFont.hxx000066400000000000000000001136621324334165500173560ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Generated by src/tools/convbdf on Wed Jul 31 12:04:17 2013. //============================================================================ #ifndef CONSOLE_FONT_DATA_HXX #define CONSOLE_FONT_DATA_HXX #include "Font.hxx" /* Font information: name: 8x13-ISO8859-1 facename: -Misc-Fixed-Medium-R-Normal--13-120-75-75-C-80-ISO8859-1 w x h: 8x13 bbx: 8 13 0 -2 size: 97 ascent: 11 descent: 2 first char: 30 (0x1e) last char: 126 (0x7e) default char: 30 (0x1e) proportional: no Public domain font. Share and enjoy. */ namespace GUI { // Font character bitmap data. static const uInt16 console_font_bits[] = { /* MODIFIED Character 29 (0x1d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | | | | |XX XX XX| | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0b1101101100000000, 0x0000, 0x0000, /* MODIFIED Character 30 (0x1e): large centered rounded rectangle width 8 bbx ( 8, 13, 0, -2 ) +--------+ | **** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | ****** | | **** | +--------+ */ 0x3c00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x7e00, 0x3c00, /* MODIFIED Character 31 (0x1f): large centered circle width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | **** | | ****** | | ****** | | **** | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x7e00, 0x7e00, 0x3c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 32 (0x20): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 33 (0x21): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * | | * | | * | | * | | | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x0000, 0x0000, /* Character 34 (0x22): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * * | | * * | | * * | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x2400, 0x2400, 0x2400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 35 (0x23): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | * * | | * * | | ****** | | * * | | ****** | | * * | | * * | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x2400, 0x2400, 0x7e00, 0x2400, 0x7e00, 0x2400, 0x2400, 0x0000, 0x0000, 0x0000, /* Character 36 (0x24): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | **** | | * * | | * * | | *** | | * * | | * * | | **** | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x1000, 0x3c00, 0x5000, 0x5000, 0x3800, 0x1400, 0x1400, 0x7800, 0x1000, 0x0000, 0x0000, /* Character 37 (0x25): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * * | | * * * | | * * | | * | | * | | * | | * * | | * * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x2200, 0x5200, 0x2400, 0x0800, 0x0800, 0x1000, 0x2400, 0x2a00, 0x4400, 0x0000, 0x0000, /* Character 38 (0x26): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | ** | | * * | | * * | | ** | | * * * | | * * | | *** * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x3000, 0x4800, 0x4800, 0x3000, 0x4a00, 0x4400, 0x3a00, 0x0000, 0x0000, /* Character 39 (0x27): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 40 (0x28): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x0400, 0x0800, 0x0800, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0400, 0x0000, 0x0000, /* Character 41 (0x29): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x2000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0800, 0x1000, 0x1000, 0x2000, 0x0000, 0x0000, /* Character 42 (0x2a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | * * | | ** | | ****** | | ** | | * * | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x2400, 0x1800, 0x7e00, 0x1800, 0x2400, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 43 (0x2b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | * | | * | | ***** | | * | | * | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x1000, 0x7c00, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 44 (0x2c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | | | *** | | ** | | * | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3800, 0x3000, 0x4000, 0x0000, /* Character 45 (0x2d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | ***** | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 46 (0x2e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | | | * | | *** | | * | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x3800, 0x1000, 0x0000, /* Character 47 (0x2f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * | | * | | * | | * | |* | |* | | | | | +--------+ */ 0x0000, 0x0000, 0x0200, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x8000, 0x0000, 0x0000, /* Character 48 (0x30): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ** | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | ** | | | | | +--------+ */ 0x0000, 0x0000, 0x1800, 0x2400, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x2400, 0x1800, 0x0000, 0x0000, /* Character 49 (0x31): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | ** | | * * | | * | | * | | * | | * | | * | | ***** | | | | | +--------+ */ 0x0000, 0x0000, 0x1000, 0x3000, 0x5000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x7c00, 0x0000, 0x0000, /* Character 50 (0x32): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * | | * | | ** | | * | | * | | ****** | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4200, 0x0200, 0x0400, 0x1800, 0x2000, 0x4000, 0x7e00, 0x0000, 0x0000, /* Character 51 (0x33): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ****** | | * | | * | | * | | *** | | * | | * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x7e00, 0x0200, 0x0400, 0x0800, 0x1c00, 0x0200, 0x0200, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 52 (0x34): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | ** | | * * | | * * | | * * | | * * | | ****** | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x0400, 0x0c00, 0x1400, 0x2400, 0x4400, 0x4400, 0x7e00, 0x0400, 0x0400, 0x0000, 0x0000, /* Character 53 (0x35): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ****** | | * | | * | | * *** | | ** * | | * | | * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x7e00, 0x4000, 0x4000, 0x5c00, 0x6200, 0x0200, 0x0200, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 54 (0x36): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | *** | | * | | * | | * | | * *** | | ** * | | * * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x1c00, 0x2000, 0x4000, 0x4000, 0x5c00, 0x6200, 0x4200, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 55 (0x37): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ****** | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x7e00, 0x0200, 0x0400, 0x0800, 0x0800, 0x1000, 0x1000, 0x2000, 0x2000, 0x0000, 0x0000, /* Character 56 (0x38): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * * | | **** | | * * | | * * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4200, 0x4200, 0x3c00, 0x4200, 0x4200, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 57 (0x39): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * ** | | *** * | | * | | * | | * | | *** | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4200, 0x4600, 0x3a00, 0x0200, 0x0200, 0x0400, 0x3800, 0x0000, 0x0000, /* Character 58 (0x3a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | * | | *** | | * | | | | | | * | | *** | | * | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x3800, 0x1000, 0x0000, 0x0000, 0x1000, 0x3800, 0x1000, 0x0000, /* Character 59 (0x3b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | * | | *** | | * | | | | | | *** | | ** | | * | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x3800, 0x1000, 0x0000, 0x0000, 0x3800, 0x3000, 0x4000, 0x0000, /* Character 60 (0x3c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0000, 0x0000, /* Character 61 (0x3d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | ****** | | | | | | ****** | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x0000, 0x0000, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 62 (0x3e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x0000, 0x0000, /* Character 63 (0x3f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * | | * | | * | | * | | | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4200, 0x0200, 0x0400, 0x0800, 0x0800, 0x0000, 0x0800, 0x0000, 0x0000, /* Character 64 (0x40): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * *** | | * * * | | * * ** | | * * * | | * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4200, 0x4e00, 0x5200, 0x5600, 0x4a00, 0x4000, 0x3c00, 0x0000, 0x0000, /* Character 65 (0x41): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ** | | * * | | * * | | * * | | * * | | ****** | | * * | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x1800, 0x2400, 0x4200, 0x4200, 0x4200, 0x7e00, 0x4200, 0x4200, 0x4200, 0x0000, 0x0000, /* Character 66 (0x42): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * * | | **** | | * * | | * * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x7800, 0x4400, 0x4200, 0x4400, 0x7800, 0x4400, 0x4200, 0x4400, 0x7800, 0x0000, 0x0000, /* Character 67 (0x43): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * | | * | | * | | * | | * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 68 (0x44): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x7800, 0x4400, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x4400, 0x7800, 0x0000, 0x0000, /* Character 69 (0x45): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ****** | | * | | * | | * | | **** | | * | | * | | * | | ****** | | | | | +--------+ */ 0x0000, 0x0000, 0x7e00, 0x4000, 0x4000, 0x4000, 0x7800, 0x4000, 0x4000, 0x4000, 0x7e00, 0x0000, 0x0000, /* Character 70 (0x46): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ****** | | * | | * | | * | | **** | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x7e00, 0x4000, 0x4000, 0x4000, 0x7800, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, /* Character 71 (0x47): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * | | * | | * | | * *** | | * * | | * ** | | *** * | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4000, 0x4000, 0x4000, 0x4e00, 0x4200, 0x4600, 0x3a00, 0x0000, 0x0000, /* Character 72 (0x48): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * * | | * * | | * * | | * * | | ****** | | * * | | * * | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x4200, 0x4200, 0x4200, 0x4200, 0x7e00, 0x4200, 0x4200, 0x4200, 0x4200, 0x0000, 0x0000, /* Character 73 (0x49): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ***** | | * | | * | | * | | * | | * | | * | | * | | ***** | | | | | +--------+ */ 0x0000, 0x0000, 0x7c00, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x7c00, 0x0000, 0x0000, /* Character 74 (0x4a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | *****| | * | | * | | * | | * | | * | | * | | * * | | *** | | | | | +--------+ */ 0x0000, 0x0000, 0x1f00, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x4400, 0x3800, 0x0000, 0x0000, /* Character 75 (0x4b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * * | | * * | | * * | | * * | | ** | | * * | | * * | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x4200, 0x4400, 0x4800, 0x5000, 0x6000, 0x5000, 0x4800, 0x4400, 0x4200, 0x0000, 0x0000, /* Character 76 (0x4c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | ****** | | | | | +--------+ */ 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x7e00, 0x0000, 0x0000, /* Character 77 (0x4d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | |* * | |* * | |** ** | |* * * * | |* * * | |* * * | |* * | |* * | |* * | | | | | +--------+ */ 0x0000, 0x0000, 0x8200, 0x8200, 0xc600, 0xaa00, 0x9200, 0x9200, 0x8200, 0x8200, 0x8200, 0x0000, 0x0000, /* Character 78 (0x4e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * * | | * * | | ** * | | * * * | | * * * | | * ** | | * * | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x4200, 0x4200, 0x6200, 0x5200, 0x4a00, 0x4600, 0x4200, 0x4200, 0x4200, 0x0000, 0x0000, /* Character 79 (0x4f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 80 (0x50): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ***** | | * * | | * * | | * * | | ***** | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x7c00, 0x4200, 0x4200, 0x4200, 0x7c00, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, /* Character 81 (0x51): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * * | | * * | | * * | | * * | | * * * | | * * * | | **** | | * | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x5200, 0x4a00, 0x3c00, 0x0200, 0x0000, /* Character 82 (0x52): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ***** | | * * | | * * | | * * | | ***** | | * * | | * * | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x7c00, 0x4200, 0x4200, 0x4200, 0x7c00, 0x5000, 0x4800, 0x4400, 0x4200, 0x0000, 0x0000, /* Character 83 (0x53): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * * | | * | | * | | **** | | * | | * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x4200, 0x4000, 0x4000, 0x3c00, 0x0200, 0x0200, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 84 (0x54): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | |******* | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0xfe00, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, /* Character 85 (0x55): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 86 (0x56): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | |* * | |* * | | * * | | * * | | * * | | * * | | * * | | * * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x8200, 0x8200, 0x4400, 0x4400, 0x4400, 0x2800, 0x2800, 0x2800, 0x1000, 0x0000, 0x0000, /* Character 87 (0x57): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | |* * | |* * | |* * | |* * | |* * * | |* * * | |* * * | |* * * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x8200, 0x8200, 0x8200, 0x8200, 0x9200, 0x9200, 0x9200, 0xaa00, 0x4400, 0x0000, 0x0000, /* Character 88 (0x58): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | |* * | |* * | | * * | | * * | | * | | * * | | * * | |* * | |* * | | | | | +--------+ */ 0x0000, 0x0000, 0x8200, 0x8200, 0x4400, 0x2800, 0x1000, 0x2800, 0x4400, 0x8200, 0x8200, 0x0000, 0x0000, /* Character 89 (0x59): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | |* * | |* * | | * * | | * * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x8200, 0x8200, 0x4400, 0x2800, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, /* Character 90 (0x5a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ****** | | * | | * | | * | | * | | * | | * | | * | | ****** | | | | | +--------+ */ 0x0000, 0x0000, 0x7e00, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x4000, 0x7e00, 0x0000, 0x0000, /* Character 91 (0x5b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * | | * | | * | | * | | * | | * | | * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x3c00, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x3c00, 0x0000, 0x0000, /* Character 92 (0x5c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | |* | |* | | * | | * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x8000, 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0200, 0x0000, 0x0000, /* Character 93 (0x5d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | **** | | * | | * | | * | | * | | * | | * | | * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x7800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x7800, 0x0000, 0x0000, /* Character 94 (0x5e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * * | | * * | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x1000, 0x2800, 0x4400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 95 (0x5f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | | | | | | | | | | | | |******* | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe00, 0x0000, /* Character 96 (0x60): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | * | | * | | | | | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x1000, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 97 (0x61): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | **** | | * | | ***** | | * * | | * ** | | *** * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x0200, 0x3e00, 0x4200, 0x4600, 0x3a00, 0x0000, 0x0000, /* Character 98 (0x62): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * *** | | ** * | | * * | | * * | | ** * | | * *** | | | | | +--------+ */ 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x5c00, 0x6200, 0x4200, 0x4200, 0x6200, 0x5c00, 0x0000, 0x0000, /* Character 99 (0x63): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | **** | | * * | | * | | * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x4200, 0x4000, 0x4000, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 100 (0x64): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | *** * | | * ** | | * * | | * * | | * ** | | *** * | | | | | +--------+ */ 0x0000, 0x0000, 0x0200, 0x0200, 0x0200, 0x3a00, 0x4600, 0x4200, 0x4200, 0x4600, 0x3a00, 0x0000, 0x0000, /* Character 101 (0x65): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | **** | | * * | | ****** | | * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x4200, 0x7e00, 0x4000, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 102 (0x66): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | *** | | * * | | * | | * | | ***** | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x1c00, 0x2200, 0x2000, 0x2000, 0x7c00, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, /* Character 103 (0x67): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | *** * | | * * | | * * | | *** | | * | | **** | | * * | | **** | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3a00, 0x4400, 0x4400, 0x3800, 0x4000, 0x3c00, 0x4200, 0x3c00, /* Character 104 (0x68): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * *** | | ** * | | * * | | * * | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x5c00, 0x6200, 0x4200, 0x4200, 0x4200, 0x4200, 0x0000, 0x0000, /* Character 105 (0x69): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | * | | | | ** | | * | | * | | * | | * | | ***** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x3000, 0x1000, 0x1000, 0x1000, 0x1000, 0x7c00, 0x0000, 0x0000, /* Character 106 (0x6a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | * | | | | ** | | * | | * | | * | | * | | * * | | * * | | *** | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0400, 0x0000, 0x0c00, 0x0400, 0x0400, 0x0400, 0x0400, 0x4400, 0x4400, 0x3800, /* Character 107 (0x6b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * * | | * * | | *** | | * * | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x4400, 0x4800, 0x7000, 0x4800, 0x4400, 0x4200, 0x0000, 0x0000, /* Character 108 (0x6c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | ** | | * | | * | | * | | * | | * | | * | | * | | ***** | | | | | +--------+ */ 0x0000, 0x0000, 0x3000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x7c00, 0x0000, 0x0000, /* Character 109 (0x6d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | |*** ** | |* * * | |* * * | |* * * | |* * * | |* * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xec00, 0x9200, 0x9200, 0x9200, 0x9200, 0x8200, 0x0000, 0x0000, /* Character 110 (0x6e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | * *** | | ** * | | * * | | * * | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5c00, 0x6200, 0x4200, 0x4200, 0x4200, 0x4200, 0x0000, 0x0000, /* Character 111 (0x6f): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | **** | | * * | | * * | | * * | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x4200, 0x4200, 0x4200, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 112 (0x70): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | * *** | | ** * | | * * | | ** * | | * *** | | * | | * | | * | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5c00, 0x6200, 0x4200, 0x6200, 0x5c00, 0x4000, 0x4000, 0x4000, /* Character 113 (0x71): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | *** * | | * ** | | * * | | * ** | | *** * | | * | | * | | * | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3a00, 0x4600, 0x4200, 0x4600, 0x3a00, 0x0200, 0x0200, 0x0200, /* Character 114 (0x72): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | * *** | | * * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5c00, 0x2200, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, /* Character 115 (0x73): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | **** | | * * | | ** | | ** | | * * | | **** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x4200, 0x3000, 0x0c00, 0x4200, 0x3c00, 0x0000, 0x0000, /* Character 116 (0x74): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | * | | * | | ***** | | * | | * | | * | | * * | | *** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x2000, 0x2000, 0x7c00, 0x2000, 0x2000, 0x2000, 0x2200, 0x1c00, 0x0000, 0x0000, /* Character 117 (0x75): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | * * | | * * | | * * | | * * | | * * | | *** * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4400, 0x4400, 0x4400, 0x4400, 0x4400, 0x3a00, 0x0000, 0x0000, /* Character 118 (0x76): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | * * | | * * | | * * | | * * | | * * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4400, 0x4400, 0x4400, 0x2800, 0x2800, 0x1000, 0x0000, 0x0000, /* Character 119 (0x77): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | |* * | |* * | |* * * | |* * * | |* * * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8200, 0x8200, 0x9200, 0x9200, 0xaa00, 0x4400, 0x0000, 0x0000, /* Character 120 (0x78): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | * * | | * * | | ** | | ** | | * * | | * * | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4200, 0x2400, 0x1800, 0x1800, 0x2400, 0x4200, 0x0000, 0x0000, /* Character 121 (0x79): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | * * | | * * | | * * | | * ** | | *** * | | * | | * * | | **** | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4200, 0x4200, 0x4200, 0x4600, 0x3a00, 0x0200, 0x4200, 0x3c00, /* Character 122 (0x7a): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | | | | | | | ****** | | * | | * | | * | | * | | ****** | | | | | +--------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x0400, 0x0800, 0x1000, 0x2000, 0x7e00, 0x0000, 0x0000, /* Character 123 (0x7b): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | *** | | * | | * | | * | | ** | | * | | * | | * | | *** | | | | | +--------+ */ 0x0000, 0x0000, 0x0e00, 0x1000, 0x1000, 0x0800, 0x3000, 0x0800, 0x1000, 0x1000, 0x0e00, 0x0000, 0x0000, /* Character 124 (0x7c): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +--------+ */ 0x0000, 0x0000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, /* Character 125 (0x7d): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | *** | | * | | * | | * | | ** | | * | | * | | * | | *** | | | | | +--------+ */ 0x0000, 0x0000, 0x7000, 0x0800, 0x0800, 0x1000, 0x0c00, 0x1000, 0x0800, 0x0800, 0x7000, 0x0000, 0x0000, /* Character 126 (0x7e): width 8 bbx ( 8, 13, 0, -2 ) +--------+ | | | | | * * | | * * * | | * * | | | | | | | | | | | | | | | | | +--------+ */ 0x0000, 0x0000, 0x2400, 0x5400, 0x4800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; /* Exported structure definition. */ static const FontDesc consoleDesc = { "8x13-ISO8859-1", 8, 13, 8, 13, 0, -2, 11, 29, 98, console_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ nullptr, /* fixed bbox*/ 32, // Originally 30 sizeof(console_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-5.1.1/src/gui/ConsoleMediumBFont.hxx000066400000000000000000001275151324334165500206230ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Generated by src/tools/convbdf on Sat Aug 24 11:44:34 2013. //============================================================================ #ifndef CONSOLEMEDIUMB_FONT_DATA_HXX #define CONSOLEMEDIUMB_FONT_DATA_HXX #include "Font.hxx" /* Font information: name: 9x15B-ISO8859-1 facename: -Misc-Fixed-Bold-R-Normal--15-140-75-75-C-90-ISO8859-1 w x h: 9x15 bbx: 9 15 0 -3 size: 97 ascent: 12 descent: 3 first char: 30 (0x1e) last char: 126 (0x7e) default char: 30 (0x1e) proportional: no Public domain font. Share and enjoy. */ namespace GUI { // Font character bitmap data. static const uInt16 consoleMediumB_font_bits[] = { /* MODIFIED Character 29 (0x1d): ellipsis width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | XX XX XX| | XX XX XX| | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0b0110110110000000, 0b0110110110000000, 0x0000, 0x0000, 0x0000, /* MODIFIED Character 30 (0x1e): large centered rounded rectangle width 9 bbx ( 9, 15, 0, -3 ) +---------+ | ***** | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ***** | +---------+ */ 0x3e00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x3e00, /* MODIFIED Character 31 (0x1f): large centered circle width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | *** | | ***** | | ******* | | ***** | | *** | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3e00, 0x7f00, 0x3e00, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 32 (0x20): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 33 (0x21): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 34 (0x22): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** ** | | ** ** | | ** ** | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3600, 0x3600, 0x3600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 35 (0x23): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | ** ** | | ** ** | | ******* | | ** ** | | ** ** | | ******* | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x3600, 0x3600, 0x7f00, 0x3600, 0x3600, 0x7f00, 0x3600, 0x3600, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 36 (0x24): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | ***** | | ** * ** | | ** * | | **** | | ***** | | **** | | * ** | | ** * ** | | ***** | | * | | | | | +---------+ */ 0x0000, 0x0000, 0x0800, 0x3e00, 0x6b00, 0x6800, 0x7800, 0x3e00, 0x0f00, 0x0b00, 0x6b00, 0x3e00, 0x0800, 0x0000, 0x0000, /* Character 37 (0x25): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * ** | |*** ** | |*** ** | | * ** | | ** | | ** | | ** * | | ** *** | | ** *** | |** * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4300, 0xe600, 0xe600, 0x4c00, 0x1800, 0x1800, 0x3200, 0x6700, 0x6700, 0xc200, 0x0000, 0x0000, 0x0000, /* Character 38 (0x26): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | *** | | ** ** | | ** ** | | **** | | ** | | **** * | |** **** | |** ** | |** *** | | **** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3800, 0x6c00, 0x6c00, 0x7800, 0x3000, 0x7900, 0xcf00, 0xc600, 0xce00, 0x7b00, 0x0000, 0x0000, 0x0000, /* Character 39 (0x27): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | ** | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 40 (0x28): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | +---------+ */ 0x0000, 0x0600, 0x0c00, 0x1800, 0x1800, 0x3000, 0x3000, 0x3000, 0x3000, 0x1800, 0x1800, 0x0c00, 0x0600, 0x0000, 0x0000, /* Character 41 (0x29): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | +---------+ */ 0x0000, 0x3000, 0x1800, 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0c00, 0x0c00, 0x1800, 0x3000, 0x0000, 0x0000, /* Character 42 (0x2a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ** ** | | *** | | ******* | | *** | | ** ** | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3600, 0x1c00, 0x7f00, 0x1c00, 0x3600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 43 (0x2b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | ** | | ** | | ** | |******** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0xff00, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 44 (0x2c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | *** | | *** | | ** | | ** | | ** | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x1c00, 0x0c00, 0x0c00, 0x1800, /* Character 45 (0x2d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | |******** | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 46 (0x2e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | ** | | **** | | ** | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x3c00, 0x1800, 0x0000, 0x0000, /* Character 47 (0x2f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | |** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0300, 0x0600, 0x0600, 0x0c00, 0x1800, 0x1800, 0x3000, 0x6000, 0x6000, 0xc000, 0x0000, 0x0000, 0x0000, /* Character 48 (0x30): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | **** | | ** ** | |** ** | |** ** | |** ** | |** ** | | ** ** | | **** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x3c00, 0x6600, 0xc300, 0xc300, 0xc300, 0xc300, 0x6600, 0x3c00, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 49 (0x31): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | *** | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x3800, 0x7800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x7e00, 0x0000, 0x0000, 0x0000, /* Character 50 (0x32): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** ** | |** ** | | ** | | ** | | ** | | ** | | ** | | ** | |******** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3c00, 0x6600, 0xc300, 0x0300, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0xff00, 0x0000, 0x0000, 0x0000, /* Character 51 (0x33): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | |** ** | | ** | | ** | | *** | | ** | | ** | | ** | |** ** | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7c00, 0xc600, 0x0300, 0x0600, 0x1c00, 0x0600, 0x0300, 0x0300, 0xc600, 0x7c00, 0x0000, 0x0000, 0x0000, /* Character 52 (0x34): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | *** | | **** | | ** ** | | ** ** | |** ** | |******** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0600, 0x0e00, 0x1e00, 0x3600, 0x6600, 0xc600, 0xff00, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, /* Character 53 (0x35): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |******* | |** | |** | |** *** | |*** ** | | ** | | ** | |** ** | | ** ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xfe00, 0xc000, 0xc000, 0xdc00, 0xe600, 0x0300, 0x0300, 0xc300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 54 (0x36): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** ** | |** * | |** | |** *** | |*** ** | |** ** | |** ** | | ** ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3c00, 0x6600, 0xc200, 0xc000, 0xdc00, 0xe600, 0xc300, 0xc300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 55 (0x37): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |******** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xff00, 0x0300, 0x0300, 0x0600, 0x0c00, 0x0c00, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 56 (0x38): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** ** | |** ** | | ** ** | | **** | | ** ** | |** ** | |** ** | | ** ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3c00, 0x6600, 0xc300, 0x6600, 0x3c00, 0x6600, 0xc300, 0xc300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 57 (0x39): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** ** | |** ** | |** ** | | ** *** | | *** ** | | ** | | * ** | | ** ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3c00, 0x6600, 0xc300, 0xc300, 0x6700, 0x3b00, 0x0300, 0x4300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 58 (0x3a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ** | | **** | | ** | | | | | | ** | | **** | | ** | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x3c00, 0x1800, 0x0000, 0x0000, 0x1800, 0x3c00, 0x1800, 0x0000, 0x0000, /* Character 59 (0x3b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ** | | **** | | ** | | | | | | *** | | *** | | ** | | ** | | ** | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x3c00, 0x1800, 0x0000, 0x0000, 0x1c00, 0x1c00, 0x0c00, 0x0c00, 0x1800, /* Character 60 (0x3c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x6000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0000, 0x0000, 0x0000, /* Character 61 (0x3d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | |******** | | | | | |******** | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0x0000, 0xff00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 62 (0x3e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x6000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x0000, 0x0000, 0x0000, /* Character 63 (0x3f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | ** ** | | ** ** | | ** | | ** | | ** | | ** | | | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x6300, 0x6300, 0x0300, 0x0600, 0x0c00, 0x1800, 0x0000, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 64 (0x40): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** ** | |** ** | |** **** | |** ** ** | |** ** ** | |** *** | |** | | ** ** | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3c00, 0x6600, 0xc300, 0xcf00, 0xdb00, 0xdb00, 0xce00, 0xc000, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 65 (0x41): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | **** | | ** ** | |** ** | |** ** | |** ** | |******** | |** ** | |** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x3c00, 0x6600, 0xc300, 0xc300, 0xc300, 0xff00, 0xc300, 0xc300, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 66 (0x42): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |****** | |** ** | |** ** | |** ** | |****** | |** ** | |** ** | |** ** | |** ** | |****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xfc00, 0xc600, 0xc300, 0xc600, 0xfc00, 0xc600, 0xc300, 0xc300, 0xc600, 0xfc00, 0x0000, 0x0000, 0x0000, /* Character 67 (0x43): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | ** ** | |** * | |** | |** | |** | |** | |** * | | ** ** | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x6300, 0xc100, 0xc000, 0xc000, 0xc000, 0xc000, 0xc100, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 68 (0x44): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |****** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xfc00, 0xc600, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0xc600, 0xfc00, 0x0000, 0x0000, 0x0000, /* Character 69 (0x45): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | ** | | ** | | ** | | ****** | | ** | | ** | | ** | | ** | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x6000, 0x6000, 0x6000, 0x7e00, 0x6000, 0x6000, 0x6000, 0x6000, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 70 (0x46): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |******** | |** | |** | |** | |****** | |** | |** | |** | |** | |** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xff00, 0xc000, 0xc000, 0xc000, 0xfc00, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0x0000, 0x0000, 0x0000, /* Character 71 (0x47): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | ** ** | |** | |** | |** | |** *** | |** ** | |** ** | | ** ** | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x6300, 0xc000, 0xc000, 0xc000, 0xc700, 0xc300, 0xc300, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 72 (0x48): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |** ** | |** ** | |** ** | |******** | |** ** | |** ** | |** ** | |** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xc300, 0xc300, 0xc300, 0xff00, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 73 (0x49): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ****** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x7e00, 0x0000, 0x0000, 0x0000, /* Character 74 (0x4a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | * ** | | ** ** | | *** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1e00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x4600, 0x6c00, 0x3800, 0x0000, 0x0000, 0x0000, /* Character 75 (0x4b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |** ** | |** ** | |** ** | |**** | |**** | |** ** | |** ** | |** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xc600, 0xcc00, 0xd800, 0xf000, 0xf000, 0xd800, 0xcc00, 0xc600, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 76 (0x4c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 77 (0x4d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |*** *** | |******** | |** ** ** | |** ** ** | |** ** ** | |** ** | |** ** | |** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xe700, 0xff00, 0xdb00, 0xdb00, 0xdb00, 0xc300, 0xc300, 0xc300, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 78 (0x4e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |*** ** | |**** ** | |**** ** | |** ** ** | |** ** ** | |** **** | |** *** | |** *** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xe300, 0xf300, 0xf300, 0xdb00, 0xdb00, 0xcf00, 0xc700, 0xc700, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 79 (0x4f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | ** ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3c00, 0x6600, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 80 (0x50): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |******* | |** ** | |** ** | |** ** | |******* | |** | |** | |** | |** | |** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xfe00, 0xc300, 0xc300, 0xc300, 0xfe00, 0xc000, 0xc000, 0xc000, 0xc000, 0xc000, 0x0000, 0x0000, 0x0000, /* Character 81 (0x51): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** ** | |** ** | |** ** | |** ** | |** ** | |** ** ** | |** **** | | ** ** | | **** * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3c00, 0x6600, 0xc300, 0xc300, 0xc300, 0xc300, 0xdb00, 0xcf00, 0x6600, 0x3d00, 0x0000, 0x0000, 0x0000, /* Character 82 (0x52): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |******* | |** ** | |** ** | |** ** | |******* | |***** | |** ** | |** ** | |** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xfe00, 0xc300, 0xc300, 0xc300, 0xfe00, 0xf800, 0xcc00, 0xc600, 0xc300, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 83 (0x53): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ****** | |** ** | |** | |** | | ****** | | ** | | ** | | ** | |** ** | | ****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7e00, 0xc300, 0xc000, 0xc000, 0x7e00, 0x0300, 0x0300, 0x0300, 0xc300, 0x7e00, 0x0000, 0x0000, 0x0000, /* Character 84 (0x54): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |******** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xff00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 85 (0x55): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | ** ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 86 (0x56): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |** ** | |** ** | | ** ** | | ** ** | | ** ** | | **** | | **** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xc300, 0xc300, 0x6600, 0x6600, 0x6600, 0x3c00, 0x3c00, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 87 (0x57): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |** ** | |** ** | |** ** | |** ** ** | |** ** ** | |** ** ** | |******** | |*** *** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xc300, 0xc300, 0xc300, 0xdb00, 0xdb00, 0xdb00, 0xff00, 0xe700, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 88 (0x58): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |** ** | | ** ** | | **** | | ** | | ** | | **** | | ** ** | |** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xc300, 0x6600, 0x3c00, 0x1800, 0x1800, 0x3c00, 0x6600, 0xc300, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 89 (0x59): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** ** | |** ** | | ** ** | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc300, 0xc300, 0x6600, 0x3c00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 90 (0x5a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x0300, 0x0300, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x6000, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 91 (0x5b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | ***** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ***** | | | | | +---------+ */ 0x0000, 0x3e00, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3e00, 0x0000, 0x0000, /* Character 92 (0x5c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc000, 0x6000, 0x6000, 0x3000, 0x1800, 0x1800, 0x0c00, 0x0600, 0x0600, 0x0300, 0x0000, 0x0000, 0x0000, /* Character 93 (0x5d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | ***** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ***** | | | | | +---------+ */ 0x0000, 0x3e00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x3e00, 0x0000, 0x0000, /* Character 94 (0x5e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | **** | | ** ** | | * * | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x3c00, 0x6600, 0x4200, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 95 (0x5f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | |******** | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0x0000, /* Character 96 (0x60): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | ** | | ** | | ** | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x3000, 0x1800, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 97 (0x61): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ***** | | ** ** | | ** | | ******* | |** ** | |** *** | | **** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x6300, 0x0300, 0x7f00, 0xc300, 0xc700, 0x7b00, 0x0000, 0x0000, 0x0000, /* Character 98 (0x62): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** | |** | |** | |** *** | |*** ** | |** ** | |** ** | |** ** | |*** ** | |** *** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xdc00, 0xe600, 0xc300, 0xc300, 0xc300, 0xe600, 0xdc00, 0x0000, 0x0000, 0x0000, /* Character 99 (0x63): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ***** | | ** ** | |** | |** | |** | | ** ** | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x6300, 0xc000, 0xc000, 0xc000, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 100 (0x64): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | *** ** | | ** *** | |** ** | |** ** | |** ** | | ** *** | | *** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0300, 0x0300, 0x0300, 0x3b00, 0x6700, 0xc300, 0xc300, 0xc300, 0x6700, 0x3b00, 0x0000, 0x0000, 0x0000, /* Character 101 (0x65): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | **** | | ** ** | |** ** | |******** | |** | | ** ** | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x6600, 0xc300, 0xff00, 0xc000, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 102 (0x66): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | ** ** | | ** ** | | ** | | ** | |****** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1e00, 0x3300, 0x3300, 0x3000, 0x3000, 0xfc00, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x0000, /* Character 103 (0x67): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ***** * | |** *** | |** ** | |** ** | | ***** | |** | | ****** | |** ** | |** ** | | ****** | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7d00, 0xc700, 0xc600, 0xc600, 0x7c00, 0xc000, 0x7e00, 0xc300, 0xc300, 0x7e00, /* Character 104 (0x68): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | |** | |** | |** | |** *** | |*** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0xc000, 0xc000, 0xc000, 0xdc00, 0xe600, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 105 (0x69): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | | | *** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x1800, 0x0000, 0x3800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x7e00, 0x0000, 0x0000, 0x0000, /* Character 106 (0x6a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** ** | | ** ** | | ** ** | | ***** | +---------+ */ 0x0000, 0x0000, 0x0300, 0x0300, 0x0000, 0x0f00, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x6300, 0x6300, 0x6300, 0x3e00, /* Character 107 (0x6b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | ** ** | | ** ** | | **** | | **** | | ** ** | | ** ** | | ** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x6600, 0x6c00, 0x7800, 0x7800, 0x6c00, 0x6600, 0x6300, 0x0000, 0x0000, 0x0000, /* Character 108 (0x6c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | *** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x7e00, 0x0000, 0x0000, 0x0000, /* Character 109 (0x6d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |* ** ** | |** ** ** | |** ** ** | |** ** ** | |** ** ** | |** ** ** | |** ** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xb600, 0xdb00, 0xdb00, 0xdb00, 0xdb00, 0xdb00, 0xdb00, 0x0000, 0x0000, 0x0000, /* Character 110 (0x6e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |** *** | |*** ** | |** ** | |** ** | |** ** | |** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xdc00, 0xe600, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 111 (0x6f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | **** | | ** ** | |** ** | |** ** | |** ** | | ** ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3c00, 0x6600, 0xc300, 0xc300, 0xc300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 112 (0x70): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |** *** | |*** ** | |** ** | |** ** | |** ** | |*** ** | |** *** | |** | |** | |** | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xdc00, 0xe600, 0xc300, 0xc300, 0xc300, 0xe600, 0xdc00, 0xc000, 0xc000, 0xc000, /* Character 113 (0x71): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | *** ** | | ** *** | |** ** | |** ** | |** ** | | ** *** | | *** ** | | ** | | ** | | ** | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3b00, 0x6700, 0xc300, 0xc300, 0xc300, 0x6700, 0x3b00, 0x0300, 0x0300, 0x0300, /* Character 114 (0x72): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |** **** | | *** ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xde00, 0x7300, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, /* Character 115 (0x73): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ****** | |** ** | |** | | ****** | | ** | |** ** | | ****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0xc300, 0xc000, 0x7e00, 0x0300, 0xc300, 0x7e00, 0x0000, 0x0000, 0x0000, /* Character 116 (0x74): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | ** | | ** | |****** | | ** | | ** | | ** | | ** | | ** ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x3000, 0x3000, 0xfc00, 0x3000, 0x3000, 0x3000, 0x3000, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, /* Character 117 (0x75): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |** ** | |** ** | |** ** | |** ** | |** ** | | ** *** | | *** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0x6700, 0x3b00, 0x0000, 0x0000, 0x0000, /* Character 118 (0x76): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |** ** | |** ** | | ** ** | | ** ** | | **** | | **** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc300, 0xc300, 0x6600, 0x6600, 0x3c00, 0x3c00, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 119 (0x77): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |** ** | |** ** | |** ** ** | |** ** ** | |** ** ** | |******** | | ** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc300, 0xc300, 0xdb00, 0xdb00, 0xdb00, 0xff00, 0x6600, 0x0000, 0x0000, 0x0000, /* Character 120 (0x78): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |** ** | | ** ** | | **** | | ** | | **** | | ** ** | |** ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc300, 0x6600, 0x3c00, 0x1800, 0x3c00, 0x6600, 0xc300, 0x0000, 0x0000, 0x0000, /* Character 121 (0x79): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | |** ** | |** ** | |** ** | |** ** | |** ** | | ** *** | | *** ** | | ** | |** ** | | ***** | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc300, 0xc300, 0xc300, 0xc300, 0xc300, 0x6700, 0x3b00, 0x0300, 0xc600, 0x7c00, /* Character 122 (0x7a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ****** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x7e00, 0x0000, 0x0000, 0x0000, /* Character 123 (0x7b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | *** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | *** | | | | | +---------+ */ 0x0000, 0x0e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x3000, 0x3000, 0x1800, 0x1800, 0x1800, 0x1800, 0x0e00, 0x0000, 0x0000, /* Character 124 (0x7c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 125 (0x7d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | *** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | *** | | | | | +---------+ */ 0x0000, 0x3800, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x3800, 0x0000, 0x0000, /* Character 126 (0x7e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | *** ** | |** ** ** | |** *** | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7300, 0xdb00, 0xce00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; /* Exported structure definition. */ static const FontDesc consoleMediumBDesc = { "9x15B-ISO8859-1", 9, 15, 9, 15, 0, -3, 12, 29, 98, consoleMediumB_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ nullptr, /* fixed bbox*/ 32, // Originally 30 sizeof(consoleMediumB_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-5.1.1/src/gui/ConsoleMediumFont.hxx000066400000000000000000001275071324334165500205220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Generated by src/tools/convbdf on Wed Jul 31 13:28:39 2013. //============================================================================ #ifndef CONSOLEMEDIUM_FONT_DATA_HXX #define CONSOLEMEDIUM_FONT_DATA_HXX #include "Font.hxx" /* Font information: name: 9x15-ISO8859-1 facename: -Misc-Fixed-Medium-R-Normal--15-140-75-75-C-90-ISO8859-1 w x h: 9x15 bbx: 9 15 0 -3 size: 97 ascent: 12 descent: 3 first char: 30 (0x1e) last char: 126 (0x7e) default char: 30 (0x1e) proportional: no Public domain font. Share and enjoy. */ namespace GUI { // Font character bitmap data. static const uInt16 consoleMedium_font_bits[] = { /* MODIFIED Character 29 (0x1d): ellipsis width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | XX XX XX| | XX XX XX| | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0b0110110110000000, 0b0110110110000000, 0x0000, 0x0000, 0x0000, /* MODIFIED Character 30 (0x1e): large centered rounded rectangle width 9 bbx ( 9, 15, 0, -3 ) +---------+ | ***** | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ***** | +---------+ */ 0x3e00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x3e00, /* MODIFIED Character 31 (0x1f): large centered circle width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | *** | | ***** | | ******* | | ***** | | *** | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3e00, 0x7f00, 0x3e00, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 32 (0x20): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 33 (0x21): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | * | | * | | * | | * | | * | | * | | * | | | | | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0000, 0x0000, 0x0800, 0x0800, 0x0000, 0x0000, 0x0000, /* Character 34 (0x22): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | * * | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1200, 0x1200, 0x1200, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 35 (0x23): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | * * | | * * | | ****** | | * * | | * * | | ****** | | * * | | * * | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x2400, 0x2400, 0x7e00, 0x2400, 0x2400, 0x7e00, 0x2400, 0x2400, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 36 (0x24): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | ***** | | * * * | | * * | | * * | | *** | | * * | | * * | | * * * | | ***** | | * | | | | | +---------+ */ 0x0000, 0x0000, 0x0800, 0x3e00, 0x4900, 0x4800, 0x2800, 0x1c00, 0x0a00, 0x0900, 0x4900, 0x3e00, 0x0800, 0x0000, 0x0000, /* Character 37 (0x25): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * * | | * * * | | * * | | * | | * | | * * | | * * * | | * * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x2100, 0x5200, 0x5200, 0x2400, 0x0800, 0x0800, 0x1200, 0x2500, 0x2500, 0x4200, 0x0000, 0x0000, 0x0000, /* Character 38 (0x26): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | * * | | * * | | * * | | ** | | ** * | | * * * | | * * | | * * * | | ** * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3000, 0x4800, 0x4800, 0x4800, 0x3000, 0x3100, 0x4a00, 0x4400, 0x4a00, 0x3100, 0x0000, 0x0000, 0x0000, /* Character 39 (0x27): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0800, 0x0800, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 40 (0x28): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +---------+ */ 0x0000, 0x0400, 0x0800, 0x0800, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x0800, 0x0800, 0x0400, 0x0000, 0x0000, /* Character 41 (0x29): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +---------+ */ 0x0000, 0x1000, 0x0800, 0x0800, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0800, 0x0800, 0x1000, 0x0000, 0x0000, /* Character 42 (0x2a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | * | | * * * | | * * * | | *** | | * * * | | * * * | | * | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x4900, 0x2a00, 0x1c00, 0x2a00, 0x4900, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 43 (0x2b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | * | | * | | * | | ******* | | * | | * | | * | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x0800, 0x0800, 0x7f00, 0x0800, 0x0800, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 44 (0x2c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | ** | | ** | | * | | * | | * | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0400, 0x0400, 0x0800, /* Character 45 (0x2d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | ******* | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 46 (0x2e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, /* Character 47 (0x2f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0100, 0x0200, 0x0200, 0x0400, 0x0800, 0x0800, 0x1000, 0x2000, 0x2000, 0x4000, 0x0000, 0x0000, 0x0000, /* Character 48 (0x30): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | *** | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | *** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1c00, 0x2200, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x2200, 0x1c00, 0x0000, 0x0000, 0x0000, /* Character 49 (0x31): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | ** | | * * | | * * | | * | | * | | * | | * | | * | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0800, 0x1800, 0x2800, 0x4800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 50 (0x32): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * | | * | | * | | * | | * | | * | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 51 (0x33): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | * | | * | | * | | *** | | * | | * | | * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x0100, 0x0200, 0x0400, 0x0e00, 0x0100, 0x0100, 0x0100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 52 (0x34): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | ** | | * * | | * * | | * * | | * * | | ******* | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0200, 0x0600, 0x0a00, 0x1200, 0x2200, 0x4200, 0x7f00, 0x0200, 0x0200, 0x0200, 0x0000, 0x0000, 0x0000, /* Character 53 (0x35): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | * | | * | | * **** | | ** * | | * | | * | | * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x4000, 0x4000, 0x5e00, 0x6100, 0x0100, 0x0100, 0x0100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 54 (0x36): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | **** | | * | | * | | * | | * **** | | ** * | | * * | | * * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1e00, 0x2000, 0x4000, 0x4000, 0x5e00, 0x6100, 0x4100, 0x4100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 55 (0x37): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x0100, 0x0200, 0x0200, 0x0400, 0x0400, 0x0800, 0x0800, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, /* Character 56 (0x38): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | *** | | * * | | * * | | * * | | *** | | * * | | * * | | * * | | * * | | *** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1c00, 0x2200, 0x4100, 0x2200, 0x1c00, 0x2200, 0x4100, 0x4100, 0x2200, 0x1c00, 0x0000, 0x0000, 0x0000, /* Character 57 (0x39): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * * | | * ** | | **** * | | * | | * | | * | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x4100, 0x4300, 0x3d00, 0x0100, 0x0100, 0x0200, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 58 (0x3a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ** | | ** | | | | | | | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, /* Character 59 (0x3b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ** | | ** | | | | | | | | ** | | ** | | * | | * | | * | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0400, 0x0400, 0x0800, /* Character 60 (0x3c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0000, 0x0000, 0x0000, /* Character 61 (0x3d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | ******* | | | | | | ******* | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x0000, 0x0000, 0x7f00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 62 (0x3e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x0000, 0x0000, 0x0000, /* Character 63 (0x3f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * | | * | | * | | * | | * | | | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x0100, 0x0200, 0x0400, 0x0800, 0x0800, 0x0000, 0x0800, 0x0000, 0x0000, 0x0000, /* Character 64 (0x40): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * **** | | * * * | | * * ** | | * ** * | | * | | * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x4f00, 0x5100, 0x5300, 0x4d00, 0x4000, 0x4000, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 65 (0x41): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * * | | * * | | * * | | * * | | * * | | ******* | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0800, 0x1400, 0x2200, 0x4100, 0x4100, 0x4100, 0x7f00, 0x4100, 0x4100, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 66 (0x42): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * * | | ***** | | * * | | * * | | * * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7c00, 0x4200, 0x4100, 0x4200, 0x7c00, 0x4200, 0x4100, 0x4100, 0x4200, 0x7c00, 0x0000, 0x0000, 0x0000, /* Character 67 (0x43): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * | | * | | * | | * | | * | | * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 68 (0x44): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7c00, 0x4200, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4200, 0x7c00, 0x0000, 0x0000, 0x0000, /* Character 69 (0x45): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | * | | * | | * | | ***** | | * | | * | | * | | * | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x4000, 0x4000, 0x4000, 0x7c00, 0x4000, 0x4000, 0x4000, 0x4000, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 70 (0x46): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | * | | * | | * | | ***** | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x4000, 0x4000, 0x4000, 0x7c00, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, 0x0000, /* Character 71 (0x47): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * | | * | | * | | * *** | | * * | | * * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4000, 0x4000, 0x4000, 0x4700, 0x4100, 0x4100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 72 (0x48): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | * * | | * * | | ******* | | * * | | * * | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4100, 0x4100, 0x4100, 0x7f00, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 73 (0x49): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * | | * | | * | | * | | * | | * | | * | | * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 74 (0x4a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | *****| | * | | * | | * | | * | | * | | * | | * | | * * | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0f80, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x4200, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 75 (0x4b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | * * | | * * | | *** | | * * | | * * | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4200, 0x4400, 0x4800, 0x7000, 0x5000, 0x4800, 0x4400, 0x4200, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 76 (0x4c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 77 (0x4d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | ** ** | | * * * * | | * * * * | | * * * | | * * * | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4100, 0x6300, 0x5500, 0x5500, 0x4900, 0x4900, 0x4100, 0x4100, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 78 (0x4e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | ** * | | * * * | | * * * | | * * * | | * ** | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4100, 0x6100, 0x5100, 0x4900, 0x4500, 0x4300, 0x4100, 0x4100, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 79 (0x4f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 80 (0x50): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ****** | | * * | | * * | | * * | | ****** | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7e00, 0x4100, 0x4100, 0x4100, 0x7e00, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, 0x0000, /* Character 81 (0x51): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * * | | * * | | * * | | * * | | * * * | | * * * | | ***** | | * | | ** | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x5100, 0x4900, 0x3e00, 0x0400, 0x0300, 0x0000, /* Character 82 (0x52): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ****** | | * * | | * * | | * * | | ****** | | * * | | * * | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7e00, 0x4100, 0x4100, 0x4100, 0x7e00, 0x4800, 0x4400, 0x4200, 0x4100, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 83 (0x53): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ***** | | * * | | * * | | * | | *** | | ** | | * | | * * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x4000, 0x3800, 0x0600, 0x0100, 0x4100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 84 (0x54): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0000, 0x0000, 0x0000, /* Character 85 (0x55): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 86 (0x56): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4100, 0x4100, 0x2200, 0x2200, 0x2200, 0x1400, 0x1400, 0x1400, 0x0800, 0x0000, 0x0000, 0x0000, /* Character 87 (0x57): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | * * | | * * | | * * * | | * * * | | * * * | | * * * | | * * * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4100, 0x4100, 0x4100, 0x4900, 0x4900, 0x4900, 0x4900, 0x5500, 0x2200, 0x0000, 0x0000, 0x0000, /* Character 88 (0x58): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | * * | | * * | | * | | * | | * * | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4100, 0x2200, 0x1400, 0x0800, 0x0800, 0x1400, 0x2200, 0x4100, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 89 (0x59): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * * | | * * | | * * | | * * | | * | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4100, 0x4100, 0x2200, 0x1400, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0000, 0x0000, 0x0000, /* Character 90 (0x5a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ******* | | * | | * | | * | | * | | * | | * | | * | | * | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x7f00, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x4000, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 91 (0x5b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | **** | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | **** | | | | | +---------+ */ 0x0000, 0x1e00, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1e00, 0x0000, 0x0000, /* Character 92 (0x5c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4000, 0x2000, 0x2000, 0x1000, 0x0800, 0x0800, 0x0400, 0x0200, 0x0200, 0x0100, 0x0000, 0x0000, 0x0000, /* Character 93 (0x5d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | **** | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | **** | | | | | +---------+ */ 0x0000, 0x3c00, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x3c00, 0x0000, 0x0000, /* Character 94 (0x5e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * * | | * * | | * * | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0800, 0x1400, 0x2200, 0x4100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 95 (0x5f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | |******** | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0x0000, /* Character 96 (0x60): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | * | | * | | * | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x1000, 0x0800, 0x0400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 97 (0x61): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ***** | | * | | * | | ****** | | * * | | * ** | | **** * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x0100, 0x0100, 0x3f00, 0x4100, 0x4300, 0x3d00, 0x0000, 0x0000, 0x0000, /* Character 98 (0x62): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | * **** | | ** * | | * * | | * * | | * * | | ** * | | * **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x5e00, 0x6100, 0x4100, 0x4100, 0x4100, 0x6100, 0x5e00, 0x0000, 0x0000, 0x0000, /* Character 99 (0x63): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ***** | | * * | | * | | * | | * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x4100, 0x4000, 0x4000, 0x4000, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 100 (0x64): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | **** * | | * ** | | * * | | * * | | * * | | * ** | | **** * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0100, 0x0100, 0x0100, 0x3d00, 0x4300, 0x4100, 0x4100, 0x4100, 0x4300, 0x3d00, 0x0000, 0x0000, 0x0000, /* Character 101 (0x65): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ***** | | * * | | * * | | ******* | | * | | * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x7f00, 0x4000, 0x4000, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 102 (0x66): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | *** | | * * | | * * | | * | | * | | ***** | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0e00, 0x1100, 0x1100, 0x1000, 0x1000, 0x7c00, 0x1000, 0x1000, 0x1000, 0x1000, 0x0000, 0x0000, 0x0000, /* Character 103 (0x67): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | **** * | | * * | | * * | | * * | | **** | | * | | ***** | | * * | | * * | | ***** | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3d00, 0x4200, 0x4200, 0x4200, 0x3c00, 0x4000, 0x3e00, 0x4100, 0x4100, 0x3e00, /* Character 104 (0x68): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | * **** | | ** * | | * * | | * * | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x5e00, 0x6100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 105 (0x69): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | | | | | *** | | * | | * | | * | | * | | * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x1800, 0x0000, 0x0000, 0x3800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 106 (0x6a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** | | | | | | *** | | * | | * | | * | | * | | * | | * * | | * * | | * * | | **** | +---------+ */ 0x0000, 0x0000, 0x0600, 0x0000, 0x0000, 0x0e00, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x4200, 0x4200, 0x4200, 0x3c00, /* Character 107 (0x6b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | * | | * | | * | | * * | | * ** | | * ** | | ** | | * ** | | * ** | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x4000, 0x4000, 0x4000, 0x4100, 0x4600, 0x5800, 0x6000, 0x5800, 0x4600, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 108 (0x6c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | *** | | * | | * | | * | | * | | * | | * | | * | | * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 109 (0x6d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | *** ** | | * * * | | * * * | | * * * | | * * * | | * * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7600, 0x4900, 0x4900, 0x4900, 0x4900, 0x4900, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 110 (0x6e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | * **** | | ** * | | * * | | * * | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5e00, 0x6100, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 111 (0x6f): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ***** | | * * | | * * | | * * | | * * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x4100, 0x4100, 0x4100, 0x4100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 112 (0x70): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | * **** | | ** * | | * * | | * * | | * * | | ** * | | * **** | | * | | * | | * | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5e00, 0x6100, 0x4100, 0x4100, 0x4100, 0x6100, 0x5e00, 0x4000, 0x4000, 0x4000, /* Character 113 (0x71): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | **** * | | * ** | | * * | | * * | | * * | | * ** | | **** * | | * | | * | | * | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3d00, 0x4300, 0x4100, 0x4100, 0x4100, 0x4300, 0x3d00, 0x0100, 0x0100, 0x0100, /* Character 114 (0x72): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | * *** | | ** * | | * * | | * | | * | | * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4e00, 0x3100, 0x2100, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, 0x0000, /* Character 115 (0x73): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ***** | | * * | | * | | ***** | | * | | * * | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x4100, 0x4000, 0x3e00, 0x0100, 0x4100, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 116 (0x74): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | * | | * | | ****** | | * | | * | | * | | * | | * * | | *** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x1000, 0x1000, 0x7e00, 0x1000, 0x1000, 0x1000, 0x1000, 0x1100, 0x0e00, 0x0000, 0x0000, 0x0000, /* Character 117 (0x75): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | * * | | * * | | * * | | * * | | * * | | * * | | **** * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x3d00, 0x0000, 0x0000, 0x0000, /* Character 118 (0x76): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | * * | | * * | | * * | | * * | | * * | | * * | | * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4100, 0x4100, 0x2200, 0x2200, 0x1400, 0x1400, 0x0800, 0x0000, 0x0000, 0x0000, /* Character 119 (0x77): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | * * | | * * | | * * * | | * * * | | * * * | | * * * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4100, 0x4100, 0x4900, 0x4900, 0x4900, 0x5500, 0x2200, 0x0000, 0x0000, 0x0000, /* Character 120 (0x78): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | * * | | * * | | * * | | * | | * * | | * * | | * * | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4100, 0x2200, 0x1400, 0x0800, 0x1400, 0x2200, 0x4100, 0x0000, 0x0000, 0x0000, /* Character 121 (0x79): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | * * | | * * | | * * | | * * | | * * | | * ** | | *** * | | * | | * * | | **** | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4200, 0x4200, 0x4200, 0x4200, 0x4200, 0x4600, 0x3a00, 0x0200, 0x4200, 0x3c00, /* Character 122 (0x7a): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | ******* | | * | | * | | * | | * | | * | | ******* | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x7f00, 0x0000, 0x0000, 0x0000, /* Character 123 (0x7b): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | *** | | * | | * | | * | | * | | ** | | ** | | * | | * | | * | | * | | *** | | | | | +---------+ */ 0x0000, 0x0700, 0x0800, 0x0800, 0x0800, 0x0400, 0x1800, 0x1800, 0x0400, 0x0800, 0x0800, 0x0800, 0x0700, 0x0000, 0x0000, /* Character 124 (0x7c): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | * | | | | | +---------+ */ 0x0000, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0800, 0x0000, 0x0000, /* Character 125 (0x7d): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | *** | | * | | * | | * | | * | | ** | | ** | | * | | * | | * | | * | | *** | | | | | +---------+ */ 0x0000, 0x7000, 0x0800, 0x0800, 0x0800, 0x1000, 0x0c00, 0x0c00, 0x1000, 0x0800, 0x0800, 0x0800, 0x7000, 0x0000, 0x0000, /* Character 126 (0x7e): width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | ** * | | * * * | | * ** | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x3100, 0x4900, 0x4600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; /* Exported structure definition. */ static const FontDesc consoleMediumDesc = { "9x15-ISO8859-1", 9, 15, 9, 15, 0, -3, 12, 29, 98, consoleMedium_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ nullptr, /* fixed bbox*/ 32, // Originally 30 sizeof(consoleMedium_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-5.1.1/src/gui/ContextMenu.cxx000066400000000000000000000404061324334165500173640ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "EventHandler.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "ScrollBarWidget.hxx" #include "ContextMenu.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ContextMenu::ContextMenu(GuiObject* boss, const GUI::Font& font, const VariantList& items, int cmd, int width) : Dialog(boss->instance(), boss->parent()), CommandSender(boss), _rowHeight(font.getLineHeight()), _firstEntry(0), _numEntries(0), _selectedOffset(0), _selectedItem(-1), _showScroll(false), _isScrolling(false), _scrollUpColor(kColor), _scrollDnColor(kColor), _font(font), _cmd(cmd), _xorig(0), _yorig(0), _maxWidth(width) { addItems(items); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::addItems(const VariantList& items) { _entries.clear(); _entries = items; // Resize to largest string int maxwidth = _maxWidth; for(const auto& e: _entries) maxwidth = std::max(maxwidth, _font.getStringWidth(e.first)); _x = _y = 0; #ifndef FLAT_UI _w = maxwidth + 15; #else _w = maxwidth + 23; #endif _h = 1; // recalculate this in ::recalc() _scrollUpColor = _firstEntry > 0 ? kScrollColor : kColor; _scrollDnColor = (_firstEntry + _numEntries < int(_entries.size())) ? kScrollColor : kColor; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::show(uInt32 x, uInt32 y, int item) { _xorig = x; _yorig = y; recalc(instance().frameBuffer().imageRect()); open(); setSelectedIndex(item); moveToSelected(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::center() { // Make sure the menu is exactly where it should be, in case the image // offset has changed const GUI::Rect& image = instance().frameBuffer().imageRect(); recalc(image); uInt32 x = image.x() + _xorig; uInt32 y = image.y() + _yorig; uInt32 tx = image.x() + image.width(); uInt32 ty = image.y() + image.height(); if(x + _w > tx) x -= (x + _w - tx); if(y + _h > ty) y -= (y + _h - ty); surface().setDstPos(x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::recalc(const GUI::Rect& image) { // Now is the time to adjust the height // If it's higher than the screen, we need to scroll through uInt32 maxentries = std::min(18u, (image.height() - 4) / _rowHeight); if(_entries.size() > maxentries) { // We show two less than the max, so we have room for two scroll buttons _numEntries = maxentries - 2; _h = maxentries * _rowHeight + 4; _showScroll = true; } else { _numEntries = int(_entries.size()); _h = int(_entries.size()) * _rowHeight + 4; _showScroll = false; } _isScrolling = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::setSelectedIndex(int idx) { if(idx >= 0 && idx < int(_entries.size())) _selectedItem = idx; else _selectedItem = -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::setSelected(const Variant& tag, const Variant& defaultTag) { if(tag != "") // indicates that the defaultTag should be used instead { for(uInt32 item = 0; item < _entries.size(); ++item) { if(BSPF::equalsIgnoreCase(_entries[item].second.toString(), tag.toString())) { setSelectedIndex(item); return; } } } // If we get this far, the value wasn't found; use the default value for(uInt32 item = 0; item < _entries.size(); ++item) { if(BSPF::equalsIgnoreCase(_entries[item].second.toString(), defaultTag.toString())) { setSelectedIndex(item); return; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::setSelectedMax() { setSelectedIndex(int(_entries.size()) - 1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::clearSelection() { _selectedItem = -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int ContextMenu::getSelected() const { return _selectedItem; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& ContextMenu::getSelectedName() const { return (_selectedItem >= 0) ? _entries[_selectedItem].first : EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Variant& ContextMenu::getSelectedTag() const { return (_selectedItem >= 0) ? _entries[_selectedItem].second : EmptyVariant; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ContextMenu::sendSelectionUp() { if(isVisible() || _selectedItem <= 0) return false; _selectedItem--; sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ContextMenu::sendSelectionDown() { if(isVisible() || _selectedItem >= int(_entries.size()) - 1) return false; _selectedItem++; sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ContextMenu::sendSelectionFirst() { if(isVisible()) return false; _selectedItem = 0; sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ContextMenu::sendSelectionLast() { if(isVisible()) return false; _selectedItem = int(_entries.size()) - 1; sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleMouseDown(int x, int y, MouseButton b, int clickCount) { // Compute over which item the mouse is... int item = findItem(x, y); // Only do a selection when the left button is in the dialog if(b == MouseButton::LEFT) { if(item != -1) { _isScrolling = _showScroll && ((item == 0) || (item == _numEntries+1)); sendSelection(); } else close(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleMouseMoved(int x, int y) { // Compute over which item the mouse is... int item = findItem(x, y); if(item == -1) return; // ...and update the selection accordingly drawCurrentSelection(item); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ContextMenu::handleMouseClicks(int x, int y, MouseButton b) { // Let continuous mouse clicks come through, as the scroll buttons need them return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleMouseWheel(int x, int y, int direction) { // Wheel events are only relevant in scroll mode if(_showScroll) { if(direction < 0) scrollUp(ScrollBarWidget::getWheelLines()); else if(direction > 0) scrollDown(ScrollBarWidget::getWheelLines()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleKeyDown(StellaKey key, StellaMod mod) { handleEvent(instance().eventHandler().eventForKey(key, kMenuMode)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleJoyDown(int stick, int button) { handleEvent(instance().eventHandler().eventForJoyButton(stick, button, kMenuMode)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleJoyAxis(int stick, int axis, int value) { if(value != 0) // we don't care about 'axis up' events handleEvent(instance().eventHandler().eventForJoyAxis(stick, axis, value, kMenuMode)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ContextMenu::handleJoyHat(int stick, int hat, JoyHat value) { handleEvent(instance().eventHandler().eventForJoyHat(stick, hat, value, kMenuMode)); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::handleEvent(Event::Type e) { switch(e) { case Event::UISelect: sendSelection(); break; case Event::UIUp: case Event::UILeft: moveUp(); break; case Event::UIDown: case Event::UIRight: moveDown(); break; case Event::UIPgUp: movePgUp(); break; case Event::UIPgDown: movePgDown(); break; case Event::UIHome: moveToFirst(); break; case Event::UIEnd: moveToLast(); break; case Event::UICancel: close(); break; default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int ContextMenu::findItem(int x, int y) const { if(x >= 0 && x < _w && y >= 0 && y < _h) return (y - 4) / _rowHeight; return -1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::drawCurrentSelection(int item) { // Change selection _selectedOffset = item; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::sendSelection() { // Select the correct item when scrolling; we have to take into account // that the viewable items are no longer 1-to-1 with the entries int item = _firstEntry + _selectedOffset; if(_showScroll) { if(_selectedOffset == 0) // scroll up return scrollUp(); else if(_selectedOffset == _numEntries+1) // scroll down return scrollDown(); else if(_isScrolling) return; else item--; } // We remove the dialog when the user has selected an item // Make sure the dialog is removed before sending any commands, // since one consequence of sending a command may be to add another // dialog/menu close(); // Send any command associated with the selection _selectedItem = item; sendCommand(_cmd ? _cmd : ContextMenu::kItemSelectedCmd, _selectedItem, -1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::moveUp() { if(_showScroll) { // Reaching the top of the list means we have to scroll up, but keep the // current item offset // Otherwise, the offset should decrease by 1 if(_selectedOffset == 1) scrollUp(); else if(_selectedOffset > 1) drawCurrentSelection(_selectedOffset-1); } else { if(_selectedOffset > 0) drawCurrentSelection(_selectedOffset-1); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::moveDown() { if(_showScroll) { // Reaching the bottom of the list means we have to scroll down, but keep the // current item offset // Otherwise, the offset should increase by 1 if(_selectedOffset == _numEntries) scrollDown(); else if(_selectedOffset < int(_entries.size())) drawCurrentSelection(_selectedOffset+1); } else { if(_selectedOffset < int(_entries.size()) - 1) drawCurrentSelection(_selectedOffset+1); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::movePgUp() { if(_firstEntry == 0) moveToFirst(); else scrollUp(_numEntries); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::movePgDown() { if(_firstEntry == int(_entries.size() - _numEntries)) moveToLast(); else scrollDown(_numEntries); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::moveToFirst() { _firstEntry = 0; _scrollUpColor = kColor; _scrollDnColor = kScrollColor; drawCurrentSelection(_firstEntry + (_showScroll ? 1 : 0)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::moveToLast() { _firstEntry = int(_entries.size()) - _numEntries; _scrollUpColor = kScrollColor; _scrollDnColor = kColor; drawCurrentSelection(_numEntries - (_showScroll ? 0 : 1)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::moveToSelected() { if(_selectedItem < 0 || _selectedItem >= int(_entries.size())) return; // First jump immediately to the item _firstEntry = _selectedItem; int offset = 0; // Now check if we've gone past the current 'window' size, and scale // back accordingly int max_offset = int(_entries.size()) - _numEntries; if(_firstEntry > max_offset) { offset = _firstEntry - max_offset; _firstEntry -= offset; } _scrollUpColor = _firstEntry > 0 ? kScrollColor : kColor; _scrollDnColor = _firstEntry < max_offset ? kScrollColor : kColor; drawCurrentSelection(offset + (_showScroll ? 1 : 0)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::scrollUp(int distance) { if(_firstEntry == 0) return; _firstEntry = std::max(_firstEntry - distance, 0); _scrollUpColor = _firstEntry > 0 ? kScrollColor : kColor; _scrollDnColor = kScrollColor; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::scrollDown(int distance) { int max_offset = int(_entries.size()) - _numEntries; if(_firstEntry == max_offset) return; _firstEntry = std::min(_firstEntry + distance, max_offset); _scrollUpColor = kScrollColor; _scrollDnColor = _firstEntry < max_offset ? kScrollColor : kColor; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ContextMenu::drawDialog() { static uInt32 up_arrow[8] = { 0b00011000, 0b00011000, 0b00111100, 0b00111100, 0b01111110, 0b01111110, 0b11111111, 0b11111111 }; static uInt32 down_arrow[8] = { 0b11111111, 0b11111111, 0b01111110, 0b01111110, 0b00111100, 0b00111100, 0b00011000, 0b00011000 }; // Normally we add widgets and let Dialog::draw() take care of this // logic. But for some reason, this Dialog was written differently // by the ScummVM guys, so I'm not going to mess with it. FBSurface& s = surface(); if(_dirty) { // Draw menu border and background s.fillRect(_x+1, _y+1, _w-2, _h-2, kWidColor); #ifndef FLAT_UI s.box(_x, _y, _w, _h, kColor, kShadowColor); // Draw the entries, taking scroll buttons into account int x = _x + 2, y = _y + 2, w = _w - 4; #else s.frameRect(_x, _y, _w, _h, kTextColor); // Draw the entries, taking scroll buttons into account int x = _x + 1, y = _y + 1, w = _w - 2; #endif // Show top scroll area int offset = _selectedOffset; if(_showScroll) { s.hLine(x, y+_rowHeight-1, w+2, kShadowColor); s.drawBitmap(up_arrow, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollUpColor, 8); y += _rowHeight; offset--; } for(int i = _firstEntry, current = 0; i < _firstEntry + _numEntries; ++i, ++current) { bool hilite = offset == current; if(hilite) s.fillRect(x, y, w, _rowHeight, kTextColorHi); s.drawString(_font, _entries[i].first, x + 1, y + 2, w, !hilite ? kTextColor : kWidColor); y += _rowHeight; } // Show bottom scroll area if(_showScroll) { s.hLine(x, y, w+2, kShadowColor); s.drawBitmap(down_arrow, ((_w-_x)>>1)-4, (_rowHeight>>1)+y-4, _scrollDnColor, 8); } s.setDirty(); _dirty = false; } // Commit surface changes to screen s.render(); } stella-5.1.1/src/gui/ContextMenu.hxx000066400000000000000000000106151324334165500173700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef CONTEXT_MENU_HXX #define CONTEXT_MENU_HXX #include "bspf.hxx" #include "Command.hxx" #include "Dialog.hxx" #include "Variant.hxx" /** * Popup context menu which, when clicked, "pop up" a list of items and * lets the user pick on of them. * * Implementation wise, when the user selects an item, then the given 'cmd' * is broadcast, with data being equal to the tag value of the selected entry. * * There are also several utility methods (named as sendSelectionXXX) that * allow to cycle through the current items without actually opening the dialog. */ class ContextMenu : public Dialog, public CommandSender { public: enum { kItemSelectedCmd = 'CMsl' }; public: ContextMenu(GuiObject* boss, const GUI::Font& font, const VariantList& items, int cmd = 0, int width = 0); virtual ~ContextMenu() = default; /** Add the given items to the widget. */ void addItems(const VariantList& items); /** Show context menu onscreen at the specified coordinates */ void show(uInt32 x, uInt32 y, int item = -1); /** Select the first entry matching the given tag. */ void setSelected(const Variant& tag, const Variant& defaultTag); /** Select the entry at the given index. */ void setSelectedIndex(int idx); /** Select the highest/last entry in the internal list. */ void setSelectedMax(); /** Clear selection (reset to default). */ void clearSelection(); /** Accessor methods for the currently selected item. */ int getSelected() const; const string& getSelectedName() const; const Variant& getSelectedTag() const; /** This dialog uses its own positioning, so we override Dialog::center() */ void center() override; /** The following methods are used when we want to select *and* send a command for the new selection. They are only to be used when the dialog *isn't* open, and are basically a shortcut so that a PopUpWidget has some basic functionality without forcing to open its associated ContextMenu. */ bool sendSelectionUp(); bool sendSelectionDown(); bool sendSelectionFirst(); bool sendSelectionLast(); private: void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseMoved(int x, int y) override; bool handleMouseClicks(int x, int y, MouseButton b) override; void handleMouseWheel(int x, int y, int direction) override; void handleKeyDown(StellaKey key, StellaMod mod) override; void handleJoyDown(int stick, int button) override; void handleJoyAxis(int stick, int axis, int value) override; bool handleJoyHat(int stick, int hat, JoyHat value) override; void handleEvent(Event::Type e); void drawDialog() override; void recalc(const GUI::Rect& image); int findItem(int x, int y) const; void drawCurrentSelection(int item); void moveUp(); void moveDown(); void movePgUp(); void movePgDown(); void moveToFirst(); void moveToLast(); void moveToSelected(); void scrollUp(int distance = 1); void scrollDown(int distance = 1); void sendSelection(); private: VariantList _entries; int _rowHeight; int _firstEntry, _numEntries; int _selectedOffset, _selectedItem; bool _showScroll; bool _isScrolling; uInt32 _scrollUpColor, _scrollDnColor; const GUI::Font& _font; int _cmd; uInt32 _xorig, _yorig; uInt32 _maxWidth; private: // Following constructors and assignment operators not supported ContextMenu() = delete; ContextMenu(const ContextMenu&) = delete; ContextMenu(ContextMenu&&) = delete; ContextMenu& operator=(const ContextMenu&) = delete; ContextMenu& operator=(ContextMenu&&) = delete; }; #endif stella-5.1.1/src/gui/DeveloperDialog.cxx000066400000000000000000001241141324334165500201570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "OSystem.hxx" #include "Joystick.hxx" #include "Paddles.hxx" #include "PointingDevice.hxx" #include "SaveKey.hxx" #include "AtariVox.hxx" #include "Settings.hxx" #include "EventMappingWidget.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "RadioButtonWidget.hxx" #include "ColorWidget.hxx" #include "TabWidget.hxx" #include "Widget.hxx" #include "Font.hxx" #ifdef DEBUGGER_SUPPORT #include "DebuggerDialog.hxx" #endif #include "Console.hxx" #include "TIA.hxx" #include "OSystem.hxx" #include "StateManager.hxx" #include "RewindManager.hxx" #include "M6502.hxx" #include "DeveloperDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DeveloperDialog::DeveloperDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent) { const int VGAP = 4; const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), buttonHeight = font.getLineHeight() + 4; int xpos, ypos; // Set real dimensions _w = std::min(53 * fontWidth + 10, max_w); _h = std::min(15 * (lineHeight + VGAP) + 14, max_h); // The tab widget xpos = 2; ypos = 4; myTab = new TabWidget(this, font, xpos, ypos, _w - 2 * xpos, _h - buttonHeight - 16 - ypos); addTabWidget(myTab); addEmulationTab(font); addVideoTab(font); addTimeMachineTab(font); addDebuggerTab(font); addDefaultOKCancelButtons(font); // Activate the first tab myTab->setActiveTab(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::addEmulationTab(const GUI::Font& font) { const int HBORDER = 10; const int INDENT = 16+4; const int VBORDER = 8; const int VGAP = 4; int ypos = VBORDER; int lineHeight = font.getLineHeight(); WidgetArray wid; VariantList items; int tabID = myTab->addTab("Emulation"); // settings set mySettingsGroup0 = new RadioButtonGroup(); RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Player settings", mySettingsGroup0, kPlrSettings); wid.push_back(r); ypos += lineHeight + VGAP; r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Developer settings", mySettingsGroup0, kDevSettings); wid.push_back(r); ypos += lineHeight + VGAP * 1; myFrameStatsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "Frame statistics"); wid.push_back(myFrameStatsWidget); ypos += lineHeight + VGAP; // 2600/7800 mode items.clear(); VarList::push_back(items, "Atari 2600", "2600"); VarList::push_back(items, "Atari 7800", "7800"); int lwidth = font.getStringWidth("Console "); int pwidth = font.getStringWidth("Atari 2600"); myConsoleWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 1, ypos, pwidth, lineHeight, items, "Console ", lwidth, kConsole); wid.push_back(myConsoleWidget); ypos += lineHeight + VGAP; // Randomize items myLoadingROMLabel = new StaticTextWidget(myTab, font, HBORDER + INDENT*1, ypos + 1, "When loading a ROM:"); wid.push_back(myLoadingROMLabel); ypos += lineHeight + VGAP; myRandomBankWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, "Random startup bank"); wid.push_back(myRandomBankWidget); ypos += lineHeight + VGAP; // Randomize RAM myRandomizeRAMWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, "Randomize zero-page and extended RAM", kRandRAMID); wid.push_back(myRandomizeRAMWidget); ypos += lineHeight + VGAP; // Randomize CPU lwidth = font.getStringWidth("Randomize CPU "); myRandomizeCPULabel = new StaticTextWidget(myTab, font, HBORDER + INDENT * 2, ypos + 1, "Randomize CPU "); wid.push_back(myRandomizeCPULabel); int xpos = myRandomizeCPULabel->getRight() + 10; const char* const cpuregs[] = { "SP", "A", "X", "Y", "PS" }; for(int i = 0; i < 5; ++i) { myRandomizeCPUWidget[i] = new CheckboxWidget(myTab, font, xpos, ypos + 1, cpuregs[i], kRandCPUID); wid.push_back(myRandomizeCPUWidget[i]); xpos += CheckboxWidget::boxSize() + font.getStringWidth("XX") + 20; } ypos += lineHeight + VGAP; // How to handle undriven TIA pins myUndrivenPinsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "Drive unused TIA pins randomly on a read/peek"); wid.push_back(myUndrivenPinsWidget); ypos += lineHeight + VGAP; // Thumb ARM emulation exception myThumbExceptionWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "Fatal ARM emulation error throws exception"); wid.push_back(myThumbExceptionWidget); ypos += lineHeight + VGAP; // AtariVox/SaveKey EEPROM access myEEPROMAccessWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "Display AtariVox/SaveKey EEPROM R/W access"); wid.push_back(myEEPROMAccessWidget); // Add items for tab 0 addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::addVideoTab(const GUI::Font& font) { const int HBORDER = 10; const int INDENT = 16 + 4; const int VBORDER = 8; const int VGAP = 4; int ypos = VBORDER; int lineHeight = font.getLineHeight(); int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(); int lwidth = font.getStringWidth("Intensity "); int pwidth = font.getMaxCharWidth() * 6; WidgetArray wid; VariantList items; int tabID = myTab->addTab("Video"); wid.clear(); ypos = VBORDER; // settings set mySettingsGroup1 = new RadioButtonGroup(); RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Player settings", mySettingsGroup1, kPlrSettings); wid.push_back(r); ypos += lineHeight + VGAP; r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Developer settings", mySettingsGroup1, kDevSettings); wid.push_back(r); ypos += lineHeight + VGAP * 1; // TV jitter effect myTVJitterWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "Jitter/roll effect", kTVJitter); wid.push_back(myTVJitterWidget); myTVJitterRecWidget = new SliderWidget(myTab, font, myTVJitterWidget->getRight() + fontWidth * 3, ypos - 1, 8 * fontWidth, lineHeight, "Recovery ", font.getStringWidth("Recovery "), kTVJitterChanged); myTVJitterRecWidget->setMinValue(1); myTVJitterRecWidget->setMaxValue(20); wid.push_back(myTVJitterRecWidget); myTVJitterRecLabelWidget = new StaticTextWidget(myTab, font, myTVJitterRecWidget->getRight() + 4, myTVJitterRecWidget->getTop() + 2, 5 * fontWidth, fontHeight, "", TextAlign::Left); wid.push_back(myTVJitterRecLabelWidget); ypos += lineHeight + VGAP; myColorLossWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "PAL color-loss"); wid.push_back(myColorLossWidget); ypos += lineHeight + VGAP; // debug colors myDebugColorsWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT * 1, ypos + 1, "Debug colors (*)"); wid.push_back(myDebugColorsWidget); ypos += lineHeight + VGAP + 2; items.clear(); VarList::push_back(items, "Red", "r"); VarList::push_back(items, "Orange", "o"); VarList::push_back(items, "Yellow", "y"); VarList::push_back(items, "Green", "g"); VarList::push_back(items, "Purple", "p"); VarList::push_back(items, "Blue", "b"); static constexpr int dbg_cmds[DEBUG_COLORS] = { kP0ColourChangedCmd, kM0ColourChangedCmd, kP1ColourChangedCmd, kM1ColourChangedCmd, kPFColourChangedCmd, kBLColourChangedCmd }; auto createDebugColourWidgets = [&](int idx, const string& desc) { int x = HBORDER + INDENT * 1; myDbgColour[idx] = new PopUpWidget(myTab, font, x, ypos - 1, pwidth, lineHeight, items, desc, lwidth, dbg_cmds[idx]); wid.push_back(myDbgColour[idx]); x += myDbgColour[idx]->getWidth() + 10; myDbgColourSwatch[idx] = new ColorWidget(myTab, font, x, ypos - 1, uInt32(2 * lineHeight), lineHeight); ypos += lineHeight + VGAP * 1; }; createDebugColourWidgets(0, "Player 0 "); createDebugColourWidgets(1, "Missile 0 "); createDebugColourWidgets(2, "Player 1 "); createDebugColourWidgets(3, "Missile 1 "); createDebugColourWidgets(4, "Playfield "); createDebugColourWidgets(5, "Ball "); // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10; new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) colors identical for player and developer settings"); // Add items for tab 2 addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::addTimeMachineTab(const GUI::Font& font) { const string INTERVALS[NUM_INTERVALS] = { " 1 frame", " 3 frames", "10 frames", "30 frames", " 1 second", " 3 seconds", "10 seconds" }; const string INT_SETTINGS[NUM_INTERVALS] = { "1f", "3f", "10f", "30f", "1s", "3s", "10s" }; const string HORIZONS[NUM_HORIZONS] = { " 3 seconds", "10 seconds", "30 seconds", " 1 minute", " 3 minutes", "10 minutes", "30 minutes", "60 minutes" }; const string HOR_SETTINGS[NUM_HORIZONS] = { "3s", "10s", "30s", "1m", "3m", "10m", "30m", "60m" }; const int HBORDER = 10; const int INDENT = 16+4; const int VBORDER = 8; const int VGAP = 4; int ypos = VBORDER; int lineHeight = font.getLineHeight(); int fontHeight = font.getFontHeight(); WidgetArray wid; VariantList items; int tabID = myTab->addTab("Time Machine"); // settings set mySettingsGroup2 = new RadioButtonGroup(); RadioButtonWidget* r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Player settings", mySettingsGroup2, kPlrSettings); wid.push_back(r); ypos += lineHeight + VGAP; r = new RadioButtonWidget(myTab, font, HBORDER, ypos + 1, "Developer settings", mySettingsGroup2, kDevSettings); wid.push_back(r); ypos += lineHeight + VGAP * 1; myTimeMachineWidget = new CheckboxWidget(myTab, font, HBORDER + INDENT, ypos + 1, "Time Machine", kTimeMachine); wid.push_back(myTimeMachineWidget); ypos += lineHeight + VGAP; int sWidth = font.getMaxCharWidth() * 8; myStateSizeWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, sWidth, lineHeight, "Buffer size (*) ", 0, kSizeChanged); myStateSizeWidget->setMinValue(20); myStateSizeWidget->setMaxValue(1000); myStateSizeWidget->setStepValue(20); wid.push_back(myStateSizeWidget); myStateSizeLabelWidget = new StaticTextWidget(myTab, font, myStateSizeWidget->getRight() + 4, myStateSizeWidget->getTop() + 2, "100 "); ypos += lineHeight + VGAP; myUncompressedWidget = new SliderWidget(myTab, font, HBORDER + INDENT * 2, ypos - 1, sWidth, lineHeight, "Uncompressed size ", 0, kUncompressedChanged); myUncompressedWidget->setMinValue(0); myUncompressedWidget->setMaxValue(1000); myUncompressedWidget->setStepValue(20); wid.push_back(myUncompressedWidget); myUncompressedLabelWidget = new StaticTextWidget(myTab, font, myUncompressedWidget->getRight() + 4, myUncompressedWidget->getTop() + 2, "50 "); ypos += lineHeight + VGAP; items.clear(); for(int i = 0; i < NUM_INTERVALS; ++i) VarList::push_back(items, INTERVALS[i], INT_SETTINGS[i]); int pwidth = font.getStringWidth("10 seconds"); myStateIntervalWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 2, ypos, pwidth, lineHeight, items, "Interval ", 0, kIntervalChanged); wid.push_back(myStateIntervalWidget); ypos += lineHeight + VGAP; items.clear(); for(int i = 0; i < NUM_HORIZONS; ++i) VarList::push_back(items, HORIZONS[i], HOR_SETTINGS[i]); myStateHorizonWidget = new PopUpWidget(myTab, font, HBORDER + INDENT * 2, ypos, pwidth, lineHeight, items, "Horizon ~ ", 0, kHorizonChanged); wid.push_back(myStateHorizonWidget); // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10; new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Any size change clears the buffer"); addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::addDebuggerTab(const GUI::Font& font) { int tabID = myTab->addTab("Debugger"); WidgetArray wid; #ifdef DEBUGGER_SUPPORT const int HBORDER = 10; const int VBORDER = 8; const int VGAP = 4; VariantList items; int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(); int xpos, ypos, pwidth; const GUI::Size& ds = instance().frameBuffer().desktopSize(); xpos = HBORDER; ypos = VBORDER; // font size items.clear(); VarList::push_back(items, "Small", "small"); VarList::push_back(items, "Medium", "medium"); VarList::push_back(items, "Large", "large"); pwidth = font.getStringWidth("Medium"); myDebuggerFontSize = new PopUpWidget(myTab, font, HBORDER, ypos + 1, pwidth, lineHeight, items, "Font size (*) ", 0, kDFontSizeChanged); wid.push_back(myDebuggerFontSize); ypos += lineHeight + 4; // Font style (bold label vs. text, etc) items.clear(); VarList::push_back(items, "All Normal font", "0"); VarList::push_back(items, "Bold labels only", "1"); VarList::push_back(items, "Bold non-labels only", "2"); VarList::push_back(items, "All Bold font", "3"); pwidth = font.getStringWidth("Bold non-labels only"); myDebuggerFontStyle = new PopUpWidget(myTab, font, HBORDER, ypos + 1, pwidth, lineHeight, items, "Font style (*) ", 0); wid.push_back(myDebuggerFontStyle); ypos += lineHeight + VGAP * 4; pwidth = font.getMaxCharWidth() * 8; // Debugger width and height myDebuggerWidthSlider = new SliderWidget(myTab, font, xpos, ypos-1, pwidth, lineHeight, "Debugger width (*) ", 0, kDWidthChanged); myDebuggerWidthSlider->setMinValue(DebuggerDialog::kSmallFontMinW); myDebuggerWidthSlider->setMaxValue(ds.w); myDebuggerWidthSlider->setStepValue(10); wid.push_back(myDebuggerWidthSlider); myDebuggerWidthLabel = new StaticTextWidget(myTab, font, xpos + myDebuggerWidthSlider->getWidth() + 4, ypos + 1, 4 * fontWidth, fontHeight, "", TextAlign::Left); ypos += lineHeight + VGAP; myDebuggerHeightSlider = new SliderWidget(myTab, font, xpos, ypos-1, pwidth, lineHeight, "Debugger height (*) ", 0, kDHeightChanged); myDebuggerHeightSlider->setMinValue(DebuggerDialog::kSmallFontMinH); myDebuggerHeightSlider->setMaxValue(ds.h); myDebuggerHeightSlider->setStepValue(10); wid.push_back(myDebuggerHeightSlider); myDebuggerHeightLabel = new StaticTextWidget(myTab, font, xpos + myDebuggerHeightSlider->getWidth() + 4, ypos + 1, 4 * fontWidth, fontHeight, "", TextAlign::Left); ypos += lineHeight + VGAP * 4; myGhostReadsTrapWidget = new CheckboxWidget(myTab, font, HBORDER, ypos + 1, "Trap on 'ghost' reads", kGhostReads); // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10; new StaticTextWidget(myTab, infofont, HBORDER, ypos, "(*) Changes require a ROM reload"); // Debugger is only realistically available in windowed modes 800x600 or greater // (and when it's actually been compiled into the app) bool debuggerAvailable = #if defined(DEBUGGER_SUPPORT) && defined(WINDOWED_SUPPORT) (ds.w >= 800 && ds.h >= 600); // TODO - maybe this logic can disappear? #else false; #endif if(!debuggerAvailable) { myDebuggerWidthSlider->clearFlags(WIDGET_ENABLED); myDebuggerWidthLabel->clearFlags(WIDGET_ENABLED); myDebuggerHeightSlider->clearFlags(WIDGET_ENABLED); myDebuggerHeightLabel->clearFlags(WIDGET_ENABLED); } // Add items for tab 1 addToFocusList(wid, myTab, tabID); #else new StaticTextWidget(myTab, font, 0, 20, _w - 20, font.getFontHeight(), "Debugger support not included", TextAlign::Center); #endif addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::addDefaultOKCancelButtons(const GUI::Font& font) { const int buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; WidgetArray wid; wid.clear(); ButtonWidget* btn = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(btn); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::loadSettings(SettingsSet set) { string prefix = set == SettingsSet::player ? "plr." : "dev."; myFrameStats[set] = instance().settings().getBool(prefix + "stats"); myConsole[set] = instance().settings().getString(prefix + "console") == "7800" ? 1 : 0; // Randomization myRandomBank[set] = instance().settings().getBool(prefix + "bankrandom"); myRandomizeRAM[set] = instance().settings().getBool(prefix + "ramrandom"); myRandomizeCPU[set] = instance().settings().getString(prefix + "cpurandom"); // Undriven TIA pins myUndrivenPins[set] = instance().settings().getBool(prefix + "tiadriven"); // Thumb ARM emulation exception myThumbException[set] = instance().settings().getBool(prefix + "thumb.trapfatal"); // AtariVox/SaveKey EEPROM access myEEPROMAccess[set] = instance().settings().getBool(prefix + "eepromaccess"); // Debug colors myDebugColors[set] = instance().settings().getBool(prefix + "debugcolors"); // PAL color-loss effect myColorLoss[set] = instance().settings().getBool(prefix + "colorloss"); // Jitter myTVJitter[set] = instance().settings().getBool(prefix + "tv.jitter"); myTVJitterRec[set] = instance().settings().getInt(prefix + "tv.jitter_recovery"); // States myTimeMachine[set] = instance().settings().getBool(prefix + "timemachine"); myStateSize[set] = instance().settings().getInt(prefix + "tm.size"); myUncompressed[set] = instance().settings().getInt(prefix + "tm.uncompressed"); myStateInterval[set] = instance().settings().getString(prefix + "tm.interval"); myStateHorizon[set] = instance().settings().getString(prefix + "tm.horizon"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::saveSettings(SettingsSet set) { string prefix = set == SettingsSet::player ? "plr." : "dev."; instance().settings().setValue(prefix + "stats", myFrameStats[set]); instance().settings().setValue(prefix + "console", myConsole[set] == 1 ? "7800" : "2600"); // Randomization instance().settings().setValue(prefix + "bankrandom", myRandomBank[set]); instance().settings().setValue(prefix + "ramrandom", myRandomizeRAM[set]); instance().settings().setValue(prefix + "cpurandom", myRandomizeCPU[set]); // Undriven TIA pins instance().settings().setValue(prefix + "tiadriven", myUndrivenPins[set]); // Thumb ARM emulation exception instance().settings().setValue(prefix + "thumb.trapfatal", myThumbException[set]); // AtariVox/SaveKey EEPROM access instance().settings().setValue(prefix + "eepromaccess", myEEPROMAccess[set]); // Debug colors instance().settings().setValue(prefix + "debugcolors", myDebugColors[set]); // PAL color loss instance().settings().setValue(prefix + "colorloss", myColorLoss[set]); // Jitter instance().settings().setValue(prefix + "tv.jitter", myTVJitter[set]); instance().settings().setValue(prefix + "tv.jitter_recovery", myTVJitterRec[set]); // States instance().settings().setValue(prefix + "timemachine", myTimeMachine[set]); instance().settings().setValue(prefix + "tm.size", myStateSize[set]); instance().settings().setValue(prefix + "tm.uncompressed", myUncompressed[set]); instance().settings().setValue(prefix + "tm.interval", myStateInterval[set]); instance().settings().setValue(prefix + "tm.horizon", myStateHorizon[set]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::getWidgetStates(SettingsSet set) { myFrameStats[set] = myFrameStatsWidget->getState(); myConsole[set] = myConsoleWidget->getSelected() == 1; // Randomization myRandomBank[set] = myRandomBankWidget->getState(); myRandomizeRAM[set] = myRandomizeRAMWidget->getState(); string cpurandom; const char* const cpuregs[] = { "S", "A", "X", "Y", "P" }; for(int i = 0; i < 5; ++i) if(myRandomizeCPUWidget[i]->getState()) cpurandom += cpuregs[i]; myRandomizeCPU[set] = cpurandom; // Undriven TIA pins myUndrivenPins[set] = myUndrivenPinsWidget->getState(); // Thumb ARM emulation exception myThumbException[set] = myThumbExceptionWidget->getState(); // AtariVox/SaveKey EEPROM access myEEPROMAccess[set] = myEEPROMAccessWidget->getState(); // Debug colors myDebugColors[set] = myDebugColorsWidget->getState(); // PAL color-loss effect myColorLoss[set] = myColorLossWidget->getState(); // Jitter myTVJitter[set] = myTVJitterWidget->getState(); myTVJitterRec[set] = myTVJitterRecWidget->getValue(); // States myTimeMachine[set] = myTimeMachineWidget->getState(); myStateSize[set] = myStateSizeWidget->getValue(); myUncompressed[set] = myUncompressedWidget->getValue(); myStateInterval[set] = myStateIntervalWidget->getSelected(); myStateInterval[set] = myStateIntervalWidget->getSelectedTag().toString(); myStateHorizon[set] = myStateHorizonWidget->getSelectedTag().toString(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::setWidgetStates(SettingsSet set) { myFrameStatsWidget->setState(myFrameStats[set]); myConsoleWidget->setSelectedIndex(myConsole[set]); // Randomization myRandomBankWidget->setState(myRandomBank[set]); myRandomizeRAMWidget->setState(myRandomizeRAM[set]); const string& cpurandom = myRandomizeCPU[set]; const char* const cpuregs[] = { "S", "A", "X", "Y", "P" }; for(int i = 0; i < 5; ++i) myRandomizeCPUWidget[i]->setState(BSPF::containsIgnoreCase(cpurandom, cpuregs[i])); // Undriven TIA pins myUndrivenPinsWidget->setState(myUndrivenPins[set]); // Thumb ARM emulation exception myThumbExceptionWidget->setState(myThumbException[set]); // AtariVox/SaveKey EEPROM access myEEPROMAccessWidget->setState(myEEPROMAccess[set]); handleConsole(); // Debug colors myDebugColorsWidget->setState(myDebugColors[set]); // PAL color-loss effect myColorLossWidget->setState(myColorLoss[set]); // Jitter myTVJitterWidget->setState(myTVJitter[set]); myTVJitterRecWidget->setValue(myTVJitterRec[set]); handleTVJitterChange(myTVJitterWidget->getState()); handleEnableDebugColors(); // States myTimeMachineWidget->setState(myTimeMachine[set]); myStateSizeWidget->setValue(myStateSize[set]); myUncompressedWidget->setValue(myUncompressed[set]); myStateIntervalWidget->setSelected(myStateInterval[set]); myStateHorizonWidget->setSelected(myStateHorizon[set]); handleTimeMachine(); handleSize(); handleUncompressed(); handleInterval(); handleHorizon(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::loadConfig() { bool devSettings = instance().settings().getBool("dev.settings"); mySettings = devSettings; mySettingsGroup0->setSelected(devSettings ? 1 : 0); mySettingsGroup1->setSelected(devSettings ? 1 : 0); mySettingsGroup2->setSelected(devSettings ? 1 : 0); // load both setting sets... loadSettings(SettingsSet::player); loadSettings(SettingsSet::developer); // ...and select the current one setWidgetStates(SettingsSet(mySettingsGroup0->getSelected())); // Debug colours handleDebugColours(instance().settings().getString("tia.dbgcolors")); #ifdef DEBUGGER_SUPPORT uInt32 w, h; // Debugger size const GUI::Size& ds = instance().settings().getSize("dbg.res"); w = ds.w; h = ds.h; myDebuggerWidthSlider->setValue(w); myDebuggerWidthLabel->setValue(w); myDebuggerHeightSlider->setValue(h); myDebuggerHeightLabel->setValue(h); // Debugger font size string size = instance().settings().getString("dbg.fontsize"); myDebuggerFontSize->setSelected(size, "medium"); // Debugger font style int style = instance().settings().getInt("dbg.fontstyle"); myDebuggerFontStyle->setSelected(style, "0"); // Ghost reads trap myGhostReadsTrapWidget->setState(instance().settings().getBool("dbg.ghostreadstrap")); handleFontSize(); #endif myTab->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::saveConfig() { instance().settings().setValue("dev.settings", mySettingsGroup0->getSelected() == SettingsSet::developer); // copy current widget status into set... getWidgetStates(SettingsSet(mySettingsGroup0->getSelected())); // ...and save both sets saveSettings(SettingsSet::player); saveSettings(SettingsSet::developer); // activate the current settings instance().frameBuffer().showFrameStats(myFrameStatsWidget->getState()); // jitter if(instance().hasConsole()) { instance().console().tia().toggleJitter(myTVJitterWidget->getState() ? 1 : 0); instance().console().tia().setJitterRecoveryFactor(myTVJitterRecWidget->getValue()); } handleEnableDebugColors(); // PAL color loss if(instance().hasConsole()) instance().console().enableColorLoss(myColorLossWidget->getState()); // Debug colours string dbgcolors; for(int i = 0; i < DEBUG_COLORS; ++i) dbgcolors += myDbgColour[i]->getSelectedTag().toString(); if(instance().hasConsole() && instance().console().tia().setFixedColorPalette(dbgcolors)) instance().settings().setValue("tia.dbgcolors", dbgcolors); // update RewindManager instance().state().rewindManager().setup(); instance().state().setRewindMode(myTimeMachineWidget->getState() ? StateManager::Mode::TimeMachine : StateManager::Mode::Off); #ifdef DEBUGGER_SUPPORT // Debugger font style instance().settings().setValue("dbg.fontstyle", myDebuggerFontStyle->getSelectedTag().toString()); // Debugger size instance().settings().setValue("dbg.res", GUI::Size(myDebuggerWidthSlider->getValue(), myDebuggerHeightSlider->getValue())); // Debugger font size instance().settings().setValue("dbg.fontsize", myDebuggerFontSize->getSelectedTag().toString()); // Ghost reads trap instance().settings().setValue("dbg.ghostreadstrap", myGhostReadsTrapWidget->getState()); if(instance().hasConsole()) instance().console().system().m6502().setGhostReadsTrap(myGhostReadsTrapWidget->getState()); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::setDefaults() { bool devSettings = mySettingsGroup0->getSelected() == 1; SettingsSet set = SettingsSet(mySettingsGroup0->getSelected()); switch(myTab->getActiveTab()) { case 0: // Emulation myFrameStats[set] = devSettings ? true : false; myConsole[set] = 0; // Randomization myRandomBank[set] = devSettings ? true : false; myRandomizeRAM[set] = devSettings ? true : false; myRandomizeCPU[set] = devSettings ? "SAXYP" : ""; // Undriven TIA pins myUndrivenPins[set] = devSettings ? true : false; // Thumb ARM emulation exception myThumbException[set] = devSettings ? true : false; // AtariVox/SaveKey EEPROM access myEEPROMAccess[set] = devSettings ? true : false; setWidgetStates(set); break; case 1: // Video // Jitter myTVJitter[set] = true; myTVJitterRec[set] = devSettings ? 2 : 10; // PAL color-loss effect myColorLoss[set] = devSettings ? true : false; // Debug colors myDebugColors[set] = false; handleDebugColours("roygpb"); setWidgetStates(set); break; case 2: // States myTimeMachine[set] = devSettings ? true : false; myStateSize[set] = 100; myUncompressed[set] = devSettings ? 60 : 30; myStateInterval[set] = devSettings ? "1f" : "30f"; myStateHorizon[set] = devSettings ? "10s" : "10m"; setWidgetStates(set); break; case 3: // Debugger options { #ifdef DEBUGGER_SUPPORT uInt32 w = std::min(instance().frameBuffer().desktopSize().w, uInt32(DebuggerDialog::kMediumFontMinW)); uInt32 h = std::min(instance().frameBuffer().desktopSize().h, uInt32(DebuggerDialog::kMediumFontMinH)); myDebuggerWidthSlider->setValue(w); myDebuggerWidthLabel->setValue(w); myDebuggerHeightSlider->setValue(h); myDebuggerHeightLabel->setValue(h); myDebuggerFontSize->setSelected("medium"); myDebuggerFontStyle->setSelected("0"); myGhostReadsTrapWidget->setState(true); handleFontSize(); #endif break; } default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kPlrSettings: handleSettings(false); break; case kDevSettings: handleSettings(true); break; case kConsole: handleConsole(); break; case kTVJitter: handleTVJitterChange(myTVJitterWidget->getState()); break; case kTVJitterChanged: myTVJitterRecLabelWidget->setValue(myTVJitterRecWidget->getValue()); break; case kPPinCmd: instance().console().tia().driveUnusedPinsRandom(myUndrivenPinsWidget->getState()); break; case kTimeMachine: handleTimeMachine(); break; case kSizeChanged: handleSize(); break; case kUncompressedChanged: handleUncompressed(); break; case kIntervalChanged: handleInterval(); break; case kHorizonChanged: handleHorizon(); break; case kP0ColourChangedCmd: handleDebugColours(0, myDbgColour[0]->getSelected()); break; case kM0ColourChangedCmd: handleDebugColours(1, myDbgColour[1]->getSelected()); break; case kP1ColourChangedCmd: handleDebugColours(2, myDbgColour[2]->getSelected()); break; case kM1ColourChangedCmd: handleDebugColours(3, myDbgColour[3]->getSelected()); break; case kPFColourChangedCmd: handleDebugColours(4, myDbgColour[4]->getSelected()); break; case kBLColourChangedCmd: handleDebugColours(5, myDbgColour[5]->getSelected()); break; #ifdef DEBUGGER_SUPPORT case kDWidthChanged: myDebuggerWidthLabel->setValue(myDebuggerWidthSlider->getValue()); break; case kDHeightChanged: myDebuggerHeightLabel->setValue(myDebuggerHeightSlider->getValue()); break; case kDFontSizeChanged: handleFontSize(); break; #endif case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kCloseCmd: // Revert changes made to event mapping close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; default: Dialog::handleCommand(sender, cmd, data, 0); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleSettings(bool devSettings) { if (mySettings != devSettings) { mySettings = devSettings; // block redundant events first! mySettingsGroup0->setSelected(devSettings ? 1 : 0); mySettingsGroup1->setSelected(devSettings ? 1 : 0); mySettingsGroup2->setSelected(devSettings ? 1 : 0); getWidgetStates(devSettings ? SettingsSet::player : SettingsSet::developer); setWidgetStates(devSettings ? SettingsSet::developer : SettingsSet::player); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleTVJitterChange(bool enable) { myTVJitterRecWidget->setEnabled(enable); myTVJitterRecLabelWidget->setEnabled(enable); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleEnableDebugColors() { if(instance().hasConsole()) { bool fixed = instance().console().tia().usingFixedColors(); if(fixed != myDebugColorsWidget->getState()) instance().console().tia().toggleFixedColors(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleConsole() { bool is7800 = myConsoleWidget->getSelected() == 1; myRandomizeRAMWidget->setEnabled(!is7800); if(is7800) myRandomizeRAMWidget->setState(false); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleTimeMachine() { bool enable = myTimeMachineWidget->getState(); myStateSizeWidget->setEnabled(enable); myStateSizeLabelWidget->setEnabled(enable); myUncompressedWidget->setEnabled(enable); myUncompressedLabelWidget->setEnabled(enable); myStateIntervalWidget->setEnabled(enable); uInt32 size = myStateSizeWidget->getValue(); uInt32 uncompressed = myUncompressedWidget->getValue(); myStateHorizonWidget->setEnabled(enable && size > uncompressed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleSize() { uInt32 size = myStateSizeWidget->getValue(); uInt32 uncompressed = myUncompressedWidget->getValue(); Int32 interval = myStateIntervalWidget->getSelected(); Int32 horizon = myStateHorizonWidget->getSelected(); bool found = false; Int32 i; // handle illegal values if(interval == -1) interval = 0; if(horizon == -1) horizon = 0; myStateSizeLabelWidget->setValue(size); // adapt horizon and interval do { for(i = horizon; i < NUM_HORIZONS; ++i) { if(uInt64(size) * instance().state().rewindManager().INTERVAL_CYCLES[interval] <= instance().state().rewindManager().HORIZON_CYCLES[i]) { found = true; break; } } if(!found) interval--; } while(!found); if(size < uncompressed) myUncompressedWidget->setValue(size); myStateIntervalWidget->setSelectedIndex(interval); myStateHorizonWidget->setSelectedIndex(i); myStateHorizonWidget->setEnabled(myTimeMachineWidget->getState() && size > uncompressed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleUncompressed() { uInt32 size = myStateSizeWidget->getValue(); uInt32 uncompressed = myUncompressedWidget->getValue(); myUncompressedLabelWidget->setValue(myUncompressedWidget->getValue()); if(size < uncompressed) myStateSizeWidget->setValue(uncompressed); myStateHorizonWidget->setEnabled(myTimeMachineWidget->getState() && size > uncompressed); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleInterval() { uInt32 size = myStateSizeWidget->getValue(); uInt32 uncompressed = myUncompressedWidget->getValue(); Int32 interval = myStateIntervalWidget->getSelected(); Int32 horizon = myStateHorizonWidget->getSelected(); bool found = false; Int32 i; // handle illegal values if(interval == -1) interval = 0; if(horizon == -1) horizon = 0; // adapt horizon and size do { for(i = horizon; i < NUM_HORIZONS; ++i) { if(uInt64(size) * instance().state().rewindManager().INTERVAL_CYCLES[interval] <= instance().state().rewindManager().HORIZON_CYCLES[i]) { found = true; break; } } if(!found) size -= myStateSizeWidget->getStepValue(); } while(!found); myStateHorizonWidget->setSelectedIndex(i); myStateSizeWidget->setValue(size); if(size < uncompressed) myUncompressedWidget->setValue(size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleHorizon() { uInt32 size = myStateSizeWidget->getValue(); uInt32 uncompressed = myUncompressedWidget->getValue(); Int32 interval = myStateIntervalWidget->getSelected(); Int32 horizon = myStateHorizonWidget->getSelected(); bool found = false; Int32 i; // handle illegal values if(interval == -1) interval = 0; if(horizon == -1) horizon = 0; // adapt interval and size do { for(i = interval; i >= 0; --i) { if(uInt64(size) * instance().state().rewindManager().INTERVAL_CYCLES[i] <= instance().state().rewindManager().HORIZON_CYCLES[horizon]) { found = true; break; } } if(!found) size -= myStateSizeWidget->getStepValue(); } while(!found); myStateIntervalWidget->setSelectedIndex(i); myStateSizeWidget->setValue(size); if(size < uncompressed) myUncompressedWidget->setValue(size); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleDebugColours(int idx, int color) { if(idx < 0 || idx >= DEBUG_COLORS) return; if(!instance().hasConsole()) { myDbgColour[idx]->clearFlags(WIDGET_ENABLED); myDbgColourSwatch[idx]->clearFlags(WIDGET_ENABLED); return; } static constexpr int dbg_color[2][DEBUG_COLORS] = { { TIA::FixedColor::NTSC_RED, TIA::FixedColor::NTSC_ORANGE, TIA::FixedColor::NTSC_YELLOW, TIA::FixedColor::NTSC_GREEN, TIA::FixedColor::NTSC_PURPLE, TIA::FixedColor::NTSC_BLUE }, { TIA::FixedColor::PAL_RED, TIA::FixedColor::PAL_ORANGE, TIA::FixedColor::PAL_YELLOW, TIA::FixedColor::PAL_GREEN, TIA::FixedColor::PAL_PURPLE, TIA::FixedColor::PAL_BLUE } }; int mode = instance().console().tia().frameLayout() == FrameLayout::ntsc ? 0 : 1; myDbgColourSwatch[idx]->setColor(dbg_color[mode][color]); myDbgColour[idx]->setSelectedIndex(color); // make sure the selected debug colors are all different bool usedCol[DEBUG_COLORS]; // identify used colors for(int i = 0; i < DEBUG_COLORS; ++i) { usedCol[i] = false; for(int j = 0; j < DEBUG_COLORS; ++j) { if(myDbgColourSwatch[j]->getColor() == dbg_color[mode][i]) { usedCol[i] = true; break; } } } // check if currently changed color was used somewhere else for(int i = 0; i < DEBUG_COLORS; ++i) { if (i != idx && myDbgColourSwatch[i]->getColor() == dbg_color[mode][color]) { // if already used, change the other color to an unused one for(int j = 0; j < DEBUG_COLORS; ++j) { if(!usedCol[j]) { myDbgColourSwatch[i]->setColor(dbg_color[mode][j]); myDbgColour[i]->setSelectedIndex(j); break; } } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleDebugColours(const string& colors) { for(int i = 0; i < DEBUG_COLORS; ++i) { switch(colors[i]) { case 'r': handleDebugColours(i, 0); break; case 'o': handleDebugColours(i, 1); break; case 'y': handleDebugColours(i, 2); break; case 'g': handleDebugColours(i, 3); break; case 'p': handleDebugColours(i, 4); break; case 'b': handleDebugColours(i, 5); break; default: break; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DeveloperDialog::handleFontSize() { #ifdef DEBUGGER_SUPPORT uInt32 minW, minH; int fontSize = myDebuggerFontSize->getSelected(); if(fontSize == 0) { minW = DebuggerDialog::kSmallFontMinW; minH = DebuggerDialog::kSmallFontMinH; } else if(fontSize == 1) { minW = DebuggerDialog::kMediumFontMinW; minH = DebuggerDialog::kMediumFontMinH; } else // large { minW = DebuggerDialog::kLargeFontMinW; minH = DebuggerDialog::kLargeFontMinH; } minW = std::min(instance().frameBuffer().desktopSize().w, minW); minH = std::min(instance().frameBuffer().desktopSize().h, minH); myDebuggerWidthSlider->setMinValue(minW); if(minW > uInt32(myDebuggerWidthSlider->getValue())) { myDebuggerWidthSlider->setValue(minW); myDebuggerWidthLabel->setValue(minW); } myDebuggerHeightSlider->setMinValue(minH); if(minH > uInt32(myDebuggerHeightSlider->getValue())) { myDebuggerHeightSlider->setValue(minH); myDebuggerHeightLabel->setValue(minH); } #endif } stella-5.1.1/src/gui/DeveloperDialog.hxx000066400000000000000000000140431324334165500201630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DEVELOPER_DIALOG_HXX #define DEVELOPER_DIALOG_HXX class OSystem; class GuiObject; class TabWidget; class EventMappingWidget; class CheckboxWidget; class EditTextWidget; class PopUpWidget; class RadioButtonGroup; class RadioButtonWidget; class SliderWidget; class StaticTextWidget; class ColorWidget; namespace GUI { class Font; } #include "bspf.hxx" #include "Dialog.hxx" class DeveloperDialog : public Dialog { public: DeveloperDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h); virtual ~DeveloperDialog() = default; private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void loadConfig() override; void saveConfig() override; void setDefaults() override; private: enum { kPlrSettings = 'DVpl', kDevSettings = 'DVdv', kConsole = 'DVco', kRandRAMID = 'DVrm', kRandCPUID = 'DVcp', kTVJitter = 'DVjt', kTVJitterChanged = 'DVjr', kPPinCmd = 'DVpn', kTimeMachine = 'DTtm', kSizeChanged = 'DTsz', kUncompressedChanged = 'DTuc', kIntervalChanged = 'DTin', kHorizonChanged = 'DThz', kP0ColourChangedCmd = 'GOp0', kM0ColourChangedCmd = 'GOm0', kP1ColourChangedCmd = 'GOp1', kM1ColourChangedCmd = 'GOm1', kPFColourChangedCmd = 'GOpf', kBLColourChangedCmd = 'GObl', #ifdef DEBUGGER_SUPPORT kDWidthChanged = 'UIdw', kDHeightChanged = 'UIdh', kDFontSizeChanged = 'UIfs', kGhostReads = 'Dbgh' #endif }; enum SettingsSet { player, developer }; // MUST be aligned with RewindManager! static const int NUM_INTERVALS = 7; static const int NUM_HORIZONS = 8; static const int DEBUG_COLORS = 6; TabWidget* myTab; // Emulator widgets RadioButtonGroup* mySettingsGroup0; CheckboxWidget* myFrameStatsWidget; PopUpWidget* myConsoleWidget; StaticTextWidget* myLoadingROMLabel; CheckboxWidget* myRandomBankWidget; CheckboxWidget* myRandomizeRAMWidget; StaticTextWidget* myRandomizeCPULabel; CheckboxWidget* myRandomizeCPUWidget[5]; CheckboxWidget* myUndrivenPinsWidget; CheckboxWidget* myThumbExceptionWidget; CheckboxWidget* myEEPROMAccessWidget; // Video widgets RadioButtonGroup* mySettingsGroup1; CheckboxWidget* myTVJitterWidget; SliderWidget* myTVJitterRecWidget; StaticTextWidget* myTVJitterRecLabelWidget; CheckboxWidget* myColorLossWidget; CheckboxWidget* myDebugColorsWidget; PopUpWidget* myDbgColour[DEBUG_COLORS]; ColorWidget* myDbgColourSwatch[DEBUG_COLORS]; // States widgets RadioButtonGroup* mySettingsGroup2; CheckboxWidget* myTimeMachineWidget; SliderWidget* myStateSizeWidget; StaticTextWidget* myStateSizeLabelWidget; SliderWidget* myUncompressedWidget; StaticTextWidget* myUncompressedLabelWidget; PopUpWidget* myStateIntervalWidget; PopUpWidget* myStateHorizonWidget; #ifdef DEBUGGER_SUPPORT // Debugger UI widgets SliderWidget* myDebuggerWidthSlider; StaticTextWidget* myDebuggerWidthLabel; SliderWidget* myDebuggerHeightSlider; StaticTextWidget* myDebuggerHeightLabel; PopUpWidget* myDebuggerFontSize; PopUpWidget* myDebuggerFontStyle; CheckboxWidget* myGhostReadsTrapWidget; #endif bool mySettings; // Emulator sets bool myFrameStats[2]; int myConsole[2]; bool myRandomBank[2]; bool myRandomizeRAM[2]; string myRandomizeCPU[2]; bool myColorLoss[2]; bool myTVJitter[2]; int myTVJitterRec[2]; bool myDebugColors[2]; bool myUndrivenPins[2]; bool myThumbException[2]; bool myEEPROMAccess[2]; // States sets bool myTimeMachine[2]; int myStateSize[2]; int myUncompressed[2]; string myStateInterval[2]; string myStateHorizon[2]; private: void addEmulationTab(const GUI::Font& font); void addTimeMachineTab(const GUI::Font& font); void addVideoTab(const GUI::Font& font); void addDebuggerTab(const GUI::Font& font); // Add Defaults, OK and Cancel buttons void addDefaultOKCancelButtons(const GUI::Font& font); void loadSettings(SettingsSet set); void saveSettings(SettingsSet set); void getWidgetStates(SettingsSet set); void setWidgetStates(SettingsSet set); void handleSettings(bool devSettings); void handleTVJitterChange(bool enable); void handleEnableDebugColors(); void handleConsole(); void handleDebugColours(int cmd, int color); void handleDebugColours(const string& colors); void handleTimeMachine(); void handleSize(); void handleUncompressed(); void handleInterval(); void handleHorizon(); void handleFontSize(); // Following constructors and assignment operators not supported DeveloperDialog() = delete; DeveloperDialog(const DeveloperDialog&) = delete; DeveloperDialog(DeveloperDialog&&) = delete; DeveloperDialog& operator=(const DeveloperDialog&) = delete; DeveloperDialog& operator=(DeveloperDialog&&) = delete; }; #endif stella-5.1.1/src/gui/Dialog.cxx000066400000000000000000000530171324334165500163140ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #include "OSystem.hxx" #include "EventHandler.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "Menu.hxx" #include "Dialog.hxx" #include "Widget.hxx" #include "TabWidget.hxx" #include "Settings.hxx" #include "Console.hxx" #include "Vec.hxx" /* * TODO list * - add some sense of the window being "active" (i.e. in front) or not. If it * was inactive and just became active, reset certain vars (like who is focused). * Maybe we should just add lostFocus and receivedFocus methods to Dialog, just * like we have for class Widget? * ... */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dialog::Dialog(OSystem& instance, DialogContainer& parent, int x, int y, int w, int h) : GuiObject(instance, parent, *this, x, y, w, h), _mouseWidget(nullptr), _focusedWidget(nullptr), _dragWidget(nullptr), _okWidget(nullptr), _cancelWidget(nullptr), _visible(false), _processCancel(false), _surface(nullptr), _tabID(0), _flags(WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dialog::~Dialog() { _myFocus.list.clear(); _myTabList.clear(); delete _firstWidget; _firstWidget = nullptr; _buttonGroup.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::open(bool refresh) { // Make sure we have a valid surface to draw into // Technically, this shouldn't be needed until drawDialog(), but some // dialogs cause drawing to occur within loadConfig() if(_surface == nullptr) _surface = instance().frameBuffer().allocateSurface(_w, _h); parent().addDialog(this); center(); loadConfig(); // (Re)-build the focus list to use for the widgets which are currently // onscreen buildCurrentFocusList(); _visible = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::close(bool refresh) { if (_mouseWidget) { _mouseWidget->handleMouseLeft(); _mouseWidget = nullptr; } releaseFocus(); _visible = false; parent().removeDialog(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::center() { if(_surface) { const GUI::Size& screen = instance().frameBuffer().screenSize(); const GUI::Rect& dst = _surface->dstRect(); _surface->setDstPos((screen.w - dst.width()) >> 1, (screen.h - dst.height()) >> 1); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::releaseFocus() { if(_focusedWidget) { _focusedWidget->lostFocus(); _focusedWidget = nullptr; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addFocusWidget(Widget* w) { if(!w) return; // All focusable widgets should retain focus w->setFlags(WIDGET_RETAIN_FOCUS); _myFocus.widget = w; _myFocus.list.push_back(w); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addToFocusList(WidgetArray& list) { // All focusable widgets should retain focus for(const auto& w: list) w->setFlags(WIDGET_RETAIN_FOCUS); Vec::append(_myFocus.list, list); _focusList = _myFocus.list; if(list.size() > 0) _myFocus.widget = list[0]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addToFocusList(WidgetArray& list, TabWidget* w, int tabId) { // Only add the list if the tab actually exists if(!w || w->getID() < 0 || uInt32(w->getID()) >= _myTabList.size()) return; assert(w == _myTabList[w->getID()].widget); // All focusable widgets should retain focus for(const auto& fw: list) fw->setFlags(WIDGET_RETAIN_FOCUS); // First get the appropriate focus list FocusList& focus = _myTabList[w->getID()].focus; // Now insert in the correct place in that focus list uInt32 id = tabId; if(id < focus.size()) Vec::append(focus[id].list, list); else { // Make sure the array is large enough while(focus.size() <= id) focus.push_back(Focus()); Vec::append(focus[id].list, list); } if(list.size() > 0) focus[id].widget = list[0]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addTabWidget(TabWidget* w) { if(!w || w->getID() < 0) return; // Make sure the array is large enough uInt32 id = w->getID(); while(_myTabList.size() < id) _myTabList.push_back(TabFocus()); _myTabList.push_back(TabFocus(w)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::setFocus(Widget* w) { // If the click occured inside a widget which is not the currently // focused one, change the focus to that widget. if(w && w != _focusedWidget && w->wantsFocus()) { // Redraw widgets for new focus _focusedWidget = Widget::setFocusForChain(this, getFocusList(), w, 0); // Update current tab based on new focused widget getTabIdForWidget(_focusedWidget); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::buildCurrentFocusList(int tabID) { // Yes, this is hideously complex. That's the price we pay for // tab navigation ... _focusList.clear(); // Remember which tab item previously had focus, if applicable // This only applies if this method was called for a tab change Widget* tabFocusWidget = nullptr; if(tabID >= 0 && tabID < int(_myTabList.size())) { // Save focus in previously selected tab column, // and get focus for new tab column TabFocus& tabfocus = _myTabList[tabID]; tabfocus.saveCurrentFocus(_focusedWidget); tabFocusWidget = tabfocus.getNewFocus(); _tabID = tabID; } // Add appropriate items from tablist (if present) for(auto& tabfocus: _myTabList) tabfocus.appendFocusList(_focusList); // Add remaining items from main focus list Vec::append(_focusList, _myFocus.list); // Add button group at end of current focus list // We do it this way for TabWidget, so that buttons are scanned // *after* the widgets in the current tab if(_buttonGroup.size() > 0) Vec::append(_focusList, _buttonGroup); // Finally, the moment we've all been waiting for :) // Set the actual focus widget if(tabFocusWidget) _focusedWidget = tabFocusWidget; else if(!_focusedWidget && _focusList.size() > 0) _focusedWidget = _focusList[0]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addSurface(shared_ptr surface) { mySurfaceStack.push(surface); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::drawDialog() { if(!isVisible()) return; FBSurface& s = surface(); if(_dirty) { if(_flags & WIDGET_CLEARBG) // cerr << "Dialog::drawDialog(): w = " << _w << ", h = " << _h << " @ " << &s << endl << endl; s.fillRect(_x, _y, _w, _h, kDlgColor); else s.invalidate(); if(_flags & WIDGET_BORDER) #ifndef FLAT_UI s.box(_x, _y, _w, _h, kColor, kShadowColor); #else s.frameRect(_x, _y, _w, _h, kColor); #endif // !FLAT_UI // Make all child widget dirty Widget* w = _firstWidget; Widget::setDirtyInChain(w); // Draw all children w = _firstWidget; while(w) { w->draw(); w = w->_next; } // Draw outlines for focused widgets // Don't change focus, since this will trigger lost and received // focus events if(_focusedWidget) _focusedWidget = Widget::setFocusForChain(this, getFocusList(), _focusedWidget, 0, false); // Tell the surface(s) this area is dirty s.setDirty(); _dirty = false; } // Commit surface changes to screen; also render any extra surfaces // Extra surfaces must be rendered afterwards, so they are drawn on top if(s.render()) { mySurfaceStack.applyAll([](shared_ptr& surface){ surface->setDirty(); surface->render(); }); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleText(char text) { // Focused widget receives text events if(_focusedWidget) _focusedWidget->handleText(text); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleKeyDown(StellaKey key, StellaMod mod) { // Test for TAB character // Control-Tab selects next tab // Shift-Control-Tab selects previous tab // Tab sets next widget in current tab // Shift-Tab sets previous widget in current tab Event::Type e = Event::NoType; // Detect selection of previous and next tab headers and objects if(key == KBDK_TAB) { if(StellaModTest::isControl(mod)) { // tab header navigation if(StellaModTest::isShift(mod) && cycleTab(-1)) return; else if(!StellaModTest::isShift(mod) && cycleTab(+1)) return; } else { // object navigation if(StellaModTest::isShift(mod)) e = Event::UINavPrev; else e = Event::UINavNext; } } // Check the keytable now, since we might get one of the above events, // which must always be processed before any widget sees it. if(e == Event::NoType) e = instance().eventHandler().eventForKey(key, kMenuMode); // Unless a widget has claimed all responsibility for data, we assume // that if an event exists for the given data, it should have priority. if(!handleNavEvent(e) && _focusedWidget) { if(_focusedWidget->wantsRaw() || e == Event::NoType) _focusedWidget->handleKeyDown(key, mod); else _focusedWidget->handleEvent(e); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleKeyUp(StellaKey key, StellaMod mod) { // Focused widget receives keyup events if(_focusedWidget) _focusedWidget->handleKeyUp(key, mod); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseDown(int x, int y, MouseButton b, int clickCount) { Widget* w = findWidget(x, y); _dragWidget = w; setFocus(w); if(w) w->handleMouseDown(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), b, clickCount); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseUp(int x, int y, MouseButton b, int clickCount) { if(_focusedWidget) { // Lose focus on mouseup unless the widget requested to retain the focus if(! (_focusedWidget->getFlags() & WIDGET_RETAIN_FOCUS )) releaseFocus(); } Widget* w = _dragWidget; if(w) w->handleMouseUp(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), b, clickCount); _dragWidget = nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseWheel(int x, int y, int direction) { // This may look a bit backwards, but I think it makes more sense for // the mouse wheel to primarily affect the widget the mouse is at than // the widget that happens to be focused. Widget* w = findWidget(x, y); if(!w) w = _focusedWidget; if(w) w->handleMouseWheel(x, y, direction); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleMouseMoved(int x, int y) { Widget* w; if(_focusedWidget && !_dragWidget) { w = _focusedWidget; int wx = w->getAbsX() - _x; int wy = w->getAbsY() - _y; // We still send mouseEntered/Left messages to the focused item // (but to no other items). bool mouseInFocusedWidget = (x >= wx && x < wx + w->_w && y >= wy && y < wy + w->_h); if(mouseInFocusedWidget && _mouseWidget != w) { if(_mouseWidget) _mouseWidget->handleMouseLeft(); _mouseWidget = w; w->handleMouseEntered(); } else if (!mouseInFocusedWidget && _mouseWidget == w) { _mouseWidget = nullptr; w->handleMouseLeft(); } w->handleMouseMoved(x - wx, y - wy); } // While a "drag" is in process (i.e. mouse is moved while a button is pressed), // only deal with the widget in which the click originated. if (_dragWidget) w = _dragWidget; else w = findWidget(x, y); if (_mouseWidget != w) { if (_mouseWidget) _mouseWidget->handleMouseLeft(); if (w) w->handleMouseEntered(); _mouseWidget = w; } if (w && (w->getFlags() & WIDGET_TRACK_MOUSE)) w->handleMouseMoved(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Dialog::handleMouseClicks(int x, int y, MouseButton b) { Widget* w = findWidget(x, y); if(w) return w->handleMouseClicks(x - (w->getAbsX() - _x), y - (w->getAbsY() - _y), b); else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleJoyDown(int stick, int button) { Event::Type e = instance().eventHandler().eventForJoyButton(stick, button, kMenuMode); // Unless a widget has claimed all responsibility for data, we assume // that if an event exists for the given data, it should have priority. if(!handleNavEvent(e) && _focusedWidget) { if(_focusedWidget->wantsRaw() || e == Event::NoType) _focusedWidget->handleJoyDown(stick, button); else _focusedWidget->handleEvent(e); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleJoyUp(int stick, int button) { // Focused widget receives joystick events if(_focusedWidget) _focusedWidget->handleJoyUp(stick, button); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleJoyAxis(int stick, int axis, int value) { Event::Type e = instance().eventHandler().eventForJoyAxis(stick, axis, value, kMenuMode); // Unless a widget has claimed all responsibility for data, we assume // that if an event exists for the given data, it should have priority. if(!handleNavEvent(e) && _focusedWidget) { if(_focusedWidget->wantsRaw() || e == Event::NoType) _focusedWidget->handleJoyAxis(stick, axis, value); else if(value != 0) _focusedWidget->handleEvent(e); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Dialog::handleJoyHat(int stick, int hat, JoyHat value) { Event::Type e = instance().eventHandler().eventForJoyHat(stick, hat, value, kMenuMode); // Unless a widget has claimed all responsibility for data, we assume // that if an event exists for the given data, it should have priority. if(!handleNavEvent(e) && _focusedWidget) { if(_focusedWidget->wantsRaw() || e == Event::NoType) return _focusedWidget->handleJoyHat(stick, hat, value); else return _focusedWidget->handleEvent(e); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Dialog::handleNavEvent(Event::Type e) { switch(e) { case Event::UINavPrev: if(_focusedWidget && !_focusedWidget->wantsTab()) { _focusedWidget = Widget::setFocusForChain(this, getFocusList(), _focusedWidget, -1); // Update current tab based on new focused widget getTabIdForWidget(_focusedWidget); return true; } break; case Event::UINavNext: if(_focusedWidget && !_focusedWidget->wantsTab()) { _focusedWidget = Widget::setFocusForChain(this, getFocusList(), _focusedWidget, +1); // Update current tab based on new focused widget getTabIdForWidget(_focusedWidget); return true; } break; case Event::UIOK: if(_okWidget && _okWidget->isEnabled()) { // Receiving 'OK' is the same as getting the 'Select' event _okWidget->handleEvent(Event::UISelect); return true; } break; case Event::UICancel: if(_cancelWidget && _cancelWidget->isEnabled()) { // Receiving 'Cancel' is the same as getting the 'Select' event _cancelWidget->handleEvent(Event::UISelect); return true; } else if(_processCancel) { // Some dialogs want the ability to cancel without actually having // a corresponding cancel button close(); return true; } break; default: return false; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::getTabIdForWidget(Widget* w) { if(_myTabList.size() == 0 || !w) return; for(uInt32 id = 0; id < _myTabList.size(); ++id) { if(w->_boss == _myTabList[id].widget) { _tabID = id; return; } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Dialog::cycleTab(int direction) { if(_tabID >= 0 && _tabID < int(_myTabList.size())) { _myTabList[_tabID].widget->cycleTab(direction); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case TabWidget::kTabChangedCmd: if(_visible) buildCurrentFocusList(id); break; case GuiObject::kCloseCmd: close(); break; } } /* * Determine the widget at location (x,y) if any. Assumes the coordinates are * in the local coordinate system, i.e. relative to the top left of the dialog. */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget* Dialog::findWidget(int x, int y) const { return Widget::findWidgetInChain(_firstWidget, x, y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText, const string& cancelText, bool focusOKButton) { int buttonWidth = std::max(font.getStringWidth("Cancel"), std::max(font.getStringWidth(okText), font.getStringWidth(okText))) + 15; int buttonHeight = font.getLineHeight() + 4; #ifndef BSPF_MAC_OSX addOKWidget(new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, buttonWidth, buttonHeight, okText, GuiObject::kOKCmd)); addCancelWidget(new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10, buttonWidth, buttonHeight, cancelText, GuiObject::kCloseCmd)); #else addCancelWidget(new ButtonWidget(this, font, _w - 2 * (buttonWidth + 7), _h - buttonHeight - 10, buttonWidth, buttonHeight, cancelText, GuiObject::kCloseCmd)); addOKWidget(new ButtonWidget(this, font, _w - (buttonWidth + 10), _h - buttonHeight - 10, buttonWidth, buttonHeight, okText, GuiObject::kOKCmd)); #endif // Note that 'focusOKButton' only takes effect when there are no other UI // elements in the dialog; otherwise, the first widget of the dialog is always // automatically focused first // Changing this behaviour would require a fairly major refactoring of the UI code if(focusOKButton) { wid.push_back(_okWidget); wid.push_back(_cancelWidget); } else { wid.push_back(_cancelWidget); wid.push_back(_okWidget); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::TabFocus::appendFocusList(WidgetArray& list) { int active = widget->getActiveTab(); if(active >= 0 && active < int(focus.size())) Vec::append(list, focus[active].list); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Dialog::TabFocus::saveCurrentFocus(Widget* w) { if(currentTab < focus.size() && Widget::isWidgetInChain(focus[currentTab].list, w)) focus[currentTab].widget = w; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget* Dialog::TabFocus::getNewFocus() { currentTab = widget->getActiveTab(); return (currentTab < focus.size()) ? focus[currentTab].widget : nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Dialog::getResizableBounds(uInt32& w, uInt32& h) const { const GUI::Rect& r = instance().frameBuffer().imageRect(); double scaleFactor = 0.8; if(instance().hasConsole()) { bool ntsc = instance().console().about().InitialFrameRate == "60"; uInt32 aspect = instance().settings().getInt(ntsc ?"tia.aspectn" : "tia.aspectp"); scaleFactor = aspect / 100.0; } if(r.width() <= FrameBuffer::kFBMinW || r.height() <= FrameBuffer::kFBMinH) { w = uInt32(scaleFactor * FrameBuffer::kTIAMinW) * 2; h = FrameBuffer::kTIAMinH * 2; return false; } else { w = std::max(uInt32(scaleFactor * r.width()), uInt32(FrameBuffer::kFBMinW)); h = std::max(uInt32(scaleFactor * r.height()), uInt32(FrameBuffer::kFBMinH)); return true; } } stella-5.1.1/src/gui/Dialog.hxx000066400000000000000000000135121324334165500163150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef DIALOG_HXX #define DIALOG_HXX class FBSurface; class OSystem; class DialogContainer; class TabWidget; class CommandSender; #include "Stack.hxx" #include "Widget.hxx" #include "GuiObject.hxx" #include "StellaKeys.hxx" #include "EventHandlerConstants.hxx" #include "bspf.hxx" /** This is the base class for all dialog boxes. @author Stephen Anthony */ class Dialog : public GuiObject { friend class DialogContainer; public: Dialog(OSystem& instance, DialogContainer& parent, int x = 0, int y = 0, int w = 0, int h = 0); virtual ~Dialog(); void open(bool refresh = true); void close(bool refresh = true); bool isVisible() const override { return _visible; } virtual void center(); virtual void drawDialog(); virtual void loadConfig() { } virtual void saveConfig() { } virtual void setDefaults() { } void addFocusWidget(Widget* w) override; void addToFocusList(WidgetArray& list) override; void addToFocusList(WidgetArray& list, TabWidget* w, int tabId); void addBGroupToFocusList(WidgetArray& list) { _buttonGroup = list; } void addTabWidget(TabWidget* w); void addOKWidget(Widget* w) { _okWidget = w; } void addCancelWidget(Widget* w) { _cancelWidget = w; } void setFocus(Widget* w); /** Returns the base surface associated with this dialog. */ FBSurface& surface() const { return *_surface; } /** Adds a surface to this dialog, which is rendered on top of the base surface whenever the base surface is re-rendered. Since the surface render() call will always occur in such a case, the surface should call setVisible() to enable/disable its output. */ void addSurface(shared_ptr surface); void setFlags(int flags) { _flags |= flags; setDirty(); } void clearFlags(int flags) { _flags &= ~flags; setDirty(); } int getFlags() const { return _flags; } /** Determine the maximum bounds based on the given width and height. Returns whether or not a large font can be used within these bounds. */ bool getResizableBounds(uInt32& w, uInt32& h) const; protected: virtual void draw() override { } void releaseFocus() override; virtual void handleText(char text); virtual void handleKeyDown(StellaKey key, StellaMod modifiers); virtual void handleKeyUp(StellaKey key, StellaMod modifiers); virtual void handleMouseDown(int x, int y, MouseButton b, int clickCount); virtual void handleMouseUp(int x, int y, MouseButton b, int clickCount); virtual void handleMouseWheel(int x, int y, int direction); virtual void handleMouseMoved(int x, int y); virtual bool handleMouseClicks(int x, int y, MouseButton b); virtual void handleJoyDown(int stick, int button); virtual void handleJoyUp(int stick, int button); virtual void handleJoyAxis(int stick, int axis, int value); virtual bool handleJoyHat(int stick, int hat, JoyHat value); virtual void handleCommand(CommandSender* sender, int cmd, int data, int id) override; Widget* findWidget(int x, int y) const; // Find the widget at pos x,y if any void addOKCancelBGroup(WidgetArray& wid, const GUI::Font& font, const string& okText = "OK", const string& cancelText = "Cancel", bool focusOKButton = true); void processCancelWithoutWidget(bool state) { _processCancel = state; } private: void buildCurrentFocusList(int tabID = -1); bool handleNavEvent(Event::Type e); void getTabIdForWidget(Widget* w); bool cycleTab(int direction); protected: Widget* _mouseWidget; Widget* _focusedWidget; Widget* _dragWidget; Widget* _okWidget; Widget* _cancelWidget; bool _visible; bool _processCancel; Common::FixedStack> mySurfaceStack; private: struct Focus { Widget* widget; WidgetArray list; Focus(Widget* w = nullptr) : widget(w) { } virtual ~Focus() = default; Focus(const Focus&) = default; Focus& operator=(const Focus&) = default; }; using FocusList = vector; struct TabFocus { TabWidget* widget; FocusList focus; uInt32 currentTab; TabFocus(TabWidget* w = nullptr) : widget(w), currentTab(0) { } virtual ~TabFocus() = default; TabFocus(const TabFocus&) = default; TabFocus& operator=(const TabFocus&) = default; void appendFocusList(WidgetArray& list); void saveCurrentFocus(Widget* w); Widget* getNewFocus(); }; using TabFocusList = vector; Focus _myFocus; // focus for base dialog TabFocusList _myTabList; // focus for each tab (if any) WidgetArray _buttonGroup; shared_ptr _surface; int _tabID; int _flags; private: // Following constructors and assignment operators not supported Dialog() = delete; Dialog(const Dialog&) = delete; Dialog(Dialog&&) = delete; Dialog& operator=(const Dialog&) = delete; Dialog& operator=(Dialog&&) = delete; }; #endif stella-5.1.1/src/gui/DialogContainer.cxx000066400000000000000000000253761324334165500201660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Dialog.hxx" #include "Stack.hxx" #include "EventHandler.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Joystick.hxx" #include "bspf.hxx" #include "DialogContainer.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DialogContainer::DialogContainer(OSystem& osystem) : myOSystem(osystem), myBaseDialog(nullptr), myTime(0), myKeyRepeatTime(0), myClickRepeatTime(0), myButtonRepeatTime(0), myAxisRepeatTime(0), myHatRepeatTime(0) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DialogContainer::~DialogContainer() { delete myBaseDialog; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::updateTime(uInt64 time) { // We only need millisecond precision myTime = time / 1000; if(myDialogStack.empty()) return; // Check for pending continuous events and send them to the active dialog box Dialog* activeDialog = myDialogStack.top(); // Key still pressed if(myCurrentKeyDown.keycode != 0 && myKeyRepeatTime < myTime) { activeDialog->handleKeyDown(myCurrentKeyDown.keycode, myCurrentKeyDown.flags); myKeyRepeatTime = myTime + kRepeatSustainDelay; } // Mouse button still pressed if(myCurrentMouseDown.b != MouseButton::NONE && myClickRepeatTime < myTime) { activeDialog->handleMouseDown(myCurrentMouseDown.x - activeDialog->_x, myCurrentMouseDown.y - activeDialog->_y, myCurrentMouseDown.b, 1); myClickRepeatTime = myTime + kRepeatSustainDelay; } // Joystick button still pressed if(myCurrentButtonDown.stick != -1 && myButtonRepeatTime < myTime) { activeDialog->handleJoyDown(myCurrentButtonDown.stick, myCurrentButtonDown.button); myButtonRepeatTime = myTime + kRepeatSustainDelay; } // Joystick axis still pressed if(myCurrentAxisDown.stick != -1 && myAxisRepeatTime < myTime) { activeDialog->handleJoyAxis(myCurrentAxisDown.stick, myCurrentAxisDown.axis, myCurrentAxisDown.value); myAxisRepeatTime = myTime + kRepeatSustainDelay; } // Joystick hat still pressed if(myCurrentHatDown.stick != -1 && myHatRepeatTime < myTime) { activeDialog->handleJoyHat(myCurrentHatDown.stick, myCurrentHatDown.hat, myCurrentHatDown.value); myHatRepeatTime = myTime + kRepeatSustainDelay; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::draw(bool full) { // Draw all the dialogs on the stack when we want a full refresh if(full) { myDialogStack.applyAll([](Dialog*& d){ d->center(); d->setDirty(); d->drawDialog(); }); } else if(!myDialogStack.empty()) myDialogStack.top()->drawDialog(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::addDialog(Dialog* d) { const GUI::Rect& r = myOSystem.frameBuffer().imageRect(); if(uInt32(d->getWidth()) > r.width() || uInt32(d->getHeight()) > r.height()) myOSystem.frameBuffer().showMessage( "Unable to show dialog box; FIX THE CODE"); else myDialogStack.push(d); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::removeDialog() { if(!myDialogStack.empty()) myDialogStack.pop(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::reStack() { // Pop all items from the stack, and then add the base menu while(!myDialogStack.empty()) myDialogStack.top()->close(false); // don't force a refresh myBaseDialog->open(false); // don't force a refresh // Reset all continuous events reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleTextEvent(char text) { if(myDialogStack.empty()) return; // Send the event to the dialog box on the top of the stack Dialog* activeDialog = myDialogStack.top(); activeDialog->handleText(text); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleKeyEvent(StellaKey key, StellaMod mod, bool state) { if(myDialogStack.empty()) return; // Send the event to the dialog box on the top of the stack Dialog* activeDialog = myDialogStack.top(); if(state) { myCurrentKeyDown.keycode = key; myCurrentKeyDown.flags = mod; myKeyRepeatTime = myTime + kRepeatInitialDelay; activeDialog->handleKeyDown(key, mod); } else { activeDialog->handleKeyUp(key, mod); // Only stop firing events if it's the current key if (key == myCurrentKeyDown.keycode) myCurrentKeyDown.keycode = KBDK_UNKNOWN; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleMouseMotionEvent(int x, int y) { if(myDialogStack.empty()) return; // Send the event to the dialog box on the top of the stack Dialog* activeDialog = myDialogStack.top(); activeDialog->surface().translateCoords(x, y); activeDialog->handleMouseMoved(x - activeDialog->_x, y - activeDialog->_y); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y) { if(myDialogStack.empty()) return; // Send the event to the dialog box on the top of the stack Dialog* activeDialog = myDialogStack.top(); activeDialog->surface().translateCoords(x, y); switch(b) { case MouseButton::LEFT: case MouseButton::RIGHT: if(pressed) { // If more than two clicks have been recorded, we start over if(myLastClick.count == 2) { myLastClick.x = myLastClick.y = 0; myLastClick.time = 0; myLastClick.count = 0; } if(myLastClick.count && (myTime < myLastClick.time + kDoubleClickDelay) && std::abs(myLastClick.x - x) < 3 && std::abs(myLastClick.y - y) < 3) { myLastClick.count++; } else { myLastClick.x = x; myLastClick.y = y; myLastClick.count = 1; } myLastClick.time = myTime; // Now account for repeated mouse events (click and hold), but only // if the dialog wants them if(activeDialog->handleMouseClicks(x - activeDialog->_x, y - activeDialog->_y, b)) { myCurrentMouseDown.x = x; myCurrentMouseDown.y = y; myCurrentMouseDown.b = b; myClickRepeatTime = myTime + kRepeatInitialDelay; } else myCurrentMouseDown.b = MouseButton::NONE; activeDialog->handleMouseDown(x - activeDialog->_x, y - activeDialog->_y, b, myLastClick.count); } else { activeDialog->handleMouseUp(x - activeDialog->_x, y - activeDialog->_y, b, myLastClick.count); if(b == myCurrentMouseDown.b) myCurrentMouseDown.b = MouseButton::NONE; } break; case MouseButton::WHEELUP: activeDialog->handleMouseWheel(x - activeDialog->_x, y - activeDialog->_y, -1); break; case MouseButton::WHEELDOWN: activeDialog->handleMouseWheel(x - activeDialog->_x, y - activeDialog->_y, 1); break; case MouseButton::NONE: // should never get here break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleJoyEvent(int stick, int button, uInt8 state) { if(myDialogStack.empty()) return; // Send the event to the dialog box on the top of the stack Dialog* activeDialog = myDialogStack.top(); if(state == 1) { myCurrentButtonDown.stick = stick; myCurrentButtonDown.button = button; myButtonRepeatTime = myTime + kRepeatInitialDelay; activeDialog->handleJoyDown(stick, button); } else { // Only stop firing events if it's the current button if(stick == myCurrentButtonDown.stick) myCurrentButtonDown.stick = myCurrentButtonDown.button = -1; activeDialog->handleJoyUp(stick, button); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleJoyAxisEvent(int stick, int axis, int value) { if(myDialogStack.empty()) return; // Only stop firing events if it's the current stick if(myCurrentAxisDown.stick == stick && value == 0) { myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1; } else if(value != 0) // never repeat the 'off' event { // Now account for repeated axis events (press and hold) myCurrentAxisDown.stick = stick; myCurrentAxisDown.axis = axis; myCurrentAxisDown.value = value; myAxisRepeatTime = myTime + kRepeatInitialDelay; } myDialogStack.top()->handleJoyAxis(stick, axis, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::handleJoyHatEvent(int stick, int hat, JoyHat value) { if(myDialogStack.empty()) return; // Only stop firing events if it's the current stick if(myCurrentHatDown.stick == stick && value == JoyHat::CENTER) { myCurrentHatDown.stick = myCurrentHatDown.hat = -1; } else if(value != JoyHat::CENTER) // never repeat the 'center' direction { // Now account for repeated hat events (press and hold) myCurrentHatDown.stick = stick; myCurrentHatDown.hat = hat; myCurrentHatDown.value = value; myHatRepeatTime = myTime + kRepeatInitialDelay; } myDialogStack.top()->handleJoyHat(stick, hat, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void DialogContainer::reset() { myCurrentKeyDown.keycode = KBDK_UNKNOWN; myCurrentMouseDown.b = MouseButton::NONE; myLastClick.x = myLastClick.y = 0; myLastClick.time = 0; myLastClick.count = 0; myCurrentButtonDown.stick = myCurrentButtonDown.button = -1; myCurrentAxisDown.stick = myCurrentAxisDown.axis = -1; myCurrentHatDown.stick = myCurrentHatDown.hat = -1; } stella-5.1.1/src/gui/DialogContainer.hxx000066400000000000000000000134701324334165500201630ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef DIALOG_CONTAINER_HXX #define DIALOG_CONTAINER_HXX class Dialog; class OSystem; class EventHandler; #include "EventHandlerConstants.hxx" #include "StellaKeys.hxx" #include "Stack.hxx" #include "bspf.hxx" /** The base class for groups of dialog boxes. Each dialog box has a parent. In most cases, the parent is itself a dialog box, but in the case of the lower-most dialog box, this class is its parent. This class keeps track of its children (dialog boxes), organizes them into a stack, and handles their events. @author Stephen Anthony */ class DialogContainer { friend class EventHandler; friend class Dialog; public: /** Create a new DialogContainer stack */ DialogContainer(OSystem& osystem); virtual ~DialogContainer(); public: /** Update the dialog container with the current time. This is useful if we want to trigger events at some specified time. @param time The current time in microseconds */ void updateTime(uInt64 time); /** Handle a keyboard Unicode text event. @param text Unicode character string */ void handleTextEvent(char text); /** Handle a keyboard single-key event. @param key Actual key symbol @param mod Modifiers @param state Pressed (true) or released (false) */ void handleKeyEvent(StellaKey key, StellaMod mod, bool state); /** Handle a mouse motion event. @param x The x location @param y The y location */ void handleMouseMotionEvent(int x, int y); /** Handle a mouse button event. @param b The mouse button @param pressed Whether the button was pressed (true) or released (false) @param x The x location @param y The y location */ void handleMouseButtonEvent(MouseButton b, bool pressed, int x, int y); /** Handle a joystick button event. @param stick The joystick number @param button The joystick button @param state The state (pressed or released) */ void handleJoyEvent(int stick, int button, uInt8 state); /** Handle a joystick axis event. @param stick The joystick number @param axis The joystick axis @param value Value associated with given axis */ void handleJoyAxisEvent(int stick, int axis, int value); /** Handle a joystick hat event. @param stick The joystick number @param hat The joystick hat @param value Value associated with given hat */ void handleJoyHatEvent(int stick, int hat, JoyHat value); /** Draw the stack of menus (full indicates to redraw all items). */ void draw(bool full = false); /** Reset dialog stack to the main configuration menu. */ void reStack(); /** Return the bottom-most dialog of this container. */ const Dialog* baseDialog() const { return myBaseDialog; } /** Inform the container that it should resize according to the current screen dimensions. We make this virtual, since the container may or may not choose to do a resize, and even if it does, *how* it does it is determined by the specific container. */ virtual void requestResize() { } private: void reset(); /** Add a dialog box to the stack. */ void addDialog(Dialog* d); /** Remove the topmost dialog box from the stack. */ void removeDialog(); protected: OSystem& myOSystem; Dialog* myBaseDialog; Common::FixedStack myDialogStack; private: enum { kDoubleClickDelay = 500, kRepeatInitialDelay = 400, kRepeatSustainDelay = 50 }; // Indicates the most current time (in milliseconds) as set by updateTime() uInt64 myTime; // For continuous 'key down' events struct { StellaKey keycode; StellaMod flags; } myCurrentKeyDown; uInt64 myKeyRepeatTime; // For continuous 'mouse down' events struct { int x; int y; MouseButton b; } myCurrentMouseDown; uInt64 myClickRepeatTime; // For continuous 'joy button down' events struct { int stick; int button; } myCurrentButtonDown; uInt64 myButtonRepeatTime; // For continuous 'joy axis down' events struct { int stick; int axis; int value; } myCurrentAxisDown; uInt64 myAxisRepeatTime; // For continuous 'joy hat' events struct { int stick; int hat; JoyHat value; } myCurrentHatDown; uInt64 myHatRepeatTime; // Position and time of last mouse click (used to detect double clicks) struct { int x, y; // Position of mouse when the click occurred int count; // How often was it already pressed? uInt64 time; // Time } myLastClick; private: // Following constructors and assignment operators not supported DialogContainer() = delete; DialogContainer(const DialogContainer&) = delete; DialogContainer(DialogContainer&&) = delete; DialogContainer& operator=(const DialogContainer&) = delete; DialogContainer& operator=(DialogContainer&&) = delete; }; #endif stella-5.1.1/src/gui/EditTextWidget.cxx000066400000000000000000000072351324334165500200140ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "FBSurface.hxx" #include "Dialog.hxx" #include "Font.hxx" #include "EditTextWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EditTextWidget::EditTextWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& text) : EditableWidget(boss, font, x, y, w, h + 2, text), _changed(false) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS; startEditMode(); // We're always in edit mode } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::setText(const string& str, bool changed) { EditableWidget::setText(str, changed); _backupString = str; _changed = changed; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { if(!isEditable()) return; x += _editScrollOffset; int width = 0; uInt32 i; for (i = 0; i < editString().size(); ++i) { width += _font.getCharWidth(editString()[i]); if (width >= x) break; } if (setCaretPos(i)) setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); // Highlight changes if(_changed) s.fillRect(_x, _y, _w, _h, kDbgChangedColor); else if(!isEditable()) #ifndef FLAT_UI s.fillRect(_x, _y, _w, _h, kBGColorHi); #else s.fillRect(_x, _y, _w, _h, kDlgColor); #endif // Draw a thin frame around us. #ifndef FLAT_UI s.hLine(_x, _y, _x + _w - 1, kColor); s.hLine(_x, _y + _h - 1, _x +_w - 1, kShadowColor); s.vLine(_x, _y, _y + _h - 1, kColor); s.vLine(_x + _w - 1, _y, _y + _h - 1, kShadowColor); #else s.frameRect(_x, _y, _w, _h, kColor); #endif // Draw the text adjustOffset(); s.drawString(_font, editString(), _x + 2, _y + 2, getEditRect().width(), !_changed ? _textcolor : uInt32(kDbgChangedTextColor), TextAlign::Left, -_editScrollOffset, false); // Draw the caret drawCaret(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect EditTextWidget::getEditRect() const { GUI::Rect r(2, 1, _w - 2, _h); return r; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::lostFocusWidget() { // If we loose focus, 'commit' the user changes _backupString = editString(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::startEditMode() { EditableWidget::startEditMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::endEditMode() { // Editing is always enabled } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditTextWidget::abortEditMode() { // Editing is always enabled setText(_backupString); } stella-5.1.1/src/gui/EditTextWidget.hxx000066400000000000000000000035001324334165500200100ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef EDIT_TEXT_WIDGET_HXX #define EDIT_TEXT_WIDGET_HXX #include "Rect.hxx" #include "EditableWidget.hxx" /* EditTextWidget */ class EditTextWidget : public EditableWidget { public: EditTextWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& text = ""); virtual ~EditTextWidget() = default; void setText(const string& str, bool changed = false) override; protected: void drawWidget(bool hilite) override; void lostFocusWidget() override; void startEditMode() override; void endEditMode() override; void abortEditMode() override; GUI::Rect getEditRect() const override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; protected: string _backupString; bool _changed; private: // Following constructors and assignment operators not supported EditTextWidget() = delete; EditTextWidget(const EditTextWidget&) = delete; EditTextWidget(EditTextWidget&&) = delete; EditTextWidget& operator=(const EditTextWidget&) = delete; EditTextWidget& operator=(EditTextWidget&&) = delete; }; #endif stella-5.1.1/src/gui/EditableWidget.cxx000066400000000000000000000247511324334165500177750ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Dialog.hxx" #include "StellaKeys.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "EditableWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EditableWidget::EditableWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& str) : Widget(boss, font, x, y, w, h), CommandSender(boss), _editable(true), _editString(str) { _caretVisible = false; _caretTime = 0; _caretPos = 0; _caretInverse = false; _editScrollOffset = 0; _bgcolor = kWidColor; _bgcolorhi = kWidColor; _textcolor = kTextColor; _textcolorhi = kTextColor; // By default, include all printable chars except quotes _filter = [](char c) { return isprint(c) && c != '\"'; }; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditableWidget::setText(const string& str, bool) { // Filter input string _editString = ""; for(char c: str) if(_filter(tolower(c))) _editString.push_back(c); _caretPos = int(_editString.size()); _editScrollOffset = (_font.getStringWidth(_editString) - (getEditRect().width())); if (_editScrollOffset < 0) _editScrollOffset = 0; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditableWidget::setEditable(bool editable, bool hiliteBG) { _editable = editable; if(_editable) { setFlags(WIDGET_WANTS_RAWDATA | WIDGET_RETAIN_FOCUS); _bgcolor = kWidColor; } else { clearFlags(WIDGET_WANTS_RAWDATA | WIDGET_RETAIN_FOCUS); _bgcolor = hiliteBG ? kBGColorHi : kWidColor; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::tryInsertChar(char c, int pos) { if(_filter(tolower(c))) { _editString.insert(pos, 1, c); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::handleText(char text) { if(!_editable) return true; if(tryInsertChar(text, _caretPos)) { _caretPos++; sendCommand(EditableWidget::kChangedCmd, 0, _id); setDirty(); return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::handleKeyDown(StellaKey key, StellaMod mod) { if(!_editable) return true; // Ignore all alt-mod keys if(StellaModTest::isAlt(mod)) return true; bool handled = true; bool dirty = false; switch(key) { case KBDK_RETURN: case KBDK_KP_ENTER: // confirm edit and exit editmode endEditMode(); sendCommand(EditableWidget::kAcceptCmd, 0, _id); dirty = true; break; case KBDK_ESCAPE: abortEditMode(); sendCommand(EditableWidget::kCancelCmd, 0, _id); dirty = true; break; case KBDK_BACKSPACE: dirty = killChar(-1); if(dirty) sendCommand(EditableWidget::kChangedCmd, key, _id); break; case KBDK_DELETE: dirty = killChar(+1); if(dirty) sendCommand(EditableWidget::kChangedCmd, key, _id); break; case KBDK_LEFT: if(StellaModTest::isControl(mod)) dirty = specialKeys(key); else if(_caretPos > 0) dirty = setCaretPos(_caretPos - 1); break; case KBDK_RIGHT: if(StellaModTest::isControl(mod)) dirty = specialKeys(key); else if(_caretPos < int(_editString.size())) dirty = setCaretPos(_caretPos + 1); break; case KBDK_HOME: dirty = setCaretPos(0); break; case KBDK_END: dirty = setCaretPos(int(_editString.size())); break; default: if (StellaModTest::isControl(mod)) { dirty = specialKeys(key); } else handled = false; } if (dirty) setDirty(); return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int EditableWidget::getCaretOffset() const { int caretpos = 0; for (int i = 0; i < _caretPos; i++) caretpos += _font.getCharWidth(_editString[i]); caretpos -= _editScrollOffset; return caretpos; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditableWidget::drawCaret() { // Only draw if item is visible if (!_editable || !isVisible() || !_boss->isVisible() || !_hasFocus) return; const GUI::Rect& editRect = getEditRect(); int x = editRect.left; int y = editRect.top; x += getCaretOffset(); x += _x; y += _y; FBSurface& s = _boss->dialog().surface(); s.vLine(x, y+2, y + editRect.height() - 2, kTextColorHi); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::setCaretPos(int newPos) { assert(newPos >= 0 && newPos <= int(_editString.size())); _caretPos = newPos; return adjustOffset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::adjustOffset() { // check if the caret is still within the textbox; if it isn't, // adjust _editScrollOffset // For some reason (differences in ScummVM event handling??), // this method should always return true. int caretpos = getCaretOffset(); const int editWidth = getEditRect().width(); if (caretpos < 0) { // scroll left _editScrollOffset += caretpos; } else if (caretpos >= editWidth) { // scroll right _editScrollOffset -= (editWidth - caretpos); } else if (_editScrollOffset > 0) { const int strWidth = _font.getStringWidth(_editString); if (strWidth - _editScrollOffset < editWidth) { // scroll right _editScrollOffset = (strWidth - editWidth); if (_editScrollOffset < 0) _editScrollOffset = 0; } } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::specialKeys(StellaKey key) { bool handled = true; switch (key) { case KBDK_A: setCaretPos(0); break; case KBDK_C: copySelectedText(); if(handled) sendCommand(EditableWidget::kChangedCmd, key, _id); break; case KBDK_E: setCaretPos(int(_editString.size())); break; case KBDK_D: handled = killChar(+1); if(handled) sendCommand(EditableWidget::kChangedCmd, key, _id); break; case KBDK_K: handled = killLine(+1); if(handled) sendCommand(EditableWidget::kChangedCmd, key, _id); break; case KBDK_U: handled = killLine(-1); if(handled) sendCommand(EditableWidget::kChangedCmd, key, _id); break; case KBDK_V: pasteSelectedText(); if(handled) sendCommand(EditableWidget::kChangedCmd, key, _id); break; case KBDK_W: handled = killLastWord(); if(handled) sendCommand(EditableWidget::kChangedCmd, key, _id); break; case KBDK_LEFT: handled = moveWord(-1); break; case KBDK_RIGHT: handled = moveWord(+1); break; default: handled = false; } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::killChar(int direction) { bool handled = false; if(direction == -1) // Delete previous character (backspace) { if(_caretPos > 0) { _caretPos--; _editString.erase(_caretPos, 1); handled = true; } } else if(direction == 1) // Delete next character (delete) { _editString.erase(_caretPos, 1); handled = true; } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::killLine(int direction) { bool handled = false; if(direction == -1) // erase from current position to beginning of line { int count = _caretPos; if(count > 0) { for (int i = 0; i < count; i++) killChar(-1); handled = true; } } else if(direction == 1) // erase from current position to end of line { int count = int(_editString.size()) - _caretPos; if(count > 0) { for (int i = 0; i < count; i++) killChar(+1); handled = true; } } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::killLastWord() { bool handled = false; int count = 0, currentPos = _caretPos; bool space = true; while (currentPos > 0) { if (_editString[currentPos - 1] == ' ') { if (!space) break; } else space = false; currentPos--; count++; } if(count > 0) { for (int i = 0; i < count; i++) killChar(-1); handled = true; } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EditableWidget::moveWord(int direction) { bool handled = false; bool space = true; int currentPos = _caretPos; if(direction == -1) // move to first character of previous word { while (currentPos > 0) { if (_editString[currentPos - 1] == ' ') { if (!space) break; } else space = false; currentPos--; } _caretPos = currentPos; handled = true; } else if(direction == +1) // move to first character of next word { while (currentPos < int(_editString.size())) { if (_editString[currentPos - 1] == ' ') { if (!space) break; } else space = false; currentPos++; } _caretPos = currentPos; handled = true; } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditableWidget::copySelectedText() { _clippedText = _editString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EditableWidget::pasteSelectedText() { _editString = _clippedText; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string EditableWidget::_clippedText = ""; stella-5.1.1/src/gui/EditableWidget.hxx000066400000000000000000000072231324334165500177750ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef EDITABLE_WIDGET_HXX #define EDITABLE_WIDGET_HXX #include #include "Widget.hxx" #include "Rect.hxx" /** * Base class for widgets which need to edit text, like ListWidget and * EditTextWidget. * * Widgets wishing to enforce their own editing restrictions are able * to use a 'TextFilter' as described below. */ class EditableWidget : public Widget, public CommandSender { public: /** Function used to test if a specified character can be inserted into the internal buffer */ using TextFilter = std::function; enum { kAcceptCmd = 'EDac', kCancelCmd = 'EDcl', kChangedCmd = 'EDch' }; public: EditableWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& str = ""); virtual ~EditableWidget() = default; virtual void setText(const string& str, bool changed = false); const string& getText() const { return _editString; } bool isEditable() const { return _editable; } virtual void setEditable(bool editable, bool hiliteBG = false); bool handleText(char text) override; bool handleKeyDown(StellaKey key, StellaMod mod) override; // We only want to focus this widget when we can edit its contents bool wantsFocus() const override { return _editable; } // Set filter used to test whether a character can be inserted void setTextFilter(const TextFilter& filter) { _filter = filter; } protected: virtual void startEditMode() { setFlags(WIDGET_WANTS_RAWDATA); } virtual void endEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); } virtual void abortEditMode() { clearFlags(WIDGET_WANTS_RAWDATA); } virtual GUI::Rect getEditRect() const = 0; virtual int getCaretOffset() const; void drawCaret(); bool setCaretPos(int newPos); bool adjustOffset(); // This method is used internally by child classes wanting to // access/edit the internal buffer string& editString() { return _editString; } private: // Line editing bool specialKeys(StellaKey key); bool killChar(int direction); bool killLine(int direction); bool killLastWord(); bool moveWord(int direction); // Clipboard void copySelectedText(); void pasteSelectedText(); // Use the current TextFilter to insert a character into the // internal buffer bool tryInsertChar(char c, int pos); private: bool _editable; string _editString; bool _caretVisible; int _caretTime; int _caretPos; protected: bool _caretInverse; int _editScrollOffset; static string _clippedText; private: TextFilter _filter; private: // Following constructors and assignment operators not supported EditableWidget() = delete; EditableWidget(const EditableWidget&) = delete; EditableWidget(EditableWidget&&) = delete; EditableWidget& operator=(const EditableWidget&) = delete; EditableWidget& operator=(EditableWidget&&) = delete; }; #endif stella-5.1.1/src/gui/EventMappingWidget.cxx000066400000000000000000000301451324334165500206530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "bspf.hxx" #include "EventHandler.hxx" #include "Event.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "StringListWidget.hxx" #include "Widget.hxx" #include "Font.hxx" #include "ComboDialog.hxx" #include "Variant.hxx" #include "EventMappingWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - EventMappingWidget::EventMappingWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const StringList& actions, EventMode mode) : Widget(boss, font, x, y, w, h), CommandSender(boss), myComboDialog(nullptr), myEventMode(mode), myActionSelected(-1), myRemapStatus(false), myLastStick(0), myLastAxis(0), myLastHat(0), myLastValue(0), myFirstTime(true) { const int fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), buttonWidth = font.getStringWidth("Defaults") + 10, buttonHeight = font.getLineHeight() + 4; int xpos = 5, ypos = 5; myActionsList = new StringListWidget(boss, font, xpos, ypos, _w - buttonWidth - 20, _h - 3*lineHeight); myActionsList->setTarget(this); myActionsList->setEditable(false); myActionsList->setList(actions); addFocusWidget(myActionsList); // Add remap, erase, cancel and default buttons xpos += myActionsList->getWidth() + 5; ypos += 5; myMapButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Map" + ELLIPSIS, kStartMapCmd); myMapButton->setTarget(this); addFocusWidget(myMapButton); ypos += lineHeight + 10; myCancelMapButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Cancel", kStopMapCmd); myCancelMapButton->setTarget(this); myCancelMapButton->clearFlags(WIDGET_ENABLED); addFocusWidget(myCancelMapButton); ypos += lineHeight + 20; myEraseButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Erase", kEraseCmd); myEraseButton->setTarget(this); addFocusWidget(myEraseButton); ypos += lineHeight + 10; myResetButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Reset", kResetCmd); myResetButton->setTarget(this); addFocusWidget(myResetButton); if(mode == kEmulationMode) { ypos += lineHeight + 20; myComboButton = new ButtonWidget(boss, font, xpos, ypos, buttonWidth, buttonHeight, "Combo" + ELLIPSIS, kComboCmd); myComboButton->setTarget(this); addFocusWidget(myComboButton); VariantList combolist = instance().eventHandler().getComboList(mode); myComboDialog = new ComboDialog(boss, font, combolist); } else myComboButton = nullptr; // Show message for currently selected event xpos = 10; ypos = 5 + myActionsList->getHeight() + 5; StaticTextWidget* t; t = new StaticTextWidget(boss, font, xpos, ypos+2, font.getStringWidth("Action"), fontHeight, "Action", TextAlign::Left); myKeyMapping = new EditTextWidget(boss, font, xpos + t->getWidth() + 8, ypos, _w - xpos - t->getWidth() - 15, lineHeight, ""); myKeyMapping->setEditable(false, true); myKeyMapping->clearFlags(WIDGET_RETAIN_FOCUS); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::loadConfig() { if(myFirstTime) { myActionsList->setSelected(0); myFirstTime = false; } // Make sure remapping is turned off, just in case the user didn't properly // exit last time if(myRemapStatus) stopRemapping(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::saveConfig() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::setDefaults() { instance().eventHandler().setDefaultMapping(Event::NoType, myEventMode); drawKeyMapping(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::startRemapping() { if(myActionSelected < 0 || myRemapStatus) return; // Set the flags for the next event that arrives myRemapStatus = true; // Reset all previous events for determining correct axis/hat values myLastStick = myLastAxis = myLastHat = myLastValue = -1; // Disable all other widgets while in remap mode, except enable 'Cancel' enableButtons(false); // And show a message indicating which key is being remapped ostringstream buf; buf << "Select action for '" << instance().eventHandler().actionAtIndex(myActionSelected, myEventMode) << "' event"; myKeyMapping->setTextColor(kTextColorEm); myKeyMapping->setText(buf.str()); // Make sure that this widget receives all raw data, before any // pre-processing occurs myActionsList->setFlags(WIDGET_WANTS_RAWDATA); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::eraseRemapping() { if(myActionSelected < 0) return; Event::Type event = instance().eventHandler().eventAtIndex(myActionSelected, myEventMode); instance().eventHandler().eraseMapping(event, myEventMode); drawKeyMapping(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::resetRemapping() { if(myActionSelected < 0) return; Event::Type event = instance().eventHandler().eventAtIndex(myActionSelected, myEventMode); instance().eventHandler().setDefaultMapping(event, myEventMode); drawKeyMapping(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::stopRemapping() { // Turn off remap mode myRemapStatus = false; // Reset all previous events for determining correct axis/hat values myLastStick = myLastAxis = myLastHat = myLastValue = -1; // And re-enable all the widgets enableButtons(true); // Make sure the list widget is in a known state drawKeyMapping(); // Widget is now free to process events normally myActionsList->clearFlags(WIDGET_WANTS_RAWDATA); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::drawKeyMapping() { if(myActionSelected >= 0) { myKeyMapping->setTextColor(kTextColor); myKeyMapping->setText(instance().eventHandler().keyAtIndex(myActionSelected, myEventMode)); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::enableButtons(bool state) { myActionsList->setEnabled(state); myMapButton->setEnabled(state); myCancelMapButton->setEnabled(!state); myEraseButton->setEnabled(state); myResetButton->setEnabled(state); if(myComboButton) { Event::Type e = instance().eventHandler().eventAtIndex(myActionSelected, myEventMode); myComboButton->setEnabled(state && e >= Event::Combo1 && e <= Event::Combo16); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventMappingWidget::handleKeyDown(StellaKey key, StellaMod mod) { // Remap keys in remap mode if(myRemapStatus && myActionSelected >= 0) { Event::Type event = instance().eventHandler().eventAtIndex(myActionSelected, myEventMode); if(instance().eventHandler().addKeyMapping(event, myEventMode, key)) stopRemapping(); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::handleJoyDown(int stick, int button) { // Remap joystick buttons in remap mode if(myRemapStatus && myActionSelected >= 0) { Event::Type event = instance().eventHandler().eventAtIndex(myActionSelected, myEventMode); if(instance().eventHandler().addJoyButtonMapping(event, myEventMode, stick, button)) stopRemapping(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::handleJoyAxis(int stick, int axis, int value) { // Remap joystick axes in remap mode // There are two phases to detection: // First, detect an axis 'on' event // Then, detect the same axis 'off' event if(myRemapStatus && myActionSelected >= 0) { // Detect the first axis event that represents 'on' if(myLastStick == -1 && myLastAxis == -1 && value != 0) { myLastStick = stick; myLastAxis = axis; myLastValue = value; } // Detect the first axis event that matches a previously set // stick and axis, but turns the axis 'off' else if(myLastStick == stick && axis == myLastAxis && value == 0) { value = myLastValue; Event::Type event = instance().eventHandler().eventAtIndex(myActionSelected, myEventMode); if(instance().eventHandler().addJoyAxisMapping(event, myEventMode, stick, axis, value)) stopRemapping(); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool EventMappingWidget::handleJoyHat(int stick, int hat, JoyHat value) { // Remap joystick hats in remap mode // There are two phases to detection: // First, detect a hat direction event // Then, detect the same hat 'center' event if(myRemapStatus && myActionSelected >= 0) { // Detect the first hat event that represents a valid direction if(myLastStick == -1 && myLastHat == -1 && value != JoyHat::CENTER) { myLastStick = stick; myLastHat = hat; myLastValue = int(value); return true; } // Detect the first hat event that matches a previously set // stick and hat, but centers the hat else if(myLastStick == stick && hat == myLastHat && value == JoyHat::CENTER) { value = JoyHat(myLastValue); Event::Type event = instance().eventHandler().eventAtIndex(myActionSelected, myEventMode); if(instance().eventHandler().addJoyHatMapping(event, myEventMode, stick, hat, value)) { stopRemapping(); return true; } } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void EventMappingWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case ListWidget::kSelectionChangedCmd: if(myActionsList->getSelected() >= 0) { myActionSelected = myActionsList->getSelected(); drawKeyMapping(); enableButtons(true); } break; /* case ListWidget::kDoubleClickedCmd: if(myActionsList->getSelected() >= 0) { myActionSelected = myActionsList->getSelected(); startRemapping(); } break; */ case kStartMapCmd: startRemapping(); break; case kStopMapCmd: stopRemapping(); break; case kEraseCmd: eraseRemapping(); break; case kResetCmd: resetRemapping(); break; case kComboCmd: if(myComboDialog) myComboDialog->show( instance().eventHandler().eventAtIndex(myActionSelected, myEventMode), instance().eventHandler().actionAtIndex(myActionSelected, myEventMode)); break; } } stella-5.1.1/src/gui/EventMappingWidget.hxx000066400000000000000000000071501324334165500206600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef EVENT_MAPPING_WIDGET_HXX #define EVENT_MAPPING_WIDGET_HXX class DialogContainer; class CommandSender; class ButtonWidget; class EditTextWidget; class StaticTextWidget; class StringListWidget; class PopUpWidget; class GuiObject; class ComboDialog; class InputDialog; #include "Widget.hxx" #include "Command.hxx" #include "bspf.hxx" class EventMappingWidget : public Widget, public CommandSender { friend class InputDialog; public: EventMappingWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const StringList& actions, EventMode mode); virtual ~EventMappingWidget() = default; bool remapMode() { return myRemapStatus; } void setDefaults(); private: enum { kStartMapCmd = 'map ', kStopMapCmd = 'smap', kEraseCmd = 'eras', kResetCmd = 'rest', kComboCmd = 'cmbo' }; bool handleKeyDown(StellaKey key, StellaMod mod) override; void handleJoyDown(int stick, int button) override; void handleJoyAxis(int stick, int axis, int value) override; bool handleJoyHat(int stick, int hat, JoyHat value) override; void loadConfig() override; void saveConfig(); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void startRemapping(); void eraseRemapping(); void resetRemapping(); void stopRemapping(); void drawKeyMapping(); void enableButtons(bool state); private: ButtonWidget* myMapButton; ButtonWidget* myCancelMapButton; ButtonWidget* myEraseButton; ButtonWidget* myResetButton; ButtonWidget* myComboButton; StringListWidget* myActionsList; EditTextWidget* myKeyMapping; ComboDialog* myComboDialog; // Since this widget can be used for different collections of events, // we need to specify exactly which group of events we are remapping EventMode myEventMode; // Indicates the event that is currently selected int myActionSelected; // Indicates if we're currently in remap mode // In this mode, the next event received is remapped to some action bool myRemapStatus; // Joystick axes and hats can be more problematic than ordinary buttons // or keys, in that there can be 'drift' in the values // Therefore, we map these events when they've been 'released', rather // than on their first occurrence (aka, when they're 'pressed') // As a result, we need to keep track of their old values int myLastStick, myLastAxis, myLastHat, myLastValue; bool myFirstTime; private: // Following constructors and assignment operators not supported EventMappingWidget() = delete; EventMappingWidget(const EventMappingWidget&) = delete; EventMappingWidget(EventMappingWidget&&) = delete; EventMappingWidget& operator=(const EventMappingWidget&) = delete; EventMappingWidget& operator=(EventMappingWidget&&) = delete; }; #endif stella-5.1.1/src/gui/FileListWidget.cxx000066400000000000000000000072131324334165500177710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "ScrollBarWidget.hxx" #include "FileListWidget.hxx" #include "bspf.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FileListWidget::FileListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : StringListWidget(boss, font, x, y, w, h), _fsmode(FilesystemNode::kListAll), _extension("") { // This widget is special, in that it catches signals and redirects them setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FileListWidget::setLocation(const FilesystemNode& node, string select) { _node = node; // Generally, we always want a directory listing if(!_node.isDirectory() && _node.hasParent()) { select = _node.getName(); _node = _node.getParent(); } // Start with empty list _gameList.clear(); // Read in the data from the file system FSList content; content.reserve(512); _node.getChildren(content, _fsmode); // Add '[..]' to indicate previous folder if(_node.hasParent()) _gameList.appendGame(" [..]", _node.getParent().getPath(), "", true); // Now add the directory entries for(const auto& file: content) { string name = file.getName(); bool isDir = file.isDirectory(); if(isDir) name = " [" + name + "]"; else if(!BSPF::endsWithIgnoreCase(name, _extension)) continue; _gameList.appendGame(name, file.getPath(), "", isDir); } _gameList.sortByName(); // Now fill the list widget with the contents of the GameList StringList l; for(uInt32 i = 0; i < _gameList.size(); ++i) l.push_back(_gameList.name(i)); setList(l); setSelected(select); ListWidget::recalc(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FileListWidget::selectParent() { if(_node.hasParent()) { const string& curr = " [" + _node.getName() + "]"; setLocation(_node.getParent(), curr); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FileListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case ListWidget::kPrevDirCmd: selectParent(); break; case ListWidget::kSelectionChangedCmd: cmd = ItemChanged; _selected = FilesystemNode(_gameList.path(data)); break; case ListWidget::kActivatedCmd: case ListWidget::kDoubleClickedCmd: if(_gameList.isDir(data)) { cmd = ItemChanged; if(_gameList.name(data) == " [..]") selectParent(); else setLocation(FilesystemNode(_gameList.path(data))); } else cmd = ItemActivated; break; default: // If we don't know about the command, send it to the parent and exit StringListWidget::handleCommand(sender, cmd, data, id); return; } // Send command to boss, then revert to target 'this' setTarget(_boss); sendCommand(cmd, data, id); setTarget(this); } stella-5.1.1/src/gui/FileListWidget.hxx000066400000000000000000000055641324334165500200050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FILE_LIST_WIDGET_HXX #define FILE_LIST_WIDGET_HXX class CommandSender; #include "FSNode.hxx" #include "GameList.hxx" #include "StringListWidget.hxx" /** Provides an encapsulation of a file listing, allowing to descend into directories, and send signals based on whether an item is selected or activated. When the signals ItemChanged and ItemActivated are emitted, the caller can query the selected() and/or currentDir() methods to determine the current state. Note that for the current implementation, the ItemActivated signal is not sent when activating a directory (instead the code descends into the directory). This may be changed in a future revision. */ class FileListWidget : public StringListWidget { public: enum { ItemChanged = 'FLic', // Entry in the list is changed (single-click, etc) ItemActivated = 'FLac' // Entry in the list is activated (double-click, etc) }; public: FileListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~FileListWidget() = default; /** Determines how to display files/folders */ void setFileListMode(FilesystemNode::ListMode mode) { _fsmode = mode; } void setFileExtension(const string& ext) { _extension = ext; } /** Set current location (file or directory) */ void setLocation(const FilesystemNode& node, string select = ""); /** Select parent directory (if applicable) */ void selectParent(); /** Gets current node(s) */ const FilesystemNode& selected() const { return _selected; } const FilesystemNode& currentDir() const { return _node; } protected: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: FilesystemNode::ListMode _fsmode; FilesystemNode _node, _selected; string _extension; GameList _gameList; private: // Following constructors and assignment operators not supported FileListWidget() = delete; FileListWidget(const FileListWidget&) = delete; FileListWidget(FileListWidget&&) = delete; FileListWidget& operator=(const FileListWidget&) = delete; FileListWidget& operator=(FileListWidget&&) = delete; }; #endif stella-5.1.1/src/gui/Font.cxx000066400000000000000000000035741324334165500160260ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #include "Font.hxx" namespace GUI { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Font::Font(FontDesc desc) : myFontDesc(desc) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Font::getCharWidth(uInt8 chr) const { // If no width table is specified, return the maximum width if(!myFontDesc.width) return myFontDesc.maxwidth; // If this character is not included in the font, use the default char. if(chr < myFontDesc.firstchar || myFontDesc.firstchar + myFontDesc.size < chr) { if(chr == ' ') return myFontDesc.maxwidth / 2; chr = myFontDesc.defaultchar; } return myFontDesc.width[chr - myFontDesc.firstchar]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int Font::getStringWidth(const string& str) const { // If no width table is specified, use the maximum width if(!myFontDesc.width) return myFontDesc.maxwidth * int(str.size()); else { int space = 0; for(auto c: str) space += getCharWidth(c); return space; } } } // namespace GUI stella-5.1.1/src/gui/Font.hxx000066400000000000000000000052051324334165500160240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef FONT_HXX #define FONT_HXX #include "bspf.hxx" struct BBX { Int8 w; Int8 h; Int8 x; Int8 y; }; /* builtin C-based proportional/fixed font structure */ /* based on The Microwindows Project http://microwindows.org */ struct FontDesc { const char* const name; /* font name */ int maxwidth; /* max width in pixels */ int height; /* height in pixels */ int fbbw, fbbh, fbbx, fbby; /* max bounding box */ int ascent; /* ascent (baseline) height */ int firstchar; /* first character in bitmap */ int size; /* font size in glyphs */ const uInt16* bits; /* 16-bit right-padded bitmap data */ const uInt32* offset; /* offsets into bitmap data*/ const uInt8* width; /* character widths or nullptr if fixed */ const BBX* bbx; /* character bounding box or nullptr if fixed */ int defaultchar; /* default char (not glyph index) */ long bits_size; /* # words of bitmap_t bits */ }; namespace GUI { class Font { public: Font(FontDesc desc); const FontDesc& desc() const { return myFontDesc; } int getFontHeight() const { return myFontDesc.height; } int getLineHeight() const { return myFontDesc.height + 2; } int getMaxCharWidth() const { return myFontDesc.maxwidth; } int getCharWidth(uInt8 chr) const; int getStringWidth(const string& str) const; private: FontDesc myFontDesc; private: // Following constructors and assignment operators not supported Font() = delete; Font(const Font&) = delete; Font(Font&&) = delete; Font& operator=(const Font&) = delete; Font& operator=(Font&&) = delete; }; } // namespace GUI #endif stella-5.1.1/src/gui/GameInfoDialog.cxx000066400000000000000000000631101324334165500177150ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "BSType.hxx" #include "Console.hxx" #include "MouseControl.hxx" #include "SaveKey.hxx" #include "Dialog.hxx" #include "EditTextWidget.hxx" #include "Launcher.hxx" #include "OSystem.hxx" #include "PopUpWidget.hxx" #include "Props.hxx" #include "PropsSet.hxx" #include "TabWidget.hxx" #include "TIAConstants.hxx" #include "Widget.hxx" #include "Font.hxx" #include "GameInfoDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GameInfoDialog::GameInfoDialog( OSystem& osystem, DialogContainer& parent, const GUI::Font& font, GuiObject* boss) : Dialog(osystem, parent), CommandSender(boss), myPropertiesLoaded(false), myDefaultsSelected(false) { const GUI::Font& ifont = instance().frameBuffer().infoFont(); const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; const int vBorder = 4; const int hBorder = 2; const int hSpace = 10; const int vGap = 4; int xpos, ypos, lwidth, fwidth, pwidth, tabID; WidgetArray wid; VariantList items, ports, ctrls; StaticTextWidget* t; // Set real dimensions _w = 52 * fontWidth + 8; _h = 9 * (lineHeight + vGap) + vBorder * 2 + buttonHeight + fontHeight + ifont.getLineHeight() + 20; // The tab widget xpos = hBorder; ypos = vBorder; myTab = new TabWidget(this, font, xpos, ypos, _w - 2 * hBorder, _h - (buttonHeight + fontHeight + ifont.getLineHeight() + 20)); addTabWidget(myTab); // 1) Cartridge properties tabID = myTab->addTab("Cartridge"); xpos = hSpace; lwidth = font.getStringWidth("Manufacturer "); fwidth = _w - xpos - lwidth - hSpace - hBorder * 2; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Name", TextAlign::Left); myName = new EditTextWidget(myTab, font, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); wid.push_back(myName); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "MD5", TextAlign::Left); myMD5 = new EditTextWidget(myTab, font, xpos + lwidth, ypos-1, fwidth, lineHeight, ""); myMD5->setEditable(false); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Manufacturer", TextAlign::Left); myManufacturer = new EditTextWidget(myTab, font, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); wid.push_back(myManufacturer); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Model", TextAlign::Left); myModelNo = new EditTextWidget(myTab, font, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); wid.push_back(myModelNo); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Rarity", TextAlign::Left); myRarity = new EditTextWidget(myTab, font, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); wid.push_back(myRarity); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Note", TextAlign::Left); myNote = new EditTextWidget(myTab, font, xpos+lwidth, ypos-1, fwidth, lineHeight, ""); wid.push_back(myNote); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Sound", TextAlign::Left); pwidth = font.getStringWidth("Stereo"); items.clear(); VarList::push_back(items, "Mono", "MONO"); VarList::push_back(items, "Stereo", "STEREO"); mySound = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(mySound); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Type", TextAlign::Left); pwidth = font.getStringWidth("CM (SpectraVideo CompuMate)"); items.clear(); for(int i = 0; i < int(BSType::NumSchemes); ++i) VarList::push_back(items, BSList[i].desc, BSList[i].name); myType = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myType); // Add items for tab 0 addToFocusList(wid, myTab, tabID); // 2) Console properties wid.clear(); tabID = myTab->addTab("Console"); xpos = hSpace; ypos = vBorder; lwidth = font.getStringWidth("Right Difficulty "); pwidth = font.getStringWidth("B & W"); new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Left Difficulty", TextAlign::Left); items.clear(); VarList::push_back(items, "B", "B"); VarList::push_back(items, "A", "A"); myLeftDiff = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myLeftDiff); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "Right Difficulty", TextAlign::Left); // ... use same items as above myRightDiff = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myRightDiff); ypos += lineHeight + vGap; new StaticTextWidget(myTab, font, xpos, ypos+1, lwidth, fontHeight, "TV Type", TextAlign::Left); items.clear(); VarList::push_back(items, "Color", "COLOR"); VarList::push_back(items, "B & W", "BW"); myTVType = new PopUpWidget(myTab, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myTVType); // Add items for tab 1 addToFocusList(wid, myTab, tabID); // 3) Controller properties wid.clear(); tabID = myTab->addTab("Controller"); ypos = vBorder; pwidth = font.getStringWidth("Paddles_IAxis"); myP0Label = new StaticTextWidget(myTab, font, hSpace, ypos+1, "P0 Controller ", TextAlign::Left); ctrls.clear(); VarList::push_back(ctrls, "Joystick", "JOYSTICK" ); VarList::push_back(ctrls, "Paddles", "PADDLES" ); VarList::push_back(ctrls, "Paddles_IAxis", "PADDLES_IAXIS"); VarList::push_back(ctrls, "Paddles_IDir", "PADDLES_IDIR" ); VarList::push_back(ctrls, "Paddles_IAxDr", "PADDLES_IAXDR"); VarList::push_back(ctrls, "BoosterGrip", "BOOSTERGRIP" ); VarList::push_back(ctrls, "Driving", "DRIVING" ); VarList::push_back(ctrls, "Keyboard", "KEYBOARD" ); VarList::push_back(ctrls, "AmigaMouse", "AMIGAMOUSE" ); VarList::push_back(ctrls, "AtariMouse", "ATARIMOUSE" ); VarList::push_back(ctrls, "Trakball", "TRAKBALL" ); VarList::push_back(ctrls, "AtariVox", "ATARIVOX" ); VarList::push_back(ctrls, "SaveKey", "SAVEKEY" ); VarList::push_back(ctrls, "Sega Genesis", "GENESIS" ); // VarList::push_back(ctrls, "KidVid", "KIDVID" ); VarList::push_back(ctrls, "MindLink", "MINDLINK" ); myP0Controller = new PopUpWidget(myTab, font, myP0Label->getRight(), myP0Label->getTop()-1, pwidth, lineHeight, ctrls, "", 0, kLeftCChanged); wid.push_back(myP0Controller); ypos += lineHeight + vGap; pwidth = font.getStringWidth("Paddles_IAxis"); myP1Label = new StaticTextWidget(myTab, font, hSpace, ypos+1, "P1 Controller ", TextAlign::Left); myP1Controller = new PopUpWidget(myTab, font, myP1Label->getRight(), myP1Label->getTop()-1, pwidth, lineHeight, ctrls, "", 0, kRightCChanged); wid.push_back(myP1Controller); //ypos += lineHeight + vGap; mySwapPorts = new CheckboxWidget(myTab, font, myP0Controller->getRight() + fontWidth*5, myP0Controller->getTop()+1, "Swap Ports"); wid.push_back(mySwapPorts); //ypos += lineHeight + vGap; mySwapPaddles = new CheckboxWidget(myTab, font, myP1Controller->getRight() + fontWidth*5, myP1Controller->getTop()+1, "Swap Paddles"); wid.push_back(mySwapPaddles); // EEPROM erase button for P0 ypos += lineHeight + vGap + 4; myEraseEEPROMLabel = new StaticTextWidget(myTab, font, hSpace, ypos, "AtariVox/SaveKey "); myEraseEEPROMButton = new ButtonWidget(myTab, font, myEraseEEPROMLabel->getRight(), ypos - 4, "Erase EEPROM", kEEButtonPressed); myEraseEEPROMInfo = new StaticTextWidget(myTab, ifont, myEraseEEPROMButton->getRight() + 4, myEraseEEPROMLabel->getTop() + 3, "(for this game only)"); ypos += lineHeight + vGap * 4; lwidth = font.getStringWidth("Mouse axis mode "); pwidth = font.getStringWidth("Specific axis"); items.clear(); VarList::push_back(items, "Automatic", "AUTO"); VarList::push_back(items, "Specific axis", "specific"); myMouseControl = new PopUpWidget(myTab, font, hSpace, ypos, pwidth, lineHeight, items, "Mouse axis mode ", lwidth, kMCtrlChanged); wid.push_back(myMouseControl); // Mouse controller specific axis pwidth = font.getStringWidth("MindLink 0"); items.clear(); VarList::push_back(items, "None", MouseControl::NoControl); VarList::push_back(items, "Paddle 0", MouseControl::Paddle0); VarList::push_back(items, "Paddle 1", MouseControl::Paddle1); VarList::push_back(items, "Paddle 2", MouseControl::Paddle2); VarList::push_back(items, "Paddle 3", MouseControl::Paddle3); VarList::push_back(items, "Driving 0", MouseControl::Driving0); VarList::push_back(items, "Driving 1", MouseControl::Driving1); VarList::push_back(items, "MindLink 0", MouseControl::MindLink0); VarList::push_back(items, "MindLink 1", MouseControl::MindLink1); xpos = hSpace + lwidth; lwidth = font.getStringWidth("X-Axis is "); xpos -= lwidth; ypos += lineHeight + vGap; myMouseX = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "X-Axis is "); wid.push_back(myMouseX); ypos += lineHeight + vGap; myMouseY = new PopUpWidget(myTab, font, myMouseX->getLeft(), ypos, pwidth, lineHeight, items, "Y-Axis is "); wid.push_back(myMouseY); xpos = hSpace; ypos += lineHeight + vGap; lwidth = font.getStringWidth("Mouse axis range "); myMouseRange = new SliderWidget(myTab, font, hSpace, ypos, 8*fontWidth, lineHeight, "Mouse axis range ", lwidth, kMRangeChanged); myMouseRange->setMinValue(1); myMouseRange->setMaxValue(100); wid.push_back(myMouseRange); myMouseRangeLabel = new StaticTextWidget(myTab, font, myMouseRange->getRight() + 4, myMouseRange->getTop()+1, " ", TextAlign::Left); // Add items for tab 2 addToFocusList(wid, myTab, tabID); // 4) Display properties wid.clear(); tabID = myTab->addTab("Display"); ypos = vBorder; pwidth = font.getStringWidth("Auto-detect"); t = new StaticTextWidget(myTab, font, hSpace, ypos+1, "Format ", TextAlign::Left); items.clear(); VarList::push_back(items, "Auto-detect", "AUTO"); VarList::push_back(items, "NTSC", "NTSC"); VarList::push_back(items, "PAL", "PAL"); VarList::push_back(items, "SECAM", "SECAM"); VarList::push_back(items, "NTSC50", "NTSC50"); VarList::push_back(items, "PAL60", "PAL60"); VarList::push_back(items, "SECAM60", "SECAM60"); myFormat = new PopUpWidget(myTab, font, t->getRight(), ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myFormat); ypos += lineHeight + vGap; t = new StaticTextWidget(myTab, font, hSpace, ypos+1, "YStart ", TextAlign::Left); myYStart = new SliderWidget(myTab, font, t->getRight(), ypos, 8*fontWidth, lineHeight, "", 0, kYStartChanged); myYStart->setMinValue(TIAConstants::minYStart-1); myYStart->setMaxValue(TIAConstants::maxYStart); wid.push_back(myYStart); myYStartLabel = new StaticTextWidget(myTab, font, myYStart->getRight() + 4, ypos+1, 5*fontWidth, fontHeight, "", TextAlign::Left); ypos += lineHeight + vGap; t = new StaticTextWidget(myTab, font, hSpace, ypos+1, "Height ", TextAlign::Left); myHeight = new SliderWidget(myTab, font, t->getRight(), ypos, 8*fontWidth, lineHeight, "", 0, kHeightChanged); myHeight->setMinValue(TIAConstants::minViewableHeight-1); myHeight->setMaxValue(TIAConstants::maxViewableHeight); wid.push_back(myHeight); myHeightLabel = new StaticTextWidget(myTab, font, myHeight->getRight() + 4, ypos+1, 5*fontWidth, fontHeight, "", TextAlign::Left); // Phosphor ypos += lineHeight + vGap*4; myPhosphor = new CheckboxWidget(myTab, font, hSpace, ypos+1, "Use Phosphor", kPhosphorChanged); wid.push_back(myPhosphor); myPPBlend = new SliderWidget(myTab, font, myPhosphor->getRight() + 16, myPhosphor->getTop()-2, 8*fontWidth, lineHeight, "Blend ", font.getStringWidth("Blend "), kPPBlendChanged); myPPBlend->setMinValue(0); myPPBlend->setMaxValue(100); wid.push_back(myPPBlend); myPPBlendLabel = new StaticTextWidget(myTab, font, myPPBlend->getRight() + 4, myPhosphor->getTop(), 5*fontWidth, fontHeight, "", TextAlign::Left); // Add items for tab 3 addToFocusList(wid, myTab, tabID); // Activate the first tab myTab->setActiveTab(0); // Add message concerning usage lwidth = ifont.getStringWidth("(*) Changes to properties require a ROM reload"); new StaticTextWidget(this, ifont, hSpace, _h - (buttonHeight + fontHeight + 20), lwidth, fontHeight, "(*) Changes to properties require a ROM reload", TextAlign::Left); // Add Defaults, OK and Cancel buttons wid.clear(); ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::loadConfig() { myPropertiesLoaded = false; myDefaultsSelected = false; if(instance().hasConsole()) { myGameProperties = instance().console().properties(); myPropertiesLoaded = true; loadView(); } else { const string& md5 = instance().launcher().selectedRomMD5(); if(md5 != "") { instance().propSet().getMD5(md5, myGameProperties); myPropertiesLoaded = true; loadView(); } } updateControllerStates(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::loadView() { if(!myPropertiesLoaded) return; // Cartridge properties myName->setText(myGameProperties.get(Cartridge_Name)); myMD5->setText(myGameProperties.get(Cartridge_MD5)); myManufacturer->setText(myGameProperties.get(Cartridge_Manufacturer)); myModelNo->setText(myGameProperties.get(Cartridge_ModelNo)); myRarity->setText(myGameProperties.get(Cartridge_Rarity)); myNote->setText(myGameProperties.get(Cartridge_Note)); mySound->setSelected(myGameProperties.get(Cartridge_Sound), "MONO"); myType->setSelected(myGameProperties.get(Cartridge_Type), "AUTO"); // Console properties myLeftDiff->setSelected(myGameProperties.get(Console_LeftDifficulty), "B"); myRightDiff->setSelected(myGameProperties.get(Console_RightDifficulty), "B"); myTVType->setSelected(myGameProperties.get(Console_TelevisionType), "COLOR"); // Controller properties myP0Controller->setSelected(myGameProperties.get(Controller_Left), "JOYSTICK"); myP1Controller->setSelected(myGameProperties.get(Controller_Right), "JOYSTICK"); mySwapPorts->setState(myGameProperties.get(Console_SwapPorts) == "YES"); mySwapPaddles->setState(myGameProperties.get(Controller_SwapPaddles) == "YES"); // MouseAxis property (potentially contains 'range' information) istringstream m_axis(myGameProperties.get(Controller_MouseAxis)); string m_control, m_range; m_axis >> m_control; bool autoAxis = BSPF::equalsIgnoreCase(m_control, "AUTO"); if(autoAxis) { myMouseControl->setSelectedIndex(0); myMouseX->setSelectedIndex(0); myMouseY->setSelectedIndex(0); } else { myMouseControl->setSelectedIndex(1); myMouseX->setSelected(m_control[0] - '0'); myMouseY->setSelected(m_control[1] - '0'); } myMouseX->setEnabled(!autoAxis); myMouseY->setEnabled(!autoAxis); if(m_axis >> m_range) { myMouseRange->setValue(atoi(m_range.c_str())); myMouseRangeLabel->setLabel(m_range); } else { myMouseRange->setValue(100); myMouseRangeLabel->setLabel("100"); } // Display properties myFormat->setSelected(myGameProperties.get(Display_Format), "AUTO"); const string& ystart = myGameProperties.get(Display_YStart); myYStart->setValue(atoi(ystart.c_str())); myYStartLabel->setLabel(ystart == "0" ? "Auto" : ystart); const string& height = myGameProperties.get(Display_Height); myHeight->setValue(atoi(height.c_str())); myHeightLabel->setLabel(height == "0" ? "Auto" : height); bool usePhosphor = myGameProperties.get(Display_Phosphor) == "YES"; myPhosphor->setState(usePhosphor); myPPBlend->setEnabled(usePhosphor); myPPBlendLabel->setEnabled(usePhosphor); const string& blend = myGameProperties.get(Display_PPBlend); myPPBlend->setValue(atoi(blend.c_str())); myPPBlendLabel->setLabel(blend == "0" ? "Auto" : blend); myTab->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::saveConfig() { if(!myPropertiesLoaded) return; // Cartridge properties myGameProperties.set(Cartridge_Name, myName->getText()); myGameProperties.set(Cartridge_Manufacturer, myManufacturer->getText()); myGameProperties.set(Cartridge_ModelNo, myModelNo->getText()); myGameProperties.set(Cartridge_Rarity, myRarity->getText()); myGameProperties.set(Cartridge_Note, myNote->getText()); myGameProperties.set(Cartridge_Sound, mySound->getSelectedTag().toString()); myGameProperties.set(Cartridge_Type, myType->getSelectedTag().toString()); // Console properties myGameProperties.set(Console_LeftDifficulty, myLeftDiff->getSelectedTag().toString()); myGameProperties.set(Console_RightDifficulty, myRightDiff->getSelectedTag().toString()); myGameProperties.set(Console_TelevisionType, myTVType->getSelectedTag().toString()); // Controller properties myGameProperties.set(Controller_Left, myP0Controller->getSelectedTag().toString()); myGameProperties.set(Controller_Right, myP1Controller->getSelectedTag().toString()); myGameProperties.set(Console_SwapPorts, (mySwapPorts->isEnabled() && mySwapPorts->getState()) ? "YES" : "NO"); myGameProperties.set(Controller_SwapPaddles, (mySwapPaddles->isEnabled() && mySwapPaddles->getState()) ? "YES" : "NO"); // MouseAxis property (potentially contains 'range' information) string mcontrol = myMouseControl->getSelectedTag().toString(); if(mcontrol != "AUTO") mcontrol = myMouseX->getSelectedTag().toString() + myMouseY->getSelectedTag().toString(); string range = myMouseRangeLabel->getLabel(); if(range != "100") mcontrol += " " + range; myGameProperties.set(Controller_MouseAxis, mcontrol); // Display properties myGameProperties.set(Display_Format, myFormat->getSelectedTag().toString()); myGameProperties.set(Display_YStart, myYStartLabel->getLabel() == "Auto" ? "0" : myYStartLabel->getLabel()); myGameProperties.set(Display_Height, myHeightLabel->getLabel() == "Auto" ? "0" : myHeightLabel->getLabel()); myGameProperties.set(Display_Phosphor, myPhosphor->getState() ? "YES" : "NO"); myGameProperties.set(Display_PPBlend, myPPBlendLabel->getLabel() == "Auto" ? "0" : myPPBlendLabel->getLabel()); // Determine whether to add or remove an entry from the properties set if(myDefaultsSelected) instance().propSet().removeMD5(myGameProperties.get(Cartridge_MD5)); else instance().propSet().insert(myGameProperties); // In any event, inform the Console if(instance().hasConsole()) instance().console().setProperties(myGameProperties); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::setDefaults() { // Load the default properties string md5 = myGameProperties.get(Cartridge_MD5); instance().propSet().getMD5(md5, myGameProperties, true); // Reload the current dialog loadView(); myDefaultsSelected = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::updateControllerStates() { const string& contrP0 = myP0Controller->getSelectedTag().toString(); const string& contrP1 = myP1Controller->getSelectedTag().toString(); bool enableEEEraseButton = false; bool enableSwapPaddles = false; bool enableSwapPorts = false; // Compumate bankswitching scheme doesn't allow to select controllers bool enableSelectControl = myType->getSelectedTag() != "CM"; enableSwapPorts = enableSelectControl; enableSwapPaddles = BSPF::startsWithIgnoreCase(contrP0, "PADDLES") || BSPF::startsWithIgnoreCase(contrP1, "PADDLES"); if(instance().hasConsole()) { const Controller& lport = instance().console().leftController(); const Controller& rport = instance().console().rightController(); // we only enable the button if we have a valid previous and new controller. enableEEEraseButton = ((lport.type() == Controller::SaveKey && contrP0 == "SAVEKEY") || (lport.type() == Controller::AtariVox && contrP0 == "ATARIVOX") || (rport.type() == Controller::SaveKey && contrP1 == "SAVEKEY") || (rport.type() == Controller::AtariVox && contrP1 == "ATARIVOX")); } myP0Label->setEnabled(enableSelectControl); myP1Label->setEnabled(enableSelectControl); myP0Controller->setEnabled(enableSelectControl); myP1Controller->setEnabled(enableSelectControl); mySwapPorts->setEnabled(enableSwapPorts); mySwapPaddles->setEnabled(enableSwapPaddles); myEraseEEPROMLabel->setEnabled(enableEEEraseButton); myEraseEEPROMButton->setEnabled(enableEEEraseButton); myEraseEEPROMInfo->setEnabled(enableEEEraseButton); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::eraseEEPROM() { Controller& lport = instance().console().leftController(); Controller& rport = instance().console().rightController(); if(lport.type() == Controller::SaveKey || lport.type() == Controller::AtariVox) { SaveKey& skey = static_cast(lport); skey.eraseCurrent(); } if(rport.type() == Controller::SaveKey || rport.type() == Controller::AtariVox) { SaveKey& skey = static_cast(rport); skey.eraseCurrent(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameInfoDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; case TabWidget::kTabChangedCmd: if(data == 2) // 'Controller' tab selected updateControllerStates(); // The underlying dialog still needs access to this command Dialog::handleCommand(sender, cmd, data, 0); break; case kLeftCChanged: case kRightCChanged: updateControllerStates(); break; case kEEButtonPressed: eraseEEPROM(); break; case kPhosphorChanged: { bool status = myPhosphor->getState(); myPPBlend->setEnabled(status); myPPBlendLabel->setEnabled(status); break; } case kYStartChanged: if(myYStart->getValue() == TIAConstants::minYStart-1) myYStartLabel->setLabel("Auto"); else myYStartLabel->setValue(myYStart->getValue()); break; case kHeightChanged: if(myHeight->getValue() == TIAConstants::minViewableHeight-1) myHeightLabel->setLabel("Auto"); else myHeightLabel->setValue(myHeight->getValue()); break; case kPPBlendChanged: if(myPPBlend->getValue() == 0) myPPBlendLabel->setLabel("Auto"); else myPPBlendLabel->setValue(myPPBlend->getValue()); break; case kMRangeChanged: myMouseRangeLabel->setValue(myMouseRange->getValue()); break; case kMCtrlChanged: { bool state = myMouseControl->getSelectedTag() != "AUTO"; myMouseX->setEnabled(state); myMouseY->setEnabled(state); break; } default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/gui/GameInfoDialog.hxx000066400000000000000000000071221324334165500177230ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef GAME_INFO_DIALOG_HXX #define GAME_INFO_DIALOG_HXX class OSystem; class GuiObject; class EditTextWidget; class PopUpWidget; class StaticTextWidget; class TabWidget; class SliderWidget; #include "Dialog.hxx" #include "Command.hxx" #include "Props.hxx" class GameInfoDialog : public Dialog, public CommandSender { public: GameInfoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, GuiObject* boss); virtual ~GameInfoDialog() = default; private: void loadConfig() override; void saveConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void setDefaults() override; void loadView(); void updateControllerStates(); void eraseEEPROM(); private: TabWidget* myTab; // Cartridge properties EditTextWidget* myName; EditTextWidget* myMD5; EditTextWidget* myManufacturer; EditTextWidget* myModelNo; EditTextWidget* myRarity; EditTextWidget* myNote; PopUpWidget* mySound; PopUpWidget* myType; // Console properties PopUpWidget* myLeftDiff; PopUpWidget* myRightDiff; PopUpWidget* myTVType; // Controller properties StaticTextWidget* myP0Label; StaticTextWidget* myP1Label; PopUpWidget* myP0Controller; PopUpWidget* myP1Controller; CheckboxWidget* mySwapPorts; CheckboxWidget* mySwapPaddles; StaticTextWidget* myEraseEEPROMLabel; ButtonWidget* myEraseEEPROMButton; StaticTextWidget* myEraseEEPROMInfo; PopUpWidget* myMouseControl; PopUpWidget* myMouseX; PopUpWidget* myMouseY; SliderWidget* myMouseRange; StaticTextWidget* myMouseRangeLabel; // Display properties PopUpWidget* myFormat; SliderWidget* myYStart; StaticTextWidget* myYStartLabel; SliderWidget* myHeight; StaticTextWidget* myHeightLabel; CheckboxWidget* myPhosphor; SliderWidget* myPPBlend; StaticTextWidget* myPPBlendLabel; enum { kLeftCChanged = 'LCch', kRightCChanged = 'RCch', kMRangeChanged = 'MRch', kYStartChanged = 'YSch', kHeightChanged = 'HTch', kPhosphorChanged = 'PPch', kPPBlendChanged = 'PBch', kMCtrlChanged = 'MCch', kEEButtonPressed = 'EEgb', }; // Game properties for currently loaded ROM Properties myGameProperties; // Indicates that we've got a valid properties entry bool myPropertiesLoaded; // Indicates that the default properties have been loaded bool myDefaultsSelected; private: // Following constructors and assignment operators not supported GameInfoDialog() = delete; GameInfoDialog(const GameInfoDialog&) = delete; GameInfoDialog(GameInfoDialog&&) = delete; GameInfoDialog& operator=(const GameInfoDialog&) = delete; GameInfoDialog& operator=(GameInfoDialog&&) = delete; }; #endif stella-5.1.1/src/gui/GameList.cxx000066400000000000000000000033701324334165500166170ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from KStella - Stella frontend // Copyright (C) 2003-2005 Stephen Anthony //============================================================================ #include #include #include "GameList.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GameList::sortByName() { if(myArray.size() < 2) return; auto cmp = [](const Entry& a, const Entry& b) { // directories always first if(a._isdir != b._isdir) return a._isdir; auto it1 = a._name.cbegin(), it2 = b._name.cbegin(); // Account for ending ']' character in directory entries auto end1 = a._isdir ? a._name.cend() - 1 : a._name.cend(); auto end2 = b._isdir ? b._name.cend() - 1 : b._name.cend(); // Stop when either string's end has been reached while((it1 != end1) && (it2 != end2)) { if(toupper(*it1) != toupper(*it2)) // letters differ? return toupper(*it1) < toupper(*it2); // proceed to the next character in each string ++it1; ++it2; } return a._name.size() < b._name.size(); }; sort(myArray.begin(), myArray.end(), cmp); } stella-5.1.1/src/gui/GameList.hxx000066400000000000000000000044151324334165500166250ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from KStella - Stella frontend // Copyright (C) 2003-2005 Stephen Anthony //============================================================================ #ifndef GAME_LIST_HXX #define GAME_LIST_HXX #include "bspf.hxx" /** Holds the list of game info for the ROM launcher. */ class GameList { public: GameList() = default; const string& name(uInt32 i) const { return i < myArray.size() ? myArray[i]._name : EmptyString; } const string& path(uInt32 i) const { return i < myArray.size() ? myArray[i]._path : EmptyString; } const string& md5(uInt32 i) const { return i < myArray.size() ? myArray[i]._md5 : EmptyString; } const bool isDir(uInt32 i) const { return i < myArray.size() ? myArray[i]._isdir: false; } void setMd5(uInt32 i, const string& md5) { myArray[i]._md5 = md5; } uInt32 size() const { return uInt32(myArray.size()); } void clear() { myArray.clear(); } void appendGame(const string& name, const string& path, const string& md5, bool isDir = false) { myArray.emplace_back(name, path, md5, isDir); } void sortByName(); private: struct Entry { string _name; string _path; string _md5; bool _isdir; Entry(string name, string path, string md5, bool isdir) : _name(name), _path(path), _md5(md5), _isdir(isdir) { } }; vector myArray; private: // Following constructors and assignment operators not supported GameList(const GameList&) = delete; GameList(GameList&&) = delete; GameList& operator=(const GameList&) = delete; GameList& operator=(GameList&&) = delete; }; #endif stella-5.1.1/src/gui/GlobalPropsDialog.cxx000066400000000000000000000264741324334165500204700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "BSType.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "PopUpWidget.hxx" #include "Settings.hxx" #include "Widget.hxx" #include "Font.hxx" #include "LauncherDialog.hxx" #include "GlobalPropsDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GlobalPropsDialog::GlobalPropsDialog(GuiObject* boss, const GUI::Font& font) : Dialog(boss->instance(), boss->parent()), CommandSender(boss) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos; int lwidth = font.getStringWidth("Right Difficulty "), pwidth = font.getStringWidth("CM (SpectraVideo CompuMate)"); WidgetArray wid; VariantList items; const GUI::Font& infofont = instance().frameBuffer().infoFont(); // Set real dimensions _w = lwidth + pwidth + fontWidth*3 + 15; _h = 17 * (lineHeight + 4) + buttonHeight + 20; xpos = 10; ypos = 10; // Bankswitch type new StaticTextWidget(this, font, xpos, ypos+1, lwidth, fontHeight, "Bankswitch type", TextAlign::Left); for(int i = 0; i < int(BSType::NumSchemes); ++i) VarList::push_back(items, BSList[i].desc, BSList[i].name); myBSType = new PopUpWidget(this, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myBSType); ypos += lineHeight + 10; // Left difficulty pwidth = font.getStringWidth("Debugger"); new StaticTextWidget(this, font, xpos, ypos+1, lwidth, fontHeight, "Left Difficulty", TextAlign::Left); items.clear(); VarList::push_back(items, "Default", "DEFAULT"); VarList::push_back(items, "B", "B"); VarList::push_back(items, "A", "A"); myLeftDiff = new PopUpWidget(this, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myLeftDiff); ypos += lineHeight + 5; // Right difficulty new StaticTextWidget(this, font, xpos, ypos+1, lwidth, fontHeight, "Right Difficulty", TextAlign::Left); // ... use same items as above myRightDiff = new PopUpWidget(this, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myRightDiff); ypos += lineHeight + 5; // TV type new StaticTextWidget(this, font, xpos, ypos+1, lwidth, fontHeight, "TV Type", TextAlign::Left); items.clear(); VarList::push_back(items, "Default", "DEFAULT"); VarList::push_back(items, "Color", "COLOR"); VarList::push_back(items, "B & W", "BW"); myTVType = new PopUpWidget(this, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myTVType); ypos += lineHeight + 10; // Start in debugger mode new StaticTextWidget(this, font, xpos, ypos+1, lwidth, fontHeight, "Startup Mode", TextAlign::Left); items.clear(); VarList::push_back(items, "Console", "false"); VarList::push_back(items, "Debugger", "true"); myDebug = new PopUpWidget(this, font, xpos+lwidth, ypos, pwidth, lineHeight, items, "", 0, 0); wid.push_back(myDebug); ypos += lineHeight + 10; // Start console with buttons held down new StaticTextWidget(this, font, xpos, ypos+1, font.getStringWidth("Start console with the following held down:"), fontHeight, "Start console with the following held down:", TextAlign::Left); xpos += 10; ypos += lineHeight; new StaticTextWidget(this, infofont, xpos, ypos+1, _w - 40, infofont.getFontHeight(), "(*) Buttons are automatically released shortly", TextAlign::Left); ypos += infofont.getLineHeight(); new StaticTextWidget(this, infofont, xpos, ypos+1, _w - 40, infofont.getFontHeight(), " after emulation has started", TextAlign::Left); // Start with console joystick direction/buttons held down xpos = 30; ypos += lineHeight + 10; ypos = addHoldWidgets(font, xpos, ypos, wid); // Add message concerning usage xpos = 10; ypos += 2 * fontHeight; new StaticTextWidget(this, infofont, xpos, ypos, _w - 20, infofont.getFontHeight(), "(*) These options are not saved, but apply to all", TextAlign::Left); ypos += infofont.getLineHeight(); new StaticTextWidget(this, infofont, xpos, ypos, _w - 20, infofont.getFontHeight(), " further ROMs until clicking 'Defaults'", TextAlign::Left); // Add Defaults, OK and Cancel buttons ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font, "Load ROM", "Close"); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int GlobalPropsDialog::addHoldWidgets(const GUI::Font& font, int x, int y, WidgetArray& wid) { const int fontHeight = font.getFontHeight(); int xpos = x, ypos = y; // Left joystick StaticTextWidget* t = new StaticTextWidget(this, font, xpos, ypos+2, font.getStringWidth("Left Joy"), fontHeight, "Left Joy", TextAlign::Left); xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 10; myJoy[kJ0Up] = new CheckboxWidget(this, font, xpos, ypos, "", kJ0Up); ypos += myJoy[kJ0Up]->getHeight() * 2 + 10; myJoy[kJ0Down] = new CheckboxWidget(this, font, xpos, ypos, "", kJ0Down); xpos -= myJoy[kJ0Up]->getWidth() + 5; ypos -= myJoy[kJ0Up]->getHeight() + 5; myJoy[kJ0Left] = new CheckboxWidget(this, font, xpos, ypos, "", kJ0Left); xpos += (myJoy[kJ0Up]->getWidth() + 5) * 2; myJoy[kJ0Right] = new CheckboxWidget(this, font, xpos, ypos, "", kJ0Right); xpos -= (myJoy[kJ0Up]->getWidth() + 5) * 2; ypos += myJoy[kJ0Down]->getHeight() * 2 + 10; myJoy[kJ0Fire] = new CheckboxWidget(this, font, xpos, ypos, "Fire", kJ0Fire); int final_y = ypos; xpos = _w / 3; ypos = y; // Right joystick t = new StaticTextWidget(this, font, xpos, ypos+2, font.getStringWidth("Right Joy"), fontHeight, "Right Joy", TextAlign::Left); xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 10; myJoy[kJ1Up] = new CheckboxWidget(this, font, xpos, ypos, "", kJ1Up); ypos += myJoy[kJ1Up]->getHeight() * 2 + 10; myJoy[kJ1Down] = new CheckboxWidget(this, font, xpos, ypos, "", kJ1Down); xpos -= myJoy[kJ1Up]->getWidth() + 5; ypos -= myJoy[kJ1Up]->getHeight() + 5; myJoy[kJ1Left] = new CheckboxWidget(this, font, xpos, ypos, "", kJ1Left); xpos += (myJoy[kJ1Up]->getWidth() + 5) * 2; myJoy[kJ1Right] = new CheckboxWidget(this, font, xpos, ypos, "", kJ1Right); xpos -= (myJoy[kJ1Up]->getWidth() + 5) * 2; ypos += myJoy[kJ1Down]->getHeight() * 2 + 10; myJoy[kJ1Fire] = new CheckboxWidget(this, font, xpos, ypos, "Fire", kJ1Fire); xpos = 2 * _w / 3; ypos = y; // Console Select/Reset t = new StaticTextWidget(this, font, xpos, ypos+2, font.getStringWidth("Console"), fontHeight, "Console", TextAlign::Left); xpos -= 10; ypos += t->getHeight() + 10; myHoldSelect = new CheckboxWidget(this, font, xpos, ypos, "Select"); ypos += myHoldSelect->getHeight() + 5; myHoldReset = new CheckboxWidget(this, font, xpos, ypos, "Reset"); for(int i = kJ0Up; i <= kJ1Fire; ++i) wid.push_back(myJoy[i]); wid.push_back(myHoldSelect); wid.push_back(myHoldReset); return final_y; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GlobalPropsDialog::loadConfig() { Settings& settings = instance().settings(); myBSType->setSelected(settings.getString("bs"), "AUTO"); myLeftDiff->setSelected(settings.getString("ld"), "DEFAULT"); myRightDiff->setSelected(settings.getString("rd"), "DEFAULT"); myTVType->setSelected(settings.getString("tv"), "DEFAULT"); myDebug->setSelected(settings.getBool("debug") ? "true" : "false"); const string& holdjoy0 = settings.getString("holdjoy0"); for(int i = kJ0Up; i <= kJ0Fire; ++i) myJoy[i]->setState(BSPF::containsIgnoreCase(holdjoy0, ourJoyState[i])); const string& holdjoy1 = settings.getString("holdjoy1"); for(int i = kJ1Up; i <= kJ1Fire; ++i) myJoy[i]->setState(BSPF::containsIgnoreCase(holdjoy1, ourJoyState[i])); myHoldSelect->setState(settings.getBool("holdselect")); myHoldReset->setState(settings.getBool("holdreset")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GlobalPropsDialog::saveConfig() { Settings& settings = instance().settings(); string s; s = myBSType->getSelectedTag().toString(); if(s == "AUTO") s = ""; settings.setValue("bs", s); s = myLeftDiff->getSelectedTag().toString(); if(s == "DEFAULT") s = ""; settings.setValue("ld", s); s = myRightDiff->getSelectedTag().toString(); if(s == "DEFAULT") s = ""; settings.setValue("rd", s); s = myTVType->getSelectedTag().toString(); if(s == "DEFAULT") s = ""; settings.setValue("tv", s); settings.setValue("debug", myDebug->getSelectedTag().toBool()); s = ""; for(int i = kJ0Up; i <= kJ0Fire; ++i) if(myJoy[i]->getState()) s += ourJoyState[i]; settings.setValue("holdjoy0", s); s = ""; for(int i = kJ1Up; i <= kJ1Fire; ++i) if(myJoy[i]->getState()) s += ourJoyState[i]; settings.setValue("holdjoy1", s); settings.setValue("holdselect", myHoldSelect->getState()); settings.setValue("holdreset", myHoldReset->getState()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GlobalPropsDialog::setDefaults() { myBSType->setSelected("AUTO"); myLeftDiff->setSelected("DEFAULT"); myRightDiff->setSelected("DEFAULT"); myTVType->setSelected("DEFAULT"); myDebug->setSelected("false"); for(int i = kJ0Up; i <= kJ1Fire; ++i) myJoy[i]->setState(false); myHoldSelect->setState(false); myHoldReset->setState(false); _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void GlobalPropsDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: saveConfig(); close(); // Inform parent to load the ROM sendCommand(LauncherDialog::kLoadROMCmd, 0, 0); break; case GuiObject::kDefaultsCmd: setDefaults(); saveConfig(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* const GlobalPropsDialog::ourJoyState[10] = { "U", "D", "L", "R", "F", "U", "D", "L", "R", "F" }; stella-5.1.1/src/gui/GlobalPropsDialog.hxx000066400000000000000000000041411324334165500204600ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef GLOBAL_PROPS_DIALOG_HXX #define GLOBAL_PROPS_DIALOG_HXX class CommandSender; class DialogContainer; class CheckboxWidget; class PopUpWidget; class OSystem; #include "Dialog.hxx" #include "bspf.hxx" class GlobalPropsDialog : public Dialog, public CommandSender { public: GlobalPropsDialog(GuiObject* boss, const GUI::Font& font); virtual ~GlobalPropsDialog() = default; private: int addHoldWidgets(const GUI::Font& font, int x, int y, WidgetArray& wid); void loadConfig() override; void saveConfig() override; void setDefaults() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: enum { kJ0Up, kJ0Down, kJ0Left, kJ0Right, kJ0Fire, kJ1Up, kJ1Down, kJ1Left, kJ1Right, kJ1Fire }; PopUpWidget* myBSType; PopUpWidget* myLeftDiff; PopUpWidget* myRightDiff; PopUpWidget* myTVType; PopUpWidget* myDebug; CheckboxWidget* myJoy[10]; CheckboxWidget* myHoldSelect; CheckboxWidget* myHoldReset; static const char* const ourJoyState[10]; private: // Following constructors and assignment operators not supported GlobalPropsDialog() = delete; GlobalPropsDialog(const GlobalPropsDialog&) = delete; GlobalPropsDialog(GlobalPropsDialog&&) = delete; GlobalPropsDialog& operator=(const GlobalPropsDialog&) = delete; GlobalPropsDialog& operator=(GlobalPropsDialog&&) = delete; }; #endif stella-5.1.1/src/gui/GuiObject.hxx000066400000000000000000000066361324334165500170020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef GUI_OBJECT_HXX #define GUI_OBJECT_HXX class Dialog; class DialogContainer; class Widget; class OSystem; #include "Command.hxx" #include "OSystem.hxx" #include "Vec.hxx" using WidgetArray = vector; /** This is the base class for all GUI objects/widgets. @author Stephen Anthony */ class GuiObject : public CommandReceiver { friend class Widget; friend class DialogContainer; public: // The commands generated by various widgets enum { kOKCmd = 'OK ', kCloseCmd = 'CLOS', kNextCmd = 'NEXT', kPrevCmd = 'PREV', kDefaultsCmd = 'DEFA', kSetPositionCmd = 'SETP' }; public: GuiObject(OSystem& osystem, DialogContainer& parent, Dialog& dialog, int x, int y, int w, int h) : myOSystem(osystem), myParent(parent), myDialog(dialog), _x(x), _y(y), _w(w), _h(h), _dirty(false), _firstWidget(nullptr) { } virtual ~GuiObject() = default; OSystem& instance() const { return myOSystem; } DialogContainer& parent() const { return myParent; } Dialog& dialog() const { return myDialog; } void setDirty() { _dirty = true; } virtual int getAbsX() const { return _x; } virtual int getAbsY() const { return _y; } virtual int getChildX() const { return getAbsX(); } virtual int getChildY() const { return getAbsY(); } virtual int getWidth() const { return _w; } virtual int getHeight() const { return _h; } virtual void setWidth(int w) { _w = w; } virtual void setHeight(int h) { _h = h; } virtual bool isVisible() const = 0; /** Add given widget(s) to the focus list */ virtual void addFocusWidget(Widget* w) = 0; virtual void addToFocusList(WidgetArray& list) = 0; /** Return focus list for this object */ WidgetArray& getFocusList() { return _focusList; } /** Redraw the focus list */ virtual void redrawFocus() { } /** Special character for menues */ const string ELLIPSIS = "\x1d"; protected: virtual void releaseFocus() = 0; virtual void draw() = 0; private: OSystem& myOSystem; DialogContainer& myParent; Dialog& myDialog; protected: int _x, _y, _w, _h; bool _dirty; Widget* _firstWidget; WidgetArray _focusList; private: // Following constructors and assignment operators not supported GuiObject() = delete; GuiObject(const GuiObject&) = delete; GuiObject(GuiObject&&) = delete; GuiObject& operator=(const GuiObject&) = delete; GuiObject& operator=(GuiObject&&) = delete; }; #endif stella-5.1.1/src/gui/HelpDialog.cxx000066400000000000000000000155061324334165500171260ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "Widget.hxx" #include "Font.hxx" #include "HelpDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - HelpDialog::HelpDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font) : Dialog(osystem, parent), myPage(1), myNumPages(5) { const string ELLIPSIS = "\x1d"; const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos; WidgetArray wid; // Set real dimensions _w = 46 * fontWidth + 10; _h = 12 * lineHeight + 20; // Add Previous, Next and Close buttons xpos = 10; ypos = _h - buttonHeight - 10; myPrevButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Previous", GuiObject::kPrevCmd); myPrevButton->clearFlags(WIDGET_ENABLED); wid.push_back(myPrevButton); xpos += buttonWidth + 7; myNextButton = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Next", GuiObject::kNextCmd); wid.push_back(myNextButton); xpos = _w - buttonWidth - 10; ButtonWidget* b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Close", GuiObject::kCloseCmd); wid.push_back(b); addOKWidget(b); addCancelWidget(b); xpos = 5; ypos = 5; myTitle = new StaticTextWidget(this, font, xpos, ypos, _w - 10, fontHeight, "", TextAlign::Center); int lwidth = 12 * fontWidth; xpos += 5; ypos += lineHeight + 4; for(uInt8 i = 0; i < kLINES_PER_PAGE; i++) { myKey[i] = new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight, "", TextAlign::Left); myDesc[i] = new StaticTextWidget(this, font, xpos+lwidth, ypos, _w - xpos - lwidth - 5, fontHeight, "", TextAlign::Left); ypos += fontHeight; } addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void HelpDialog::updateStrings(uInt8 page, uInt8 lines, string& title) { #ifdef BSPF_MAC_OSX #define ALT_ "Cmd" #else #define ALT_ "Alt" #endif int i = 0; auto ADD_BIND = [&](const string& k, const string& d) { myKeyStr[i] = k; myDescStr[i] = d; i++; }; auto ADD_TEXT = [&](const string& d) { ADD_BIND("", d); }; auto ADD_LINE = [&]() { ADD_BIND("", ""); }; switch(page) { case 1: title = "Common commands"; #ifndef BSPF_MAC_OSX ADD_BIND("Ctrl Q", "Quit emulation"); #else ADD_BIND("Cmd Q", "Quit emulation"); #endif ADD_BIND("Escape", "Exit current game"); ADD_BIND("Tab", "Enter 'Options' menu"); ADD_BIND("\\", "Toggle command menu"); ADD_BIND(ALT_" =", "Increase window size"); ADD_BIND(ALT_" -", "Decrease window size"); ADD_BIND(ALT_" Enter", "Toggle fullscreen /"); ADD_BIND("", " windowed mode"); ADD_BIND(ALT_" ]", "Increase volume by 2%"); ADD_BIND(ALT_" [", "Decrease volume by 2%"); break; case 2: title = "Special commands"; ADD_BIND("Ctrl g", "Grab mouse (keep in window)"); ADD_BIND("Ctrl f", "Switch between NTSC/PAL/SECAM"); ADD_BIND("Ctrl s", "Save game properties to a"); ADD_BIND("", " new file"); ADD_LINE(); ADD_BIND("Ctrl 0", "Toggle controller for Mouse"); ADD_BIND("Ctrl 1", "Toggle Stelladaptor left/right"); break; case 3: title = "TV Filters"; ADD_BIND(ALT_" 1", "Disable filtering"); ADD_BIND(ALT_" 2", "Enable 'Composite' mode"); ADD_BIND(ALT_" 3", "Enable 'S-video' mode"); ADD_BIND(ALT_" 4", "Enable 'RGB' mode"); ADD_BIND(ALT_" 5", "Enable 'Bad Adjust' mode"); ADD_BIND(ALT_" 6", "Enable 'Custom' mode"); ADD_BIND(ALT_" 7", "Adjust scanline intensity"); ADD_BIND(ALT_" 8", "Toggle scanline interpol."); ADD_BIND(ALT_" 9", "Select 'Custom' adjustable"); ADD_BIND(ALT_" 0", "Modify 'Custom' adjustable"); break; case 4: title = "Developer commands"; ADD_BIND("`", "Enter/exit debugger"); ADD_LINE(); ADD_BIND(ALT_" PgUp", "Increase Display.YStart"); ADD_BIND(ALT_" PgDn", "Decrease Display.YStart"); ADD_BIND("Ctrl PgUp", "Increase Display.Height"); ADD_BIND("Ctrl PgDn", "Decrease Display.Height"); ADD_LINE(); ADD_BIND(ALT_" L", "Toggle frame stats"); ADD_BIND(ALT_" ,", "Toggle 'Debug Colors' mode"); ADD_BIND(ALT_" t", "Toggle 'Time Machine' mode"); break; case 5: title = "All other commands"; ADD_LINE(); ADD_BIND("Remapped Eve", "nts"); ADD_TEXT("Most other commands can be"); ADD_TEXT("remapped. Please consult the"); ADD_TEXT("'Input Settings" + ELLIPSIS + "' menu for"); ADD_TEXT("more information."); break; } while(i < lines) ADD_LINE(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void HelpDialog::displayInfo() { string titleStr; updateStrings(myPage, kLINES_PER_PAGE, titleStr); myTitle->setLabel(titleStr); for(uInt8 i = 0; i < kLINES_PER_PAGE; i++) { myKey[i]->setLabel(myKeyStr[i]); myDesc[i]->setLabel(myDescStr[i]); } _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void HelpDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kNextCmd: myPage++; if(myPage >= myNumPages) myNextButton->clearFlags(WIDGET_ENABLED); if(myPage >= 2) myPrevButton->setFlags(WIDGET_ENABLED); displayInfo(); break; case GuiObject::kPrevCmd: myPage--; if(myPage <= myNumPages) myNextButton->setFlags(WIDGET_ENABLED); if(myPage <= 1) myPrevButton->clearFlags(WIDGET_ENABLED); displayInfo(); break; default: Dialog::handleCommand(sender, cmd, data, 0); } } stella-5.1.1/src/gui/HelpDialog.hxx000066400000000000000000000036371324334165500171350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef HELP_DIALOG_HXX #define HELP_DIALOG_HXX class DialogContainer; class CommandSender; class ButtonWidget; class StaticTextWidget; class OSystem; #include "Dialog.hxx" #include "bspf.hxx" class HelpDialog : public Dialog { public: HelpDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); virtual ~HelpDialog() = default; private: void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void updateStrings(uInt8 page, uInt8 lines, string& title); void displayInfo(); void loadConfig() override { displayInfo(); } private: enum { kLINES_PER_PAGE = 10 }; ButtonWidget* myNextButton; ButtonWidget* myPrevButton; StaticTextWidget* myTitle; StaticTextWidget* myKey[kLINES_PER_PAGE]; StaticTextWidget* myDesc[kLINES_PER_PAGE]; string myKeyStr[kLINES_PER_PAGE]; string myDescStr[kLINES_PER_PAGE]; uInt8 myPage; uInt8 myNumPages; private: // Following constructors and assignment operators not supported HelpDialog() = delete; HelpDialog(const HelpDialog&) = delete; HelpDialog(HelpDialog&&) = delete; HelpDialog& operator=(const HelpDialog&) = delete; HelpDialog& operator=(HelpDialog&&) = delete; }; #endif stella-5.1.1/src/gui/InputDialog.cxx000066400000000000000000000457761324334165500173510ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "OSystem.hxx" #include "Console.hxx" #include "EventHandler.hxx" #include "Joystick.hxx" #include "Paddles.hxx" #include "PointingDevice.hxx" #include "SaveKey.hxx" #include "AtariVox.hxx" #include "Settings.hxx" #include "EventMappingWidget.hxx" #include "EditTextWidget.hxx" #include "JoystickDialog.hxx" #include "PopUpWidget.hxx" #include "TabWidget.hxx" #include "Widget.hxx" #include "Font.hxx" #include "MessageBox.hxx" #include "InputDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - InputDialog::InputDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent), myConfirmMsg(nullptr), myMaxWidth(max_w), myMaxHeight(max_h) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; const int vBorder = 4; int xpos, ypos, tabID; StringList actions; // Set real dimensions _w = std::min(50 * fontWidth + 10, max_w); _h = std::min(16 * (lineHeight + 4) + 14, max_h); // The tab widget xpos = 2; ypos = vBorder; myTab = new TabWidget(this, font, xpos, ypos, _w - 2*xpos, _h - buttonHeight - 20); addTabWidget(myTab); // 1) Event mapper for emulation actions tabID = myTab->addTab("Emul. Events"); actions = instance().eventHandler().getActionList(kEmulationMode); myEmulEventMapper = new EventMappingWidget(myTab, font, 2, 2, myTab->getWidth(), myTab->getHeight() - ypos, actions, kEmulationMode); myTab->setParentWidget(tabID, myEmulEventMapper); addToFocusList(myEmulEventMapper->getFocusList(), myTab, tabID); // 2) Event mapper for UI actions tabID = myTab->addTab("UI Events"); actions = instance().eventHandler().getActionList(kMenuMode); myMenuEventMapper = new EventMappingWidget(myTab, font, 2, 2, myTab->getWidth(), myTab->getHeight() - ypos, actions, kMenuMode); myTab->setParentWidget(tabID, myMenuEventMapper); addToFocusList(myMenuEventMapper->getFocusList(), myTab, tabID); // 3) Devices & ports addDevicePortTab(font); // Finalize the tabs, and activate the first tab myTab->activateTabs(); myTab->setActiveTab(0); // Add Defaults, OK and Cancel buttons WidgetArray wid; ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - InputDialog::~InputDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::addDevicePortTab(const GUI::Font& font) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(); int xpos, ypos, lwidth, pwidth, tabID; WidgetArray wid; VariantList items; const int vGap = 4; const int hSpace = 8; // Devices/ports tabID = myTab->addTab("Devices & Ports"); // Stelladaptor mappings ypos = vGap+2; lwidth = font.getStringWidth("Digital paddle sensitivity "); // was: "Use mouse as a controller " pwidth = font.getStringWidth("-UI, -Emulation"); VarList::push_back(items, "Left / Right", "lr"); VarList::push_back(items, "Right / Left", "rl"); mySAPort = new PopUpWidget(myTab, font, hSpace, ypos, pwidth, lineHeight, items, "Stelladaptor port order ", lwidth); wid.push_back(mySAPort); // Use mouse as controller ypos += lineHeight + vGap; items.clear(); VarList::push_back(items, "Always", "always"); VarList::push_back(items, "Analog devices", "analog"); VarList::push_back(items, "Never", "never"); myMouseControl = new PopUpWidget(myTab, font, hSpace, ypos, pwidth, lineHeight, items, "Use mouse as a controller ", lwidth); wid.push_back(myMouseControl); // Mouse cursor state ypos += lineHeight + vGap; items.clear(); VarList::push_back(items, "-UI, -Emulation", "0"); VarList::push_back(items, "-UI, +Emulation", "1"); VarList::push_back(items, "+UI, -Emulation", "2"); VarList::push_back(items, "+UI, +Emulation", "3"); myCursorState = new PopUpWidget(myTab, font, hSpace, ypos, pwidth, lineHeight, items, "Mouse cursor visibility ", lwidth); wid.push_back(myCursorState); #ifndef WINDOWED_SUPPORT myCursorState->clearFlags(WIDGET_ENABLED); #endif lwidth = font.getStringWidth("Digital paddle sensitivity "); pwidth = font.getMaxCharWidth() * 8; // Add joystick deadzone setting ypos += lineHeight + vGap*3; myDeadzone = new SliderWidget(myTab, font, hSpace, ypos, pwidth, lineHeight, "Joystick deadzone size ", lwidth, kDeadzoneChanged); myDeadzone->setMinValue(0); myDeadzone->setMaxValue(29); xpos = hSpace + myDeadzone->getWidth() + 5; myDeadzoneLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 5*fontWidth, lineHeight, "", TextAlign::Left); wid.push_back(myDeadzone); // Add paddle speed (digital emulation) ypos += lineHeight + vGap; myDPaddleSpeed = new SliderWidget(myTab, font, hSpace, ypos, pwidth, lineHeight, "Digital paddle sensitivity ", lwidth, kDPSpeedChanged); myDPaddleSpeed->setMinValue(1); myDPaddleSpeed->setMaxValue(20); xpos = hSpace + myDPaddleSpeed->getWidth() + 5; myDPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight, "", TextAlign::Left); wid.push_back(myDPaddleSpeed); // Add paddle speed (mouse emulation) ypos += lineHeight + vGap; myMPaddleSpeed = new SliderWidget(myTab, font, hSpace, ypos, pwidth, lineHeight, "Mouse paddle sensitivity ", lwidth, kMPSpeedChanged); myMPaddleSpeed->setMinValue(1); myMPaddleSpeed->setMaxValue(20); xpos = hSpace + myMPaddleSpeed->getWidth() + 5; myMPaddleLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight, "", TextAlign::Left); wid.push_back(myMPaddleSpeed); // Add trackball speed ypos += lineHeight + vGap; myTrackBallSpeed = new SliderWidget(myTab, font, hSpace, ypos, pwidth, lineHeight, "Trackball sensitivity ", lwidth, kTBSpeedChanged); myTrackBallSpeed->setMinValue(1); myTrackBallSpeed->setMaxValue(20); xpos = hSpace + myTrackBallSpeed->getWidth() + 5; myTrackBallLabel = new StaticTextWidget(myTab, font, xpos, ypos+1, 24, lineHeight, "", TextAlign::Left); wid.push_back(myTrackBallSpeed); // Add 'allow all 4 directions' for joystick ypos += lineHeight + vGap*3; myAllowAll4 = new CheckboxWidget(myTab, font, hSpace, ypos, "Allow all 4 directions on joystick"); wid.push_back(myAllowAll4); // Grab mouse (in windowed mode) ypos += lineHeight + vGap; myGrabMouse = new CheckboxWidget(myTab, font, hSpace, ypos, "Grab mouse in emulation mode"); wid.push_back(myGrabMouse); #ifndef WINDOWED_SUPPORT myGrabMouse->clearFlags(WIDGET_ENABLED); #endif // Enable/disable control key-combos ypos += lineHeight + vGap; myCtrlCombo = new CheckboxWidget(myTab, font, hSpace, ypos, "Use Control key combos"); wid.push_back(myCtrlCombo); int fwidth; // Add EEPROM erase (part 1/2) ypos += vGap*4; fwidth = font.getStringWidth("AtariVox/SaveKey"); lwidth = font.getStringWidth("AtariVox/SaveKey"); new StaticTextWidget(myTab, font, _w - 14 - (fwidth + lwidth) / 2, ypos, "AtariVox/SaveKey"); // Show joystick database ypos += lineHeight; myJoyDlgButton = new ButtonWidget(myTab, font, hSpace, ypos, 20, "Joystick database" + ELLIPSIS, kDBButtonPressed); wid.push_back(myJoyDlgButton); // Add EEPROM erase (part 1/2) myEraseEEPROMButton = new ButtonWidget(myTab, font, _w - 14 - fwidth, ypos, fwidth, lineHeight+4, "Erase EEPROM", kEEButtonPressed); // Add AtariVox serial port ypos += lineHeight + vGap*2; lwidth = font.getStringWidth("AVox serial port "); fwidth = _w - 14 - hSpace - lwidth; new StaticTextWidget(myTab, font, hSpace, ypos, "AVox serial port "); myAVoxPort = new EditTextWidget(myTab, font, hSpace + lwidth, ypos, fwidth, fontHeight, ""); wid.push_back(myAVoxPort); // Add items for virtual device ports addToFocusList(wid, myTab, tabID); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::loadConfig() { // Left & right ports mySAPort->setSelected(instance().settings().getString("saport"), "lr"); // Use mouse as a controller myMouseControl->setSelected( instance().settings().getString("usemouse"), "analog"); // Mouse cursor state myCursorState->setSelected(instance().settings().getString("cursor"), "2"); // Joystick deadzone myDeadzone->setValue(instance().settings().getInt("joydeadzone")); myDeadzoneLabel->setValue(Joystick::deadzone()); // Paddle speed (digital and mouse) myDPaddleSpeed->setValue(instance().settings().getInt("dsense")); myDPaddleLabel->setLabel(instance().settings().getString("dsense")); myMPaddleSpeed->setValue(instance().settings().getInt("msense")); myMPaddleLabel->setLabel(instance().settings().getString("msense")); // Trackball speed myTrackBallSpeed->setValue(instance().settings().getInt("tsense")); myTrackBallLabel->setLabel(instance().settings().getString("tsense")); // AtariVox serial port myAVoxPort->setText(instance().settings().getString("avoxport")); // EEPROM erase (only enable in emulation mode and for valid controllers) if(instance().hasConsole()) { Controller& lport = instance().console().leftController(); Controller& rport = instance().console().rightController(); myEraseEEPROMButton->setEnabled(lport.type() == Controller::SaveKey || lport.type() == Controller::AtariVox || rport.type() == Controller::SaveKey || rport.type() == Controller::AtariVox); } else myEraseEEPROMButton->setEnabled(false); // Allow all 4 joystick directions myAllowAll4->setState(instance().settings().getBool("joyallow4")); // Grab mouse myGrabMouse->setState(instance().settings().getBool("grabmouse")); // Enable/disable control key-combos myCtrlCombo->setState(instance().settings().getBool("ctrlcombo")); myTab->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::saveConfig() { // Left & right ports instance().eventHandler().mapStelladaptors(mySAPort->getSelectedTag().toString()); // Use mouse as a controller const string& usemouse = myMouseControl->getSelectedTag().toString(); instance().settings().setValue("usemouse", usemouse); instance().eventHandler().setMouseControllerMode(usemouse); // Joystick deadzone int deadzone = myDeadzone->getValue(); instance().settings().setValue("joydeadzone", deadzone); Joystick::setDeadZone(deadzone); // Paddle speed (digital and mouse) int sensitivity = myDPaddleSpeed->getValue(); instance().settings().setValue("dsense", sensitivity); Paddles::setDigitalSensitivity(sensitivity); sensitivity = myMPaddleSpeed->getValue(); instance().settings().setValue("msense", sensitivity); Paddles::setMouseSensitivity(sensitivity); // Trackball speed sensitivity = myTrackBallSpeed->getValue(); instance().settings().setValue("tsense", sensitivity); PointingDevice::setSensitivity(sensitivity); // AtariVox serial port instance().settings().setValue("avoxport", myAVoxPort->getText()); // Allow all 4 joystick directions bool allowall4 = myAllowAll4->getState(); instance().settings().setValue("joyallow4", allowall4); instance().eventHandler().allowAllDirections(allowall4); // Grab mouse and hide cursor const string& cursor = myCursorState->getSelectedTag().toString(); instance().settings().setValue("cursor", cursor); instance().settings().setValue("grabmouse", myGrabMouse->getState()); instance().frameBuffer().enableGrabMouse(myGrabMouse->getState()); // Enable/disable control key-combos instance().settings().setValue("ctrlcombo", myCtrlCombo->getState()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::setDefaults() { switch(myTab->getActiveTab()) { case 0: // Emulation events myEmulEventMapper->setDefaults(); break; case 1: // UI events myMenuEventMapper->setDefaults(); break; case 2: // Virtual devices { // Left & right ports mySAPort->setSelected("lr"); // Use mouse as a controller myMouseControl->setSelected("analog"); // Mouse cursor state myCursorState->setSelected("2"); // Joystick deadzone myDeadzone->setValue(0); myDeadzoneLabel->setValue(3200); // Paddle speed (digital and mouse) myDPaddleSpeed->setValue(10); myDPaddleLabel->setLabel("10"); myMPaddleSpeed->setValue(10); myMPaddleLabel->setLabel("10"); myTrackBallSpeed->setValue(10); myTrackBallLabel->setLabel("10"); // AtariVox serial port myAVoxPort->setText(""); // Allow all 4 joystick directions myAllowAll4->setState(false); // Grab mouse myGrabMouse->setState(true); // Enable/disable control key-combos myCtrlCombo->setState(true); break; } default: break; } _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleKeyDown(StellaKey key, StellaMod mod) { // Remap key events in remap mode, otherwise pass to parent dialog if(myEmulEventMapper->remapMode()) myEmulEventMapper->handleKeyDown(key, mod); else if(myMenuEventMapper->remapMode()) myMenuEventMapper->handleKeyDown(key, mod); else Dialog::handleKeyDown(key, mod); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleJoyDown(int stick, int button) { // Remap joystick buttons in remap mode, otherwise pass to parent dialog if(myEmulEventMapper->remapMode()) myEmulEventMapper->handleJoyDown(stick, button); else if(myMenuEventMapper->remapMode()) myMenuEventMapper->handleJoyDown(stick, button); else Dialog::handleJoyDown(stick, button); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleJoyAxis(int stick, int axis, int value) { // Remap joystick axis in remap mode, otherwise pass to parent dialog if(myEmulEventMapper->remapMode()) myEmulEventMapper->handleJoyAxis(stick, axis, value); else if(myMenuEventMapper->remapMode()) myMenuEventMapper->handleJoyAxis(stick, axis, value); else Dialog::handleJoyAxis(stick, axis, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool InputDialog::handleJoyHat(int stick, int hat, JoyHat value) { // Remap joystick hat in remap mode, otherwise pass to parent dialog if(myEmulEventMapper->remapMode()) return myEmulEventMapper->handleJoyHat(stick, hat, value); else if(myMenuEventMapper->remapMode()) return myMenuEventMapper->handleJoyHat(stick, hat, value); else return Dialog::handleJoyHat(stick, hat, value); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::eraseEEPROM() { // This method will only be callable if a console exists, so we don't // need to check again here Controller& lport = instance().console().leftController(); Controller& rport = instance().console().rightController(); if(lport.type() == Controller::SaveKey || lport.type() == Controller::AtariVox) { SaveKey& skey = static_cast(lport); skey.eraseCurrent(); } if(rport.type() == Controller::SaveKey || rport.type() == Controller::AtariVox) { SaveKey& skey = static_cast(rport); skey.eraseCurrent(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kCloseCmd: // Revert changes made to event mapping close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; case kDeadzoneChanged: myDeadzoneLabel->setValue(3200 + 1000*myDeadzone->getValue()); break; case kDPSpeedChanged: myDPaddleLabel->setValue(myDPaddleSpeed->getValue()); break; case kMPSpeedChanged: myMPaddleLabel->setValue(myMPaddleSpeed->getValue()); break; case kTBSpeedChanged: myTrackBallLabel->setValue(myTrackBallSpeed->getValue()); break; case kDBButtonPressed: if(!myJoyDialog) myJoyDialog = make_unique (this, instance().frameBuffer().font(), _w-60, _h-60); myJoyDialog->show(); break; case kEEButtonPressed: if(!myConfirmMsg) { StringList msg; msg.push_back("This operation cannot be undone."); msg.push_back("All data stored on your AtariVox"); msg.push_back("or SaveKey will be erased!"); msg.push_back(""); msg.push_back("If you are sure you want to erase"); msg.push_back("the data, click 'OK', otherwise "); msg.push_back("click 'Cancel'."); myConfirmMsg = make_unique (this, instance().frameBuffer().font(), msg, myMaxWidth, myMaxHeight, kConfirmEEEraseCmd, "OK", "Cancel", false); } myConfirmMsg->show(); break; case kConfirmEEEraseCmd: eraseEEPROM(); break; default: Dialog::handleCommand(sender, cmd, data, 0); } } stella-5.1.1/src/gui/InputDialog.hxx000066400000000000000000000064561324334165500173460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef INPUT_DIALOG_HXX #define INPUT_DIALOG_HXX class OSystem; class GuiObject; class TabWidget; class EventMappingWidget; class CheckboxWidget; class EditTextWidget; class JoystickDialog; class PopUpWidget; class SliderWidget; class StaticTextWidget; namespace GUI { class MessageBox; } #include "Dialog.hxx" #include "bspf.hxx" class InputDialog : public Dialog { public: InputDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h); virtual ~InputDialog(); private: void handleKeyDown(StellaKey key, StellaMod mod) override; void handleJoyDown(int stick, int button) override; void handleJoyAxis(int stick, int axis, int value) override; bool handleJoyHat(int stick, int hat, JoyHat value) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void loadConfig() override; void saveConfig() override; void setDefaults() override; void addDevicePortTab(const GUI::Font& font); void eraseEEPROM(); private: enum { kDeadzoneChanged = 'DZch', kDPSpeedChanged = 'PDch', kMPSpeedChanged = 'PMch', kTBSpeedChanged = 'TBch', kDBButtonPressed = 'DBbp', kEEButtonPressed = 'EEbp', kConfirmEEEraseCmd = 'EEcf' }; TabWidget* myTab; EventMappingWidget* myEmulEventMapper; EventMappingWidget* myMenuEventMapper; PopUpWidget* mySAPort; PopUpWidget* myMouseControl; PopUpWidget* myCursorState; EditTextWidget* myAVoxPort; SliderWidget* myDeadzone; StaticTextWidget* myDeadzoneLabel; SliderWidget* myDPaddleSpeed; SliderWidget* myMPaddleSpeed; SliderWidget* myTrackBallSpeed; StaticTextWidget* myDPaddleLabel; StaticTextWidget* myMPaddleLabel; StaticTextWidget* myTrackBallLabel; CheckboxWidget* myAllowAll4; CheckboxWidget* myGrabMouse; CheckboxWidget* myCtrlCombo; ButtonWidget* myJoyDlgButton; ButtonWidget* myEraseEEPROMButton; // Show the list of joysticks that the eventhandler knows about unique_ptr myJoyDialog; // Show a message about the dangers of using this function unique_ptr myConfirmMsg; // Maximum width and height for this dialog int myMaxWidth, myMaxHeight; private: // Following constructors and assignment operators not supported InputDialog() = delete; InputDialog(const InputDialog&) = delete; InputDialog(InputDialog&&) = delete; InputDialog& operator=(const InputDialog&) = delete; InputDialog& operator=(InputDialog&&) = delete; }; #endif stella-5.1.1/src/gui/InputTextDialog.cxx000066400000000000000000000146351324334165500202040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "EditTextWidget.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "Widget.hxx" #include "InputTextDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - InputTextDialog::InputTextDialog(GuiObject* boss, const GUI::Font& font, const StringList& labels) : Dialog(boss->instance(), boss->parent()), CommandSender(boss), myEnableCenter(false), myErrorFlag(false), myXOrig(0), myYOrig(0) { initialize(font, font, labels); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - InputTextDialog::InputTextDialog(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, const StringList& labels) : Dialog(boss->instance(), boss->parent()), CommandSender(boss), myEnableCenter(false), myErrorFlag(false), myXOrig(0), myYOrig(0) { initialize(lfont, nfont, labels); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::initialize(const GUI::Font& lfont, const GUI::Font& nfont, const StringList& labels) { const int fontWidth = lfont.getMaxCharWidth(), fontHeight = lfont.getFontHeight(), lineHeight = lfont.getLineHeight(); uInt32 xpos, ypos, i, lwidth = 0, maxIdx = 0; WidgetArray wid; // Calculate real dimensions _w = fontWidth * 41; _h = lineHeight * 4 + int(labels.size()) * (lineHeight + 5); // Determine longest label for(i = 0; i < labels.size(); ++i) { if(labels[i].length() > lwidth) { lwidth = int(labels[i].length()); maxIdx = i; } } lwidth = lfont.getStringWidth(labels[maxIdx]); // Create editboxes for all labels ypos = lineHeight; for(i = 0; i < labels.size(); ++i) { xpos = 10; new StaticTextWidget(this, lfont, xpos, ypos + 2, lwidth, fontHeight, labels[i], TextAlign::Left); xpos += lwidth + fontWidth; EditTextWidget* w = new EditTextWidget(this, nfont, xpos, ypos, _w - xpos - 10, lineHeight, ""); wid.push_back(w); myInput.push_back(w); ypos += lineHeight + 5; } xpos = 10; myTitle = new StaticTextWidget(this, lfont, xpos, ypos, _w - 2*xpos, fontHeight, "", TextAlign::Left); myTitle->setTextColor(kTextColorEm); addToFocusList(wid); // Add OK and Cancel buttons wid.clear(); addOKCancelBGroup(wid, lfont); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::show() { myEnableCenter = true; open(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::show(uInt32 x, uInt32 y) { myXOrig = x; myYOrig = y; myEnableCenter = false; open(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::center() { if(!myEnableCenter) { // Make sure the menu is exactly where it should be, in case the image // offset has changed const GUI::Rect& image = instance().frameBuffer().imageRect(); uInt32 x = image.x() + myXOrig; uInt32 y = image.y() + myYOrig; uInt32 tx = image.x() + image.width(); uInt32 ty = image.y() + image.height(); if(x + _w > tx) x -= (x + _w - tx); if(y + _h > ty) y -= (y + _h - ty); surface().setDstPos(x, y); } else Dialog::center(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::setTitle(const string& title) { myTitle->setLabel(title); myErrorFlag = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& InputTextDialog::getResult(int idx) { if(uInt32(idx) < myInput.size()) return myInput[idx]->getText(); else return EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::setText(const string& str, int idx) { if(uInt32(idx) < myInput.size()) myInput[idx]->setText(str); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::setTextFilter(const EditableWidget::TextFilter& f, int idx) { if(uInt32(idx) < myInput.size()) myInput[idx]->setTextFilter(f); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::setFocus(int idx) { if(uInt32(idx) < myInput.size()) Dialog::setFocus(getFocusList()[idx]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void InputTextDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: case EditableWidget::kAcceptCmd: { // Send a signal to the calling class that a selection has been made // Since we aren't derived from a widget, we don't have a 'data' or 'id' if(myCmd) sendCommand(myCmd, 0, 0); // We don't close, but leave the parent to do it // If the data isn't valid, the parent may wait until it is break; } case EditableWidget::kChangedCmd: // Erase the invalid message once editing is restarted if(myErrorFlag) { myTitle->setLabel(""); myErrorFlag = false; } break; case EditableWidget::kCancelCmd: Dialog::handleCommand(sender, GuiObject::kCloseCmd, data, id); break; default: Dialog::handleCommand(sender, cmd, data, id); break; } } stella-5.1.1/src/gui/InputTextDialog.hxx000066400000000000000000000050101324334165500201740ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef INPUT_TEXT_DIALOG_HXX #define INPUT_TEXT_DIALOG_HXX class GuiObject; class StaticTextWidget; class EditTextWidget; #include "Dialog.hxx" #include "Command.hxx" #include "EditableWidget.hxx" class InputTextDialog : public Dialog, public CommandSender { public: InputTextDialog(GuiObject* boss, const GUI::Font& font, const StringList& labels); InputTextDialog(GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, const StringList& labels); virtual ~InputTextDialog() = default; /** Place the input dialog onscreen and center it */ void show(); /** Show input dialog onscreen at the specified coordinates */ void show(uInt32 x, uInt32 y); const string& getResult(int idx = 0); void setText(const string& str, int idx = 0); void setTextFilter(const EditableWidget::TextFilter& f, int idx = 0); void setEmitSignal(int cmd) { myCmd = cmd; } void setTitle(const string& title); void setFocus(int idx = 0); protected: void initialize(const GUI::Font& lfont, const GUI::Font& nfont, const StringList& labels); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; /** This dialog uses its own positioning, so we override Dialog::center() */ void center() override; private: vector myInput; StaticTextWidget* myTitle; bool myEnableCenter; bool myErrorFlag; int myCmd; uInt32 myXOrig, myYOrig; private: // Following constructors and assignment operators not supported InputTextDialog() = delete; InputTextDialog(const InputTextDialog&) = delete; InputTextDialog(InputTextDialog&&) = delete; InputTextDialog& operator=(const InputTextDialog&) = delete; InputTextDialog& operator=(InputTextDialog&&) = delete; }; #endif stella-5.1.1/src/gui/JoystickDialog.cxx000066400000000000000000000074451324334165500200400ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "EventHandler.hxx" #include "Widget.hxx" #include "Font.hxx" #include "EditTextWidget.hxx" #include "StringListWidget.hxx" #include "Variant.hxx" #include "JoystickDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - JoystickDialog::JoystickDialog(GuiObject* boss, const GUI::Font& font, int max_w, int max_h) : Dialog(boss->instance(), boss->parent(), 0, 0, max_w, max_h) { int xpos, ypos; WidgetArray wid; int buttonWidth = font.getStringWidth("Close") + 20, buttonHeight = font.getLineHeight() + 4; // Joystick list xpos = 10; ypos = 10; int w = _w - 2 * xpos; int h = _h - buttonHeight - ypos - 20; myJoyList = new StringListWidget(this, font, xpos, ypos, w, h); myJoyList->setEditable(false); wid.push_back(myJoyList); // Joystick ID ypos = _h - buttonHeight - 10; StaticTextWidget* t = new StaticTextWidget(this, font, xpos, ypos, font.getStringWidth("Joystick ID "), font.getFontHeight(), "Joystick ID ", TextAlign::Left); xpos += t->getWidth() + 4; myJoyText = new EditTextWidget(this, font, xpos, ypos-2, font.getStringWidth("Unplugged")+8, font.getLineHeight(), ""); myJoyText->setEditable(false); // Add buttons at bottom xpos = _w - buttonWidth - 10; myCloseBtn = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Close", GuiObject::kCloseCmd); addOKWidget(myCloseBtn); addCancelWidget(myCloseBtn); buttonWidth = font.getStringWidth("Remove") + 20; xpos -= buttonWidth + 5; myRemoveBtn = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Remove", kRemoveCmd); myRemoveBtn->clearFlags(WIDGET_ENABLED); // Now we can finally add the widgets to the focus list wid.push_back(myRemoveBtn); wid.push_back(myCloseBtn); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JoystickDialog::loadConfig() { myJoyIDs.clear(); StringList sticks; for(const auto& i: instance().eventHandler().joystickDatabase()) { sticks.push_back(i.first); myJoyIDs.push_back(i.second.toInt()); } myJoyList->setList(sticks); myJoyList->setSelected(0); if(sticks.size() == 0) { myRemoveBtn->setEnabled(false); myJoyText->setText(""); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void JoystickDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: close(); break; case kRemoveCmd: instance().eventHandler().removeJoystickFromDatabase(myJoyList->getSelectedString()); loadConfig(); break; case ListWidget::kSelectionChangedCmd: if(myJoyIDs[data] >= 0) { myRemoveBtn->setEnabled(false); ostringstream buf; buf << "J" << myJoyIDs[data]; myJoyText->setText(buf.str()); } else { myRemoveBtn->setEnabled(true); myJoyText->setText("Unplugged"); } break; default: Dialog::handleCommand(sender, cmd, data, id); break; } } stella-5.1.1/src/gui/JoystickDialog.hxx000066400000000000000000000036711324334165500200420ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef JOYSTICK_DIALOG_HXX #define JOYSTICK_DIALOG_HXX class CommandSender; class GuiObject; class ButtonWidget; class EditTextWidgetWidget; class StringListWidget; #include "Dialog.hxx" /** * Show a listing of joysticks currently stored in the eventhandler database, * and allow to remove those that aren't currently being used. */ class JoystickDialog : public Dialog { public: JoystickDialog(GuiObject* boss, const GUI::Font& font, int max_w, int max_h); virtual ~JoystickDialog() = default; /** Place the dialog onscreen and center it */ void show() { open(); } private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: StringListWidget* myJoyList; EditTextWidget* myJoyText; ButtonWidget* myRemoveBtn; ButtonWidget* myCloseBtn; IntArray myJoyIDs; enum { kRemoveCmd = 'JDrm' }; private: // Following constructors and assignment operators not supported JoystickDialog() = delete; JoystickDialog(const JoystickDialog&) = delete; JoystickDialog(JoystickDialog&&) = delete; JoystickDialog& operator=(const JoystickDialog&) = delete; JoystickDialog& operator=(JoystickDialog&&) = delete; }; #endif stella-5.1.1/src/gui/Launcher.cxx000066400000000000000000000047421324334165500166570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "LauncherDialog.hxx" #include "Version.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "FSNode.hxx" #include "FrameBuffer.hxx" #include "bspf.hxx" #include "Launcher.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Launcher::Launcher(OSystem& osystem) : DialogContainer(osystem) { const GUI::Size& s = myOSystem.settings().getSize("launcherres"); const GUI::Size& d = myOSystem.frameBuffer().desktopSize(); myWidth = s.w; myHeight = s.h; // The launcher dialog is resizable, within certain bounds // We check those bounds now myWidth = std::max(myWidth, uInt32(FrameBuffer::kFBMinW)); myHeight = std::max(myHeight, uInt32(FrameBuffer::kFBMinH)); myWidth = std::min(myWidth, uInt32(d.w)); myHeight = std::min(myHeight, uInt32(d.h)); myOSystem.settings().setValue("launcherres", GUI::Size(myWidth, myHeight)); myBaseDialog = new LauncherDialog(myOSystem, *this, 0, 0, myWidth, myHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FBInitStatus Launcher::initializeVideo() { string title = string("Stella ") + STELLA_VERSION; return myOSystem.frameBuffer().createDisplay(title, myWidth, myHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& Launcher::selectedRomMD5() { return (static_cast(myBaseDialog))->selectedRomMD5(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const FilesystemNode& Launcher::currentNode() const { return (static_cast(myBaseDialog))->currentNode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Launcher::reload() { (static_cast(myBaseDialog))->reload(); } stella-5.1.1/src/gui/Launcher.hxx000066400000000000000000000035771324334165500166710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef LAUNCHER_HXX #define LAUNCHER_HXX class Properties; class OSystem; class FilesystemNode; #include "FrameBufferConstants.hxx" #include "DialogContainer.hxx" /** The base dialog for the ROM launcher in Stella. @author Stephen Anthony */ class Launcher : public DialogContainer { public: /** Create a new menu stack */ Launcher(OSystem& osystem); virtual ~Launcher() = default; /** Initialize the video subsystem wrt this class. */ FBInitStatus initializeVideo(); /** Wrapper for LauncherDialog::selectedRomMD5() method. */ const string& selectedRomMD5(); /** Wrapper for LauncherDialog::currentNode() method. */ const FilesystemNode& currentNode() const; /** Wrapper for LauncherDialog::reload() method. */ void reload(); private: // The width and height of this dialog uInt32 myWidth; uInt32 myHeight; private: // Following constructors and assignment operators not supported Launcher() = delete; Launcher(const Launcher&) = delete; Launcher(Launcher&&) = delete; Launcher& operator=(const Launcher&) = delete; Launcher& operator=(Launcher&&) = delete; }; #endif stella-5.1.1/src/gui/LauncherDialog.cxx000066400000000000000000000435671324334165500200070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "BrowserDialog.hxx" #include "ContextMenu.hxx" #include "DialogContainer.hxx" #include "Dialog.hxx" #include "EditTextWidget.hxx" #include "FSNode.hxx" #include "GameList.hxx" #include "MD5.hxx" #include "OptionsDialog.hxx" #include "GlobalPropsDialog.hxx" #include "LauncherFilterDialog.hxx" #include "MessageBox.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "EventHandler.hxx" #include "StellaKeys.hxx" #include "Props.hxx" #include "PropsSet.hxx" #include "RomInfoWidget.hxx" #include "Settings.hxx" #include "StringListWidget.hxx" #include "Widget.hxx" #include "Font.hxx" #include "LauncherDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LauncherDialog::LauncherDialog(OSystem& osystem, DialogContainer& parent, int x, int y, int w, int h) : Dialog(osystem, parent, x, y, w, h), myStartButton(nullptr), myPrevDirButton(nullptr), myOptionsButton(nullptr), myQuitButton(nullptr), myList(nullptr), myPattern(nullptr), myRomInfoWidget(nullptr), mySelectedItem(0) { const GUI::Font& font = instance().frameBuffer().launcherFont(); const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(), bwidth = (_w - 2 * 10 - 8 * (4 - 1)) / 4, bheight = font.getLineHeight() + 4; int xpos = 0, ypos = 0, lwidth = 0, lwidth2 = 0; WidgetArray wid; // Show game name lwidth = font.getStringWidth("Select an item from the list ..."); xpos += 10; ypos += 8; new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight, "Select an item from the list ...", TextAlign::Left); lwidth2 = font.getStringWidth("XXXX items found"); xpos = _w - lwidth2 - 10; myRomCount = new StaticTextWidget(this, font, xpos, ypos, lwidth2, fontHeight, "", TextAlign::Right); // Add filter that can narrow the results shown in the listing // It has to fit between both labels if(w >= 640) { int fwidth = std::min(15 * fontWidth, xpos - 20 - lwidth); xpos -= fwidth + 5; myPattern = new EditTextWidget(this, font, xpos, ypos, fwidth, fontHeight, ""); } // Add list with game titles // Before we add the list, we need to know the size of the RomInfoWidget xpos = 10; ypos += fontHeight + 5; int romWidth = 0; int romSize = instance().settings().getInt("romviewer"); if(romSize > 1 && w >= 1000 && h >= 760) romWidth = 660; else if(romSize > 0 && w >= 640 && h >= 480) romWidth = 365; int listWidth = _w - (romWidth > 0 ? romWidth+5 : 0) - 20; myList = new StringListWidget(this, font, xpos, ypos, listWidth, _h - 35 - bheight - 2*fontHeight); myList->setEditable(false); wid.push_back(myList); if(myPattern) wid.push_back(myPattern); // Add after the list for tab order // Add ROM info area (if enabled) if(romWidth > 0) { xpos += myList->getWidth() + 5; myRomInfoWidget = new RomInfoWidget(this, romWidth < 660 ? instance().frameBuffer().smallFont() : instance().frameBuffer().infoFont(), xpos, ypos, romWidth, myList->getHeight()); } // Add textfield to show current directory xpos = 10; xpos += 5; ypos += myList->getHeight() + 4; lwidth = font.getStringWidth("Dir "); myDirLabel = new StaticTextWidget(this, font, xpos, ypos+2, lwidth, fontHeight, "Dir", TextAlign::Left); xpos += lwidth + 5; myDir = new EditTextWidget(this, font, xpos, ypos, _w - xpos - 10, lineHeight, ""); myDir->setEditable(false, true); myDir->clearFlags(WIDGET_RETAIN_FOCUS); // Add four buttons at the bottom xpos = 10; ypos += myDir->getHeight() + 4; #ifndef BSPF_MAC_OSX myStartButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Select", kLoadROMCmd); wid.push_back(myStartButton); xpos += bwidth + 8; myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Go Up", kPrevDirCmd); wid.push_back(myPrevDirButton); xpos += bwidth + 8; myOptionsButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Options" + ELLIPSIS, kOptionsCmd); wid.push_back(myOptionsButton); xpos += bwidth + 8; myQuitButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Quit", kQuitCmd); wid.push_back(myQuitButton); #else myQuitButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Quit", kQuitCmd); wid.push_back(myQuitButton); xpos += bwidth + 8; myOptionsButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Options" + ELLIPSIS, kOptionsCmd); wid.push_back(myOptionsButton); xpos += bwidth + 8; myPrevDirButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Go Up", kPrevDirCmd); wid.push_back(myPrevDirButton); xpos += bwidth + 8; myStartButton = new ButtonWidget(this, font, xpos, ypos, bwidth, bheight, "Select", kLoadROMCmd); wid.push_back(myStartButton); #endif mySelectedItem = 0; // Highlight 'Rom Listing' // Create an options dialog, similar to the in-game one myOptions = make_unique(osystem, parent, this, w, h, OptionsDialog::launcher); // Create a game list, which contains all the information about a ROM that // the launcher needs myGameList = make_unique(); addToFocusList(wid); // Create context menu for ROM list options VariantList l; VarList::push_back(l, "Power-on options" + ELLIPSIS, "override"); VarList::push_back(l, "Filter listing" + ELLIPSIS, "filter"); VarList::push_back(l, "Reload listing", "reload"); myMenu = make_unique(this, osystem.frameBuffer().font(), l); // Create global props dialog, which is used to temporarily overrride // ROM properties myGlobalProps = make_unique(this, osystem.frameBuffer().font()); // Create dialog whereby the files shown in the ROM listing can be customized myFilters = make_unique(this, osystem.frameBuffer().font()); // Figure out which filters are needed for the ROM listing setListFilters(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& LauncherDialog::selectedRomMD5() { int item = myList->getSelected(); if(item < 0) return EmptyString; string extension; const FilesystemNode node(myGameList->path(item)); if(node.isDirectory() || !LauncherFilterDialog::isValidRomName(node, extension)) return EmptyString; // Make sure we have a valid md5 for this ROM if(myGameList->md5(item) == "") myGameList->setMd5(item, MD5::hash(node)); return myGameList->md5(item); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::loadConfig() { const string& tmpromdir = instance().settings().getString("tmpromdir"); const string& romdir = tmpromdir != "" ? tmpromdir : instance().settings().getString("romdir"); // When romdir hasn't been set, it probably indicates that this is the first // time running Stella; in this case, we should prompt the user if(romdir == "") { if(!myFirstRunMsg) { StringList msg; msg.push_back("This seems to be your first time running Stella."); msg.push_back("Before you can start a game, you need to"); msg.push_back("specify where your ROMs are located."); msg.push_back(""); msg.push_back("Click 'OK' to select a default ROM directory,"); msg.push_back("or 'Cancel' to browse the filesystem manually."); myFirstRunMsg = make_unique (this, instance().frameBuffer().font(), msg, _w, _h, kFirstRunMsgChosenCmd); } myFirstRunMsg->show(); } // Assume that if the list is empty, this is the first time that loadConfig() // has been called (and we should reload the list) if(myList->getList().empty()) { myPrevDirButton->setEnabled(false); myCurrentNode = FilesystemNode(romdir == "" ? "~" : romdir); if(!(myCurrentNode.exists() && myCurrentNode.isDirectory())) myCurrentNode = FilesystemNode("~"); updateListing(); } Dialog::setFocus(getFocusList()[mySelectedItem]); if(myRomInfoWidget) myRomInfoWidget->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::updateListing(const string& nameToSelect) { // Start with empty list myGameList->clear(); myDir->setText(""); loadDirListing(); // Only hilite the 'up' button if there's a parent directory myPrevDirButton->setEnabled(myCurrentNode.hasParent()); // Show current directory myDir->setText(myCurrentNode.getShortPath()); // Now fill the list widget with the contents of the GameList StringList l; for(uInt32 i = 0; i < myGameList->size(); ++i) l.push_back(myGameList->name(i)); myList->setList(l); // Indicate how many files were found ostringstream buf; buf << (myGameList->size() - 1) << " items found"; myRomCount->setLabel(buf.str()); // Restore last selection const string& find = nameToSelect == "" ? instance().settings().getString("lastrom") : nameToSelect; myList->setSelected(find); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::loadDirListing() { if(!myCurrentNode.isDirectory()) return; FSList files; files.reserve(2048); myCurrentNode.getChildren(files, FilesystemNode::kListAll); // Add '[..]' to indicate previous folder if(myCurrentNode.hasParent()) myGameList->appendGame(" [..]", "", "", true); // Now add the directory entries bool domatch = myPattern && myPattern->getText() != ""; for(const auto& f: files) { bool isDir = f.isDirectory(); const string& name = isDir ? (" [" + f.getName() + "]") : f.getName(); // Honour the filtering settings // Showing only certain ROM extensions is determined by the extension // that we want - if there are no extensions, it implies show all files // In this way, showing all files is on the 'fast code path' if(!isDir && myRomExts.size() > 0) { // Skip over those names we've filtered out if(!LauncherFilterDialog::isValidRomName(name, myRomExts)) continue; } // Skip over files that don't match the pattern in the 'pattern' textbox if(domatch && !isDir && !matchPattern(name, myPattern->getText())) continue; myGameList->appendGame(name, f.getPath(), "", isDir); } // Sort the list by rom name (since that's what we see in the listview) myGameList->sortByName(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::loadRomInfo() { if(!myRomInfoWidget) return; int item = myList->getSelected(); if(item < 0) return; string extension; const FilesystemNode node(myGameList->path(item)); if(!node.isDirectory() && LauncherFilterDialog::isValidRomName(node, extension)) { // Make sure we have a valid md5 for this ROM if(myGameList->md5(item) == "") myGameList->setMd5(item, MD5::hash(node)); // Get the properties for this entry Properties props; instance().propSet().getMD5WithInsert(node, myGameList->md5(item), props); myRomInfoWidget->setProperties(props); } else myRomInfoWidget->clearProperties(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::handleContextMenu() { const string& cmd = myMenu->getSelectedTag().toString(); if(cmd == "override") { myGlobalProps->open(); } else if(cmd == "filter") { myFilters->open(); } else if(cmd == "reload") { updateListing(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::setListFilters() { const string& exts = instance().settings().getString("launcherexts"); myRomExts.clear(); LauncherFilterDialog::parseExts(myRomExts, exts); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool LauncherDialog::matchPattern(const string& s, const string& pattern) const { // This method is modelled after strcasestr, which we don't use // because it isn't guaranteed to be available everywhere // The strcasestr uses the KMP algorithm when the comparisons // reach a certain point, but since we'll be dealing with relatively // short strings, I think the overhead of building a KMP table // each time would be slower than the brute force method used here const char* haystack = s.c_str(); const char* needle = pattern.c_str(); uInt8 b = tolower(*needle); needle++; for(;; haystack++) { if(*haystack == '\0') /* No match */ return false; /* The first character matches */ if(tolower(*haystack) == b) { const char* rhaystack = haystack + 1; const char* rneedle = needle; for(;; rhaystack++, rneedle++) { if(*rneedle == '\0') /* Found a match */ return true; if(*rhaystack == '\0') /* No match */ return false; /* Nothing in this round */ if(tolower(*rhaystack) != tolower(*rneedle)) break; } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod) { // Grab the key before passing it to the actual dialog and check for // Control-R (reload ROM listing) if(StellaModTest::isControl(mod) && key == KBDK_R) updateListing(); else Dialog::handleKeyDown(key, mod); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::handleMouseDown(int x, int y, MouseButton b, int clickCount) { // Grab right mouse button for context menu, send left to base class if(b == MouseButton::RIGHT) { // Add menu at current x,y mouse location myMenu->show(x + getAbsX(), y + getAbsY()); } else Dialog::handleMouseDown(x, y, b, clickCount); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case kLoadROMCmd: case ListWidget::kActivatedCmd: case ListWidget::kDoubleClickedCmd: { int item = myList->getSelected(); if(item >= 0) { const FilesystemNode romnode(myGameList->path(item)); // Directory's should be selected (ie, enter them and redisplay) if(romnode.isDirectory()) { string dirname = ""; if(myGameList->name(item) == " [..]") { myCurrentNode = myCurrentNode.getParent(); if(!myNodeNames.empty()) dirname = myNodeNames.pop(); } else { myCurrentNode = romnode; myNodeNames.push(myGameList->name(item)); } updateListing(dirname); } else { const string& result = instance().createConsole(romnode, myGameList->md5(item)); if(result == EmptyString) instance().settings().setValue("lastrom", myList->getSelectedString()); else instance().frameBuffer().showMessage(result, MessagePosition::MiddleCenter, true); } } break; } case kOptionsCmd: myOptions->open(); break; case kPrevDirCmd: case ListWidget::kPrevDirCmd: myCurrentNode = myCurrentNode.getParent(); updateListing(myNodeNames.empty() ? "" : myNodeNames.pop()); break; case ListWidget::kSelectionChangedCmd: loadRomInfo(); break; case kQuitCmd: close(); instance().eventHandler().quit(); break; case kFirstRunMsgChosenCmd: // Show a file browser, starting from the users' home directory if(!myRomDir) myRomDir = make_unique(this, instance().frameBuffer().font(), _w, _h); myRomDir->show("Select ROM directory", "~", BrowserDialog::Directories, kStartupRomDirChosenCmd); break; case kStartupRomDirChosenCmd: { FilesystemNode dir(myRomDir->getResult()); instance().settings().setValue("romdir", dir.getShortPath()); [[fallthrough]]; } case kRomDirChosenCmd: myCurrentNode = FilesystemNode(instance().settings().getString("romdir")); if(!(myCurrentNode.exists() && myCurrentNode.isDirectory())) myCurrentNode = FilesystemNode("~"); updateListing(); break; case kReloadRomDirCmd: updateListing(); break; case kReloadFiltersCmd: setListFilters(); updateListing(); break; case ContextMenu::kItemSelectedCmd: handleContextMenu(); break; case EditableWidget::kAcceptCmd: case EditableWidget::kChangedCmd: // The updateListing() method knows what to do when the text changes updateListing(); break; default: Dialog::handleCommand(sender, cmd, data, 0); } } stella-5.1.1/src/gui/LauncherDialog.hxx000066400000000000000000000076431324334165500200070ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef LAUNCHER_DIALOG_HXX #define LAUNCHER_DIALOG_HXX class ButtonWidget; class CommandSender; class ContextMenu; class DialogContainer; class GameList; class BrowserDialog; class OptionsDialog; class GlobalPropsDialog; class LauncherFilterDialog; class OSystem; class Properties; class EditTextWidget; class RomInfoWidget; class StaticTextWidget; class StringListWidget; namespace GUI { class MessageBox; } #include "bspf.hxx" #include "Dialog.hxx" #include "FSNode.hxx" #include "Stack.hxx" class LauncherDialog : public Dialog { public: // These must be accessible from dialogs created by this class enum { kLoadROMCmd = 'STRT', // load currently selected ROM kRomDirChosenCmd = 'romc', // rom chosen kReloadRomDirCmd = 'rdrl', // reload the current listing kReloadFiltersCmd = 'rlfl' // reload filtering options and current listing }; public: LauncherDialog(OSystem& osystem, DialogContainer& parent, int x, int y, int w, int h); virtual ~LauncherDialog() = default; /** Get MD5sum for the currently selected file @return md5sum if a valid ROM file, else the empty string */ const string& selectedRomMD5(); /** Get node for the currently selected directory @return FilesystemNode currently active */ const FilesystemNode& currentNode() const { return myCurrentNode; } /** Reload the current listing */ void reload() { updateListing(); } private: void handleKeyDown(StellaKey key, StellaMod mod) override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void loadConfig() override; void updateListing(const string& nameToSelect = ""); void loadDirListing(); void loadRomInfo(); void handleContextMenu(); void setListFilters(); bool matchPattern(const string& s, const string& pattern) const; private: unique_ptr myOptions; unique_ptr myGameList; unique_ptr myMenu; unique_ptr myGlobalProps; unique_ptr myFilters; unique_ptr myRomDir; unique_ptr myFirstRunMsg; ButtonWidget* myStartButton; ButtonWidget* myPrevDirButton; ButtonWidget* myOptionsButton; ButtonWidget* myQuitButton; StringListWidget* myList; StaticTextWidget* myDirLabel; EditTextWidget* myDir; StaticTextWidget* myRomCount; EditTextWidget* myPattern; RomInfoWidget* myRomInfoWidget; int mySelectedItem; FilesystemNode myCurrentNode; Common::FixedStack myNodeNames; StringList myRomExts; enum { kPrevDirCmd = 'PRVD', kOptionsCmd = 'OPTI', kQuitCmd = 'QUIT', kFirstRunMsgChosenCmd = 'frmc', kStartupRomDirChosenCmd = 'rmsc' }; private: // Following constructors and assignment operators not supported LauncherDialog() = delete; LauncherDialog(const LauncherDialog&) = delete; LauncherDialog(LauncherDialog&&) = delete; LauncherDialog& operator=(const LauncherDialog&) = delete; LauncherDialog& operator=(LauncherDialog&&) = delete; }; #endif stella-5.1.1/src/gui/LauncherFilterDialog.cxx000066400000000000000000000163271324334165500211470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "OSystem.hxx" #include "FSNode.hxx" #include "PopUpWidget.hxx" #include "Settings.hxx" #include "Widget.hxx" #include "Font.hxx" #include "LauncherDialog.hxx" #include "LauncherFilterDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LauncherFilterDialog::LauncherFilterDialog(GuiObject* boss, const GUI::Font& font) : Dialog(boss->instance(), boss->parent()), CommandSender(boss) { const int lineHeight = font.getLineHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos; int lwidth = font.getStringWidth("Show "), pwidth = font.getStringWidth("ROMs ending with"); WidgetArray wid; VariantList items; // Set real dimensions _w = 3 * buttonWidth;//lwidth + pwidth + fontWidth*5 + 10; xpos = 10; ypos = 10; // Types of files to show VarList::push_back(items, "All files", "allfiles"); VarList::push_back(items, "All ROMs", "allroms"); VarList::push_back(items, "ROMs ending with", "__EXTS"); myFileType = new PopUpWidget(this, font, xpos, ypos, pwidth, lineHeight, items, "Show ", lwidth, kFileTypeChanged); wid.push_back(myFileType); ypos += lineHeight + 10; // Different types of ROM extensions xpos = 40; myRomType[0] = new CheckboxWidget(this, font, xpos, ypos, ourRomTypes[0][0]); int rightcol = xpos + myRomType[0]->getWidth() + 10; myRomType[3] = new CheckboxWidget(this, font, xpos+rightcol, ypos, ourRomTypes[0][3]); ypos += lineHeight + 4; myRomType[1] = new CheckboxWidget(this, font, xpos, ypos, ourRomTypes[0][1]); myRomType[4] = new CheckboxWidget(this, font, xpos+rightcol, ypos, ourRomTypes[0][4]); ypos += lineHeight + 4; myRomType[2] = new CheckboxWidget(this, font, xpos, ypos, ourRomTypes[0][2]); ypos += lineHeight + 10; _h = ypos + buttonHeight + 20; // Add Defaults, OK and Cancel buttons ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherFilterDialog::parseExts(StringList& list, const string& type) { // Assume the list is empty before this method is called if(type == "allroms") { for(uInt32 i = 0; i < 5; ++i) list.push_back(ourRomTypes[1][i]); } else if(type != "allfiles") { // Since istringstream swallows whitespace, we have to make the // delimiters be spaces string exts = type, ext; replace(exts.begin(), exts.end(), ':', ' '); istringstream buf(exts); while(buf >> ext) { for(uInt32 i = 0; i < 5; ++i) { if(ourRomTypes[1][i] == ext) { list.push_back(ext); break; } } } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool LauncherFilterDialog::isValidRomName(const string& name, const StringList& exts) { string::size_type idx = name.find_last_of('.'); if(idx != string::npos) { const char* const ext = name.c_str() + idx + 1; for(const auto& s: exts) if(BSPF::equalsIgnoreCase(ext, s)) return true; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool LauncherFilterDialog::isValidRomName(const FilesystemNode& node, string& ext) { const string& name = node.getPath(); string::size_type idx = name.find_last_of('.'); if(idx != string::npos) { const char* const e = name.c_str() + idx + 1; for(uInt32 i = 0; i < 5; ++i) { if(BSPF::equalsIgnoreCase(e, ourRomTypes[1][i])) { ext = e; return true; } } } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherFilterDialog::loadConfig() { handleFileTypeChange(instance().settings().getString("launcherexts")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherFilterDialog::saveConfig() { const string& type = myFileType->getSelectedTag().toString(); if(type == "allfiles" || type == "allroms") instance().settings().setValue("launcherexts", type); else { ostringstream buf; for(uInt32 i = 0; i < 5; ++i) if(myRomType[i]->getState()) buf << ourRomTypes[1][i] << ":"; // No ROMs selected means use all files if(buf.str() == "") instance().settings().setValue("launcherexts", "allfiles"); else instance().settings().setValue("launcherexts", buf.str()); } // Let parent know about the changes sendCommand(LauncherDialog::kReloadFiltersCmd, 0, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherFilterDialog::setDefaults() { handleFileTypeChange("allfiles"); _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherFilterDialog::handleFileTypeChange(const string& type) { bool enable = (type != "allfiles" && type != "allroms"); for(uInt32 i = 0; i < 5; ++i) myRomType[i]->setEnabled(enable); if(enable) { myFileType->setSelected("__EXTS", ""); // Since istringstream swallows whitespace, we have to make the // delimiters be spaces string exts = type, ext; replace(exts.begin(), exts.end(), ':', ' '); istringstream buf(exts); while(buf >> ext) { for(uInt32 i = 0; i < 5; ++i) { if(ourRomTypes[1][i] == ext) { myRomType[i]->setState(true); break; } } } } else myFileType->setSelected(type, ""); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LauncherFilterDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; case kFileTypeChanged: handleFileTypeChange(myFileType->getSelectedTag().toString()); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* const LauncherFilterDialog::ourRomTypes[2][5] = { { ".a26", ".bin", ".rom", ".zip", ".gz" }, { "a26", "bin", "rom", "zip", "gz" } }; stella-5.1.1/src/gui/LauncherFilterDialog.hxx000066400000000000000000000052721324334165500211510ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef LAUNCHER_FILTER_DIALOG_HXX #define LAUNCHER_FILTER_DIALOG_HXX class CommandSender; class DialogContainer; class FilesystemNode; class CheckboxWidget; class PopUpWidget; class OSystem; #include "bspf.hxx" #include "Dialog.hxx" #include "Settings.hxx" class LauncherFilterDialog : public Dialog, public CommandSender { public: LauncherFilterDialog(GuiObject* boss, const GUI::Font& font); virtual ~LauncherFilterDialog() = default; /** Add valid extensions from 'exts' to the given StringList */ static void parseExts(StringList& list, const string& exts); /** Is this a valid ROM filename (does it have a valid extension from those specified in the list of extensions). @param name Filename of potential ROM file @param exts The list of extensions to consult */ static bool isValidRomName(const string& name, const StringList& exts); /** Is this a valid ROM filename (does it have a valid extension?). @param name File node of potential ROM file @param ext The extension extracted from the given file */ static bool isValidRomName(const FilesystemNode& name, string& ext); private: void loadConfig() override; void saveConfig() override; void setDefaults() override; void handleFileTypeChange(const string& type); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: PopUpWidget* myFileType; CheckboxWidget* myRomType[5]; enum { kFileTypeChanged = 'LFDc' }; // Holds static strings representing ROM types static const char* const ourRomTypes[2][5]; private: // Following constructors and assignment operators not supported LauncherFilterDialog() = delete; LauncherFilterDialog(const LauncherFilterDialog&) = delete; LauncherFilterDialog(LauncherFilterDialog&&) = delete; LauncherFilterDialog& operator=(const LauncherFilterDialog&) = delete; LauncherFilterDialog& operator=(LauncherFilterDialog&&) = delete; }; #endif stella-5.1.1/src/gui/ListWidget.cxx000066400000000000000000000307611324334165500171750ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #include "OSystem.hxx" #include "Widget.hxx" #include "ScrollBarWidget.hxx" #include "Dialog.hxx" #include "FrameBuffer.hxx" #include "StellaKeys.hxx" #include "ListWidget.hxx" #include "bspf.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ListWidget::ListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, bool quickSelect) : EditableWidget(boss, font, x, y, 16, 16), _rows(0), _cols(0), _currentPos(0), _selectedItem(-1), _highlightedItem(-1), _editMode(false), _currentKeyDown(KBDK_UNKNOWN), _quickSelect(quickSelect), _quickSelectTime(0) { _flags = WIDGET_ENABLED | WIDGET_CLEARBG | WIDGET_RETAIN_FOCUS; _bgcolor = kWidColor; _bgcolorhi = kWidColor; _textcolor = kTextColor; _textcolorhi = kTextColor; _cols = w / _fontWidth; _rows = h / _fontHeight; // Set real dimensions _w = w - kScrollBarWidth; _h = h + 2; // Create scrollbar and attach to the list _scrollBar = new ScrollBarWidget(boss, font, _x + _w, _y, kScrollBarWidth, _h); _scrollBar->setTarget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::setSelected(int item) { if(item < 0 || item >= int(_list.size())) { setDirty(); // Simply redraw and exit return; } if(isEnabled()) { if(_editMode) abortEditMode(); _selectedItem = item; sendCommand(ListWidget::kSelectionChangedCmd, _selectedItem, _id); _currentPos = _selectedItem - _rows / 2; scrollToSelected(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::setSelected(const string& item) { int selected = -1; if(!_list.empty()) { if(item == "") selected = 0; else { uInt32 itemToSelect = 0; for(const auto& iter: _list) { if(item == iter) { selected = itemToSelect; break; } ++itemToSelect; } if(itemToSelect > _list.size() || selected == -1) selected = 0; } } setSelected(selected); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::setHighlighted(int item) { if(item < -1 || item >= int(_list.size())) return; if(isEnabled()) { if(_editMode) abortEditMode(); _highlightedItem = item; // Only scroll the list if we're about to pass the page boundary if(_currentPos == 0) _currentPos = _highlightedItem; else if(_highlightedItem == _currentPos + _rows) _currentPos += _rows; scrollToHighlighted(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& ListWidget::getSelectedString() const { return (_selectedItem >= 0 && _selectedItem < int(_list.size())) ? _list[_selectedItem] : EmptyString; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::scrollTo(int item) { int size = int(_list.size()); if (item >= size) item = size - 1; if (item < 0) item = 0; if(_currentPos != item) { _currentPos = item; scrollBarRecalc(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int ListWidget::getWidth() const { return _w + kScrollBarWidth; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::recalc() { int size = int(_list.size()); if (_currentPos >= size) _currentPos = size - 1; if (_currentPos < 0) _currentPos = 0; if(_selectedItem < 0 || _selectedItem >= size) _selectedItem = 0; _editMode = false; _scrollBar->_numEntries = int(_list.size()); _scrollBar->_entriesPerPage = _rows; // Reset to normal data entry abortEditMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::scrollBarRecalc() { _scrollBar->_currentPos = _currentPos; _scrollBar->recalc(); sendCommand(ListWidget::kScrolledCmd, _currentPos, _id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { if (!isEnabled()) return; // First check whether the selection changed int newSelectedItem; newSelectedItem = findItem(x, y); if (newSelectedItem >= int(_list.size())) return; if (_selectedItem != newSelectedItem) { if (_editMode) abortEditMode(); _selectedItem = newSelectedItem; sendCommand(ListWidget::kSelectionChangedCmd, _selectedItem, _id); setDirty(); } // TODO: Determine where inside the string the user clicked and place the // caret accordingly. See _editScrollOffset and EditTextWidget::handleMouseDown. } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { // If this was a double click and the mouse is still over the selected item, // send the double click command if (clickCount == 2 && (_selectedItem == findItem(x, y))) { sendCommand(ListWidget::kDoubleClickedCmd, _selectedItem, _id); // Start edit mode if(isEditable() && !_editMode) startEditMode(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::handleMouseWheel(int x, int y, int direction) { _scrollBar->handleMouseWheel(x, y, direction); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int ListWidget::findItem(int x, int y) const { return (y - 1) / _fontHeight + _currentPos; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ListWidget::handleText(char text) { bool handled = true; int oldSelectedItem = _selectedItem; if (!_editMode && _quickSelect) { // Quick selection mode: Go to first list item starting with this key // (or a substring accumulated from the last couple key presses). // Only works in a useful fashion if the list entries are sorted. // TODO: Maybe this should be off by default, and instead we add a // method "enableQuickSelect()" or so ? uInt64 time = instance().getTicks() / 1000; if (_quickSelectTime < time) _quickSelectStr = text; else _quickSelectStr += text; _quickSelectTime = time + _QUICK_SELECT_DELAY; // FIXME: This is bad slow code (it scans the list linearly each time a // key is pressed); it could be much faster. Only of importance if we have // quite big lists to deal with -- so for now we can live with this lazy // implementation :-) int newSelectedItem = 0; for(const auto& i: _list) { if(BSPF::startsWithIgnoreCase(i, _quickSelectStr)) { _selectedItem = newSelectedItem; break; } newSelectedItem++; } } else if (_editMode) { // Class EditableWidget handles all text editing related key presses for us handled = EditableWidget::handleText(text); } if (_selectedItem != oldSelectedItem) { _scrollBar->draw(); scrollToSelected(); sendCommand(ListWidget::kSelectionChangedCmd, _selectedItem, _id); } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ListWidget::handleKeyDown(StellaKey key, StellaMod mod) { // Ignore all Alt-mod keys if(StellaModTest::isAlt(mod)) return true; bool handled = true; if (!_editMode) { switch(key) { case KBDK_SPACE: // Snap list back to currently highlighted line if(_highlightedItem >= 0) { _currentPos = _highlightedItem; scrollToHighlighted(); } break; default: handled = false; } } _currentKeyDown = key; return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ListWidget::handleKeyUp(StellaKey key, StellaMod mod) { if (key == _currentKeyDown) _currentKeyDown = KBDK_UNKNOWN; return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ListWidget::handleEvent(Event::Type e) { if(!isEnabled() || _editMode) return false; bool handled = true; int oldSelectedItem = _selectedItem; int size = int(_list.size()); switch(e) { case Event::UISelect: if (_selectedItem >= 0) { if (isEditable()) startEditMode(); else sendCommand(ListWidget::kActivatedCmd, _selectedItem, _id); } break; case Event::UIUp: if (_selectedItem > 0) _selectedItem--; break; case Event::UIDown: if (_selectedItem < size - 1) _selectedItem++; break; case Event::UIPgUp: _selectedItem -= _rows - 1; if (_selectedItem < 0) _selectedItem = 0; break; case Event::UIPgDown: _selectedItem += _rows - 1; if (_selectedItem >= size) _selectedItem = size - 1; break; case Event::UIHome: _selectedItem = 0; break; case Event::UIEnd: _selectedItem = size - 1; break; case Event::UIPrevDir: sendCommand(ListWidget::kPrevDirCmd, _selectedItem, _id); break; default: handled = false; } if (_selectedItem != oldSelectedItem) { _scrollBar->draw(); scrollToSelected(); sendCommand(ListWidget::kSelectionChangedCmd, _selectedItem, _id); } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::lostFocusWidget() { _editMode = false; // Reset to normal data entry abortEditMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case GuiObject::kSetPositionCmd: if (_currentPos != data) { _currentPos = data; setDirty(); // Let boss know the list has scrolled sendCommand(ListWidget::kScrolledCmd, _currentPos, _id); } break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::scrollToCurrent(int item) { // Only do something if the current item is not in our view port if (item < _currentPos) { // it's above our view _currentPos = item; } else if (item >= _currentPos + _rows ) { // it's below our view _currentPos = item - _rows + 1; } if (_currentPos < 0 || _rows > int(_list.size())) _currentPos = 0; else if (_currentPos + _rows > int(_list.size())) _currentPos = int(_list.size()) - _rows; int oldScrollPos = _scrollBar->_currentPos; _scrollBar->_currentPos = _currentPos; _scrollBar->recalc(); setDirty(); if(oldScrollPos != _currentPos) sendCommand(ListWidget::kScrolledCmd, _currentPos, _id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::startEditMode() { if (isEditable() && !_editMode && _selectedItem >= 0) { _editMode = true; setText(_list[_selectedItem]); // Widget gets raw data while editing EditableWidget::startEditMode(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::endEditMode() { if (!_editMode) return; // Send a message that editing finished with a return/enter key press _editMode = false; _list[_selectedItem] = editString(); sendCommand(ListWidget::kDataChangedCmd, _selectedItem, _id); // Reset to normal data entry EditableWidget::endEditMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ListWidget::abortEditMode() { // Undo any changes made _editMode = false; // Reset to normal data entry EditableWidget::abortEditMode(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt64 ListWidget::_QUICK_SELECT_DELAY = 300; stella-5.1.1/src/gui/ListWidget.hxx000066400000000000000000000100621324334165500171720ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef LIST_WIDGET_HXX #define LIST_WIDGET_HXX class GuiObject; class ScrollBarWidget; #include "Rect.hxx" #include "Command.hxx" #include "EditableWidget.hxx" /** ListWidget */ class ListWidget : public EditableWidget { public: enum { kDoubleClickedCmd = 'LIdb', // double click on item - 'data' will be item index kActivatedCmd = 'LIac', // item activated by return/enter - 'data' will be item index kDataChangedCmd = 'LIch', // item data changed - 'data' will be item index kRClickedCmd = 'LIrc', // right click on item - 'data' will be item index kSelectionChangedCmd = 'Lsch', // selection changed - 'data' will be item index kScrolledCmd = 'Lscl', // list scrolled - 'data' will be current position kPrevDirCmd = 'Lpdr' // request to go to parent list, if applicable }; public: ListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, bool quickSelect); virtual ~ListWidget() = default; int rows() const { return _rows; } int currentPos() const { return _currentPos; } int getSelected() const { return _selectedItem; } void setSelected(int item); void setSelected(const string& item); int getHighlighted() const { return _highlightedItem; } void setHighlighted(int item); const StringList& getList() const { return _list; } const string& getSelectedString() const; void scrollTo(int item); // Account for the extra width of embedded scrollbar int getWidth() const override; static void setQuickSelectDelay(uInt64 time) { _QUICK_SELECT_DELAY = time; } protected: void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; bool handleText(char text) override; bool handleKeyDown(StellaKey key, StellaMod mod) override; bool handleKeyUp(StellaKey key, StellaMod mod) override; bool handleEvent(Event::Type e) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; virtual void drawWidget(bool hilite) override = 0; virtual GUI::Rect getEditRect() const override = 0; int findItem(int x, int y) const; void recalc(); void scrollBarRecalc(); void startEditMode() override; void endEditMode() override; void abortEditMode() override; void lostFocusWidget() override; void scrollToSelected() { scrollToCurrent(_selectedItem); } void scrollToHighlighted() { scrollToCurrent(_highlightedItem); } private: void scrollToCurrent(int item); protected: int _rows; int _cols; int _currentPos; int _selectedItem; int _highlightedItem; bool _editMode; StellaKey _currentKeyDown; ScrollBarWidget* _scrollBar; StringList _list; string _backupString; bool _quickSelect; string _quickSelectStr; uInt64 _quickSelectTime; private: static uInt64 _QUICK_SELECT_DELAY; private: // Following constructors and assignment operators not supported ListWidget() = delete; ListWidget(const ListWidget&) = delete; ListWidget(ListWidget&&) = delete; ListWidget& operator=(const ListWidget&) = delete; ListWidget& operator=(ListWidget&&) = delete; }; #endif stella-5.1.1/src/gui/LoggerDialog.cxx000066400000000000000000000105601324334165500174500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "FSNode.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "Settings.hxx" #include "PopUpWidget.hxx" #include "StringListWidget.hxx" #include "StringParser.hxx" #include "Widget.hxx" #include "Font.hxx" #include "LoggerDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - LoggerDialog::LoggerDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h, bool uselargefont) : Dialog(osystem, parent), myLogInfo(nullptr) { const int lineHeight = font.getLineHeight(), buttonWidth = font.getStringWidth("Save log to disk") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos; WidgetArray wid; // Set real dimensions // This is one dialog that can take as much space as is available _w = max_w; _h = max_h; // Test listing of the log output xpos = 10; ypos = 10; myLogInfo = new StringListWidget(this, uselargefont ? font : instance().frameBuffer().infoFont(), xpos, ypos, _w - 2 * xpos, _h - buttonHeight - ypos - 20 - 2 * lineHeight, false); myLogInfo->setEditable(false); wid.push_back(myLogInfo); ypos += myLogInfo->getHeight() + 8; // Level of logging (how much info to print) xpos += 20; VariantList items; VarList::push_back(items, "None", "0"); VarList::push_back(items, "Basic", "1"); VarList::push_back(items, "Verbose", "2"); myLogLevel = new PopUpWidget(this, font, xpos, ypos, font.getStringWidth("Verbose"), lineHeight, items, "Log level ", font.getStringWidth("Log level ")); wid.push_back(myLogLevel); // Should log output also be shown on the console? xpos += myLogLevel->getWidth() + 30; myLogToConsole = new CheckboxWidget(this, font, xpos, ypos, "Print to console"); wid.push_back(myLogToConsole); // Add Defaults, OK and Cancel buttons ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Save log to disk", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LoggerDialog::loadConfig() { StringParser parser(instance().logMessages()); myLogInfo->setList(parser.stringList()); myLogInfo->setSelected(0); myLogLevel->setSelected(instance().settings().getString("loglevel"), "1"); myLogToConsole->setState(instance().settings().getBool("logtoconsole")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LoggerDialog::saveConfig() { instance().settings().setValue("loglevel", myLogLevel->getSelectedTag().toString()); instance().settings().setValue("logtoconsole", myLogToConsole->getState()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LoggerDialog::saveLogFile() { ostringstream path; path << "~" << BSPF::PATH_SEPARATOR << "stella.log"; FilesystemNode node(path.str()); ofstream out(node.getPath()); if(out.is_open()) out << instance().logMessages(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void LoggerDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kDefaultsCmd: saveLogFile(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/gui/LoggerDialog.hxx000066400000000000000000000033321324334165500174540ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef LOGGER_DIALOG_HXX #define LOGGER_DIALOG_HXX class GuiObject; class CheckboxWidget; class PopUpWidget; class StringListWidget; #include "Dialog.hxx" #include "bspf.hxx" class LoggerDialog : public Dialog { public: LoggerDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h, bool useLargeFont = true); virtual ~LoggerDialog() = default; private: void loadConfig() override; void saveConfig() override; void saveLogFile(); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: StringListWidget* myLogInfo; PopUpWidget* myLogLevel; CheckboxWidget* myLogToConsole; private: // Following constructors and assignment operators not supported LoggerDialog() = delete; LoggerDialog(const LoggerDialog&) = delete; LoggerDialog(LoggerDialog&&) = delete; LoggerDialog& operator=(const LoggerDialog&) = delete; LoggerDialog& operator=(LoggerDialog&&) = delete; }; #endif stella-5.1.1/src/gui/Menu.cxx000066400000000000000000000021071324334165500160130ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Dialog.hxx" #include "FrameBuffer.hxx" #include "OptionsDialog.hxx" #include "bspf.hxx" #include "Menu.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Menu::Menu(OSystem& osystem) : DialogContainer(osystem) { myBaseDialog = new OptionsDialog(myOSystem, *this, nullptr, FrameBuffer::kFBMinW, FrameBuffer::kFBMinH, OptionsDialog::emulator); } stella-5.1.1/src/gui/Menu.hxx000066400000000000000000000023751324334165500160270ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef MENU_HXX #define MENU_HXX class OSystem; #include "DialogContainer.hxx" /** The base dialog for all configuration menus in Stella. @author Stephen Anthony */ class Menu : public DialogContainer { public: /** Create a new menu stack */ Menu(OSystem& osystem); virtual ~Menu() = default; private: // Following constructors and assignment operators not supported Menu() = delete; Menu(const Menu&) = delete; Menu(Menu&&) = delete; Menu& operator=(const Menu&) = delete; Menu& operator=(Menu&&) = delete; }; #endif stella-5.1.1/src/gui/MessageBox.cxx000066400000000000000000000062371324334165500171540ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Dialog.hxx" #include "OSystem.hxx" #include "Version.hxx" #include "Widget.hxx" #include "Font.hxx" #include "StringParser.hxx" #include "MessageBox.hxx" namespace GUI { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MessageBox::MessageBox(GuiObject* boss, const GUI::Font& font, const StringList& text, int max_w, int max_h, int cmd, const string& okText, const string& cancelText, bool focusOKButton) : Dialog(boss->instance(), boss->parent(), 0, 0, max_w, max_h), CommandSender(boss), myCmd(cmd) { addText(font, text); WidgetArray wid; addOKCancelBGroup(wid, font, okText, cancelText, focusOKButton); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MessageBox::MessageBox(GuiObject* boss, const GUI::Font& font, const string& text, int max_w, int max_h, int cmd, const string& okText, const string& cancelText, bool focusOKButton) : MessageBox(boss, font, StringParser(text).stringList(), max_w, max_h, cmd, okText, cancelText, focusOKButton) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MessageBox::addText(const GUI::Font& font, const StringList& text) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(); int xpos, ypos; // Set real dimensions int str_w = 0; for(const auto& s: text) str_w = std::max(int(s.length()), str_w); _w = std::min(str_w * fontWidth + 20, _w); _h = std::min(uInt32((text.size() + 2) * lineHeight + 20), uInt32(_h)); xpos = 10; ypos = 10; for(const auto& s: text) { new StaticTextWidget(this, font, xpos, ypos, _w - 20, fontHeight, s, TextAlign::Left); ypos += fontHeight; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void MessageBox::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: { close(); // Send a signal to the calling class that 'OK' has been selected // Since we aren't derived from a widget, we don't have a 'data' or 'id' if(myCmd) sendCommand(myCmd, 0, 0); break; } default: Dialog::handleCommand(sender, cmd, data, id); break; } } } // namespace GUI stella-5.1.1/src/gui/MessageBox.hxx000066400000000000000000000043001324334165500171460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef MESSAGE_BOX_HXX #define MESSAGE_BOX_HXX class GuiObject; class StaticTextWidget; #include "Dialog.hxx" #include "Command.hxx" namespace GUI { /** * Show a simple message box containing the given text, with buttons * prompting the user to accept or reject. If the user selects 'OK', * the value of 'cmd' is returned. */ class MessageBox : public Dialog, public CommandSender { public: MessageBox(GuiObject* boss, const GUI::Font& font, const StringList& text, int max_w, int max_h, int cmd = 0, const string& okText = "OK", const string& cancelText = "Cancel", bool focusOKButton = true); MessageBox(GuiObject* boss, const GUI::Font& font, const string& text, int max_w, int max_h, int cmd = 0, const string& okText = "OK", const string& cancelText = "Cancel", bool focusOKButton = true); virtual ~MessageBox() = default; /** Place the input dialog onscreen and center it */ void show() { open(); } private: void addText(const GUI::Font& font, const StringList& text); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: int myCmd; private: // Following constructors and assignment operators not supported MessageBox() = delete; MessageBox(const MessageBox&) = delete; MessageBox(MessageBox&&) = delete; MessageBox& operator=(const MessageBox&) = delete; MessageBox& operator=(MessageBox&&) = delete; }; } // namespace GUI #endif stella-5.1.1/src/gui/OptionsDialog.cxx000066400000000000000000000165471324334165500176770ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "EventHandler.hxx" #include "Dialog.hxx" #include "DialogContainer.hxx" #include "Widget.hxx" #include "Font.hxx" #include "Control.hxx" #include "VideoDialog.hxx" #include "AudioDialog.hxx" #include "InputDialog.hxx" #include "UIDialog.hxx" #include "SnapshotDialog.hxx" #include "ConfigPathDialog.hxx" #include "RomAuditDialog.hxx" #include "GameInfoDialog.hxx" #include "LoggerDialog.hxx" #include "DeveloperDialog.hxx" #include "HelpDialog.hxx" #include "AboutDialog.hxx" #include "OptionsDialog.hxx" #include "Launcher.hxx" #ifdef CHEATCODE_SUPPORT #include "CheatCodeDialog.hxx" #endif #include "bspf.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OptionsDialog::OptionsDialog(OSystem& osystem, DialogContainer& parent, GuiObject* boss, int max_w, int max_h, stellaMode mode) : Dialog(osystem, parent), myMode(mode) { const GUI::Font& font = instance().frameBuffer().font(); const int buttonWidth = font.getStringWidth("Developer Settings" + ELLIPSIS) + 20, buttonHeight = font.getLineHeight() + 6, rowHeight = font.getLineHeight() + 10; _w = 2 * buttonWidth + 30; _h = 7 * rowHeight + 15; int xoffset = 10, yoffset = 10; WidgetArray wid; ButtonWidget* b = nullptr; auto ADD_OD_BUTTON = [&](const string& label, int cmd) { ButtonWidget* bw = new ButtonWidget(this, font, xoffset, yoffset, buttonWidth, buttonHeight, label, cmd); yoffset += rowHeight; return bw; }; b = ADD_OD_BUTTON("Video Settings" + ELLIPSIS, kVidCmd); wid.push_back(b); b = ADD_OD_BUTTON("Audio Settings" + ELLIPSIS, kAudCmd); #ifndef SOUND_SUPPORT b->clearFlags(WIDGET_ENABLED); #endif wid.push_back(b); b = ADD_OD_BUTTON("Input Settings" + ELLIPSIS, kInptCmd); wid.push_back(b); b = ADD_OD_BUTTON("UI Settings" + ELLIPSIS, kUsrIfaceCmd); wid.push_back(b); b = ADD_OD_BUTTON("Snapshot Settings" + ELLIPSIS, kSnapCmd); wid.push_back(b); b = ADD_OD_BUTTON("Config Paths" + ELLIPSIS, kCfgPathsCmd); wid.push_back(b); b = ADD_OD_BUTTON("Developer Settings" + ELLIPSIS, kDevelopCmd); wid.push_back(b); // Move to second column xoffset += buttonWidth + 10; yoffset = 10; myGameInfoButton = ADD_OD_BUTTON("Game Properties" + ELLIPSIS, kInfoCmd); wid.push_back(myGameInfoButton); myCheatCodeButton = ADD_OD_BUTTON("Cheat Code" + ELLIPSIS, kCheatCmd); #ifndef CHEATCODE_SUPPORT myCheatCodeButton->clearFlags(WIDGET_ENABLED); #endif wid.push_back(myCheatCodeButton); myRomAuditButton = ADD_OD_BUTTON("Audit ROMs" + ELLIPSIS, kAuditCmd); wid.push_back(myRomAuditButton); b = ADD_OD_BUTTON("System Logs" + ELLIPSIS, kLoggerCmd); wid.push_back(b); b = ADD_OD_BUTTON("Help" + ELLIPSIS, kHelpCmd); wid.push_back(b); b = ADD_OD_BUTTON("About" + ELLIPSIS, kAboutCmd); wid.push_back(b); b = ADD_OD_BUTTON("Exit Menu", kExitCmd); wid.push_back(b); addCancelWidget(b); // Now create all the dialogs attached to each menu button myVideoDialog = make_unique(osystem, parent, font, max_w, max_h); myAudioDialog = make_unique(osystem, parent, font); myInputDialog = make_unique(osystem, parent, font, max_w, max_h); myUIDialog = make_unique(osystem, parent, font); mySnapshotDialog = make_unique(osystem, parent, font); myConfigPathDialog = make_unique(osystem, parent, font, boss); myRomAuditDialog = make_unique(osystem, parent, font, max_w, max_h); myGameInfoDialog = make_unique(osystem, parent, font, this); #ifdef CHEATCODE_SUPPORT myCheatCodeDialog = make_unique(osystem, parent, font); #endif myLoggerDialog = make_unique(osystem, parent, font, max_w, max_h); myDeveloperDialog = make_unique(osystem, parent, font, max_w, max_h); myHelpDialog = make_unique(osystem, parent, font); myAboutDialog = make_unique(osystem, parent, font); addToFocusList(wid); // Certain buttons are disabled depending on mode if(myMode == launcher) { myCheatCodeButton->clearFlags(WIDGET_ENABLED); } else { myRomAuditButton->clearFlags(WIDGET_ENABLED); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OptionsDialog::~OptionsDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OptionsDialog::loadConfig() { // Determine whether we should show the 'Game Information' button // We always show it in emulation mode, or if a valid ROM is selected // in launcher mode switch(instance().eventHandler().state()) { case EventHandlerState::EMULATION: myGameInfoButton->setFlags(WIDGET_ENABLED); break; case EventHandlerState::LAUNCHER: if(instance().launcher().selectedRomMD5() != "") myGameInfoButton->setFlags(WIDGET_ENABLED); else myGameInfoButton->clearFlags(WIDGET_ENABLED); break; default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void OptionsDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kVidCmd: myVideoDialog->open(); break; case kAudCmd: myAudioDialog->open(); break; case kInptCmd: myInputDialog->open(); break; case kUsrIfaceCmd: myUIDialog->open(); break; case kSnapCmd: mySnapshotDialog->open(); break; case kCfgPathsCmd: myConfigPathDialog->open(); break; case kAuditCmd: myRomAuditDialog->open(); break; case kInfoCmd: myGameInfoDialog->open(); break; #ifdef CHEATCODE_SUPPORT case kCheatCmd: myCheatCodeDialog->open(); break; #endif case kLoggerCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary if(myMode != launcher) { uInt32 w = 0, h = 0; bool uselargefont = getResizableBounds(w, h); myLoggerDialog = make_unique(instance(), parent(), instance().frameBuffer().font(), w, h, uselargefont); } myLoggerDialog->open(); break; case kDevelopCmd: myDeveloperDialog->open(); break; case kHelpCmd: myHelpDialog->open(); break; case kAboutCmd: myAboutDialog->open(); break; case kExitCmd: if(myMode != emulator) close(); else instance().eventHandler().leaveMenuMode(); break; default: Dialog::handleCommand(sender, cmd, data, 0); } } stella-5.1.1/src/gui/OptionsDialog.hxx000066400000000000000000000063171324334165500176760ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef OPTIONS_DIALOG_HXX #define OPTIONS_DIALOG_HXX class CommandSender; class DialogContainer; class GuiObject; class OSystem; class VideoDialog; class AudioDialog; class InputDialog; class UIDialog; class SnapshotDialog; class ConfigPathDialog; class RomAuditDialog; class GameInfoDialog; #ifdef CHEATCODE_SUPPORT class CheatCodeDialog; #endif class HelpDialog; class AboutDialog; class LoggerDialog; #include "Dialog.hxx" #include "bspf.hxx" class DeveloperDialog; class OptionsDialog : public Dialog { public: // Current Stella mode enum stellaMode { launcher, emulator, debugger }; OptionsDialog(OSystem& osystem, DialogContainer& parent, GuiObject* boss, int max_w, int max_h, stellaMode mode); virtual ~OptionsDialog(); private: void loadConfig() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: unique_ptr myVideoDialog; unique_ptr myAudioDialog; unique_ptr myInputDialog; unique_ptr myUIDialog; unique_ptr mySnapshotDialog; unique_ptr myConfigPathDialog; unique_ptr myRomAuditDialog; unique_ptr myGameInfoDialog; #ifdef CHEATCODE_SUPPORT unique_ptr myCheatCodeDialog; #endif unique_ptr myLoggerDialog; unique_ptr myDeveloperDialog; unique_ptr myHelpDialog; unique_ptr myAboutDialog; ButtonWidget* myRomAuditButton; ButtonWidget* myGameInfoButton; ButtonWidget* myCheatCodeButton; // Indicates if this dialog is used for global (vs. in-game) settings stellaMode myMode; enum { kVidCmd = 'VIDO', kAudCmd = 'AUDO', kInptCmd = 'INPT', kUsrIfaceCmd = 'URIF', kSnapCmd = 'SNAP', kCfgPathsCmd = 'CFGP', kAuditCmd = 'RAUD', kInfoCmd = 'INFO', kCheatCmd = 'CHET', kLoggerCmd = 'LOGG', kDevelopCmd = 'DEVL', kHelpCmd = 'HELP', kAboutCmd = 'ABOU', kExitCmd = 'EXIM' }; private: // Following constructors and assignment operators not supported OptionsDialog() = delete; OptionsDialog(const OptionsDialog&) = delete; OptionsDialog(OptionsDialog&&) = delete; OptionsDialog& operator=(const OptionsDialog&) = delete; OptionsDialog& operator=(OptionsDialog&&) = delete; }; #endif stella-5.1.1/src/gui/PopUpWidget.cxx000066400000000000000000000175071324334165500173300ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "ContextMenu.hxx" #include "DialogContainer.hxx" #include "PopUpWidget.hxx" // Little up/down arrow #ifndef FLAT_UI static uInt32 up_down_arrows[8] = { 0b00000000, 0b00001000, 0b00011100, 0b00111110, 0b00000000, 0b00111110, 0b00011100, 0b00001000, }; #else static uInt32 down_arrow[8] = { 0b100000001, 0b110000011, 0b111000111, 0b011101110, 0b001111100, 0b000111000, 0b000010000, 0b000000000 }; #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - PopUpWidget::PopUpWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const VariantList& list, const string& label, int labelWidth, int cmd) : Widget(boss, font, x, y - 1, w, h + 2), CommandSender(boss), _label(label), _labelWidth(labelWidth), _changed(false) { _flags = WIDGET_ENABLED | WIDGET_RETAIN_FOCUS; _bgcolor = kDlgColor; _bgcolorhi = kDlgColor; // do not highlight the background _textcolor = kTextColor; _textcolorhi = kTextColor; // do not highlight the label if(!_label.empty() && _labelWidth == 0) _labelWidth = _font.getStringWidth(_label); #ifndef FLAT_UI _w = w + _labelWidth + 15; #else _w = w + _labelWidth + 23; #endif // vertically center the arrows and text myTextY = (_h - _font.getFontHeight()) / 2; myArrowsY = (_h - 8) / 2; myMenu = make_unique(this, font, list, cmd, w); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::addItems(const VariantList& items) { myMenu->addItems(items); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::setSelected(const Variant& tag, const Variant& def) { myMenu->setSelected(tag, def); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::setSelectedIndex(int idx, bool changed) { _changed = changed; myMenu->setSelectedIndex(idx); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::setSelectedMax(bool changed) { _changed = changed; myMenu->setSelectedMax(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::clearSelection() { myMenu->clearSelection(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int PopUpWidget::getSelected() const { return myMenu->getSelected(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& PopUpWidget::getSelectedName() const { return myMenu->getSelectedName(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const Variant& PopUpWidget::getSelectedTag() const { return myMenu->getSelectedTag(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { if(isEnabled() && !myMenu->isVisible()) { // Add menu just underneath parent widget const GUI::Rect& image = instance().frameBuffer().imageRect(); const GUI::Rect& srect = dialog().surface().dstRect(); uInt32 tx = srect.x(), ty = srect.y(); tx += getAbsX() + _labelWidth - image.x(); ty += getAbsY() + getHeight() - image.y(); myMenu->show(tx, ty, myMenu->getSelected()); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::handleMouseWheel(int x, int y, int direction) { if(isEnabled() && !myMenu->isVisible()) { if(direction < 0) myMenu->sendSelectionUp(); else myMenu->sendSelectionDown(); } } #ifdef FLAT_UI // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::handleMouseEntered() { setFlags(WIDGET_HILITED); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::handleMouseLeft() { clearFlags(WIDGET_HILITED); setDirty(); } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool PopUpWidget::handleEvent(Event::Type e) { if(!isEnabled()) return false; switch(e) { case Event::UISelect: handleMouseDown(0, 0, MouseButton::LEFT, 0); return true; case Event::UIUp: case Event::UILeft: case Event::UIPgUp: return myMenu->sendSelectionUp(); case Event::UIDown: case Event::UIRight: case Event::UIPgDown: return myMenu->sendSelectionDown(); case Event::UIHome: return myMenu->sendSelectionFirst(); case Event::UIEnd: return myMenu->sendSelectionLast(); default: return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { // Intercept all events sent through the PromptWidget // They're likely from our ContextMenu, indicating a redraw is required dialog().setDirty(); // Pass the cmd on to our parent sendCommand(cmd, data, id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void PopUpWidget::drawWidget(bool hilite) { //cerr << "PopUpWidget::drawWidget\n"; FBSurface& s = dialog().surface(); int x = _x + _labelWidth; int w = _w - _labelWidth; #ifndef FLAT_UI // Draw the label, if any if(_labelWidth > 0) s.drawString(_font, _label, _x, _y + myTextY, _labelWidth, isEnabled() ? _textcolor : uInt32(kColor), TextAlign::Right); // Draw a thin frame around us. s.hLine(x, _y, x + w - 1, kColor); s.hLine(x, _y +_h-1, x + w - 1, kShadowColor); s.vLine(x, _y, _y+_h-1, kColor); s.vLine(x + w - 1, _y, _y +_h - 1, kShadowColor); // Fill the background s.fillRect(x + 1, _y + 1, w - 2, _h - 2, _changed ? kDbgChangedColor : kWidColor); // Draw an arrow pointing down at the right end to signal this is a dropdown/popup s.drawBitmap(up_down_arrows, x + w - 10, _y + myArrowsY, !isEnabled() ? kColor : hilite ? kTextColorHi : kTextColor); #else // Draw the label, if any if(_labelWidth > 0) s.drawString(_font, _label, _x, _y + myTextY, _labelWidth, isEnabled() ? _textcolor : uInt32(kColor), TextAlign::Left); // Draw a thin frame around us. s.frameRect(x, _y, w, _h, kColor); s.frameRect(x + w - 16, _y + 1, 15, _h - 2, isEnabled() && hilite ? kTextColorHi : kBGColorLo); // Fill the background s.fillRect(x + 1, _y + 1, w - 17, _h - 2, _changed ? kDbgChangedColor : kWidColor); s.fillRect(x + w - 15, _y + 2, 13, _h - 4, isEnabled() && hilite ? kWidColor : kBGColorHi); // Draw an arrow pointing down at the right end to signal this is a dropdown/popup s.drawBitmap(down_arrow, x + w - 13, _y + myArrowsY + 1, !isEnabled() ? kColor : kTextColor, 9u, 8u); #endif // Draw the selected entry, if any const string& name = myMenu->getSelectedName(); TextAlign align = (_font.getStringWidth(name) > w-6) ? TextAlign::Right : TextAlign::Left; s.drawString(_font, name, x+2, _y+myTextY, w-6, !isEnabled() ? kColor : kTextColor, align); } stella-5.1.1/src/gui/PopUpWidget.hxx000066400000000000000000000060321324334165500173240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef POPUP_WIDGET_HXX #define POPUP_WIDGET_HXX class GUIObject; class ContextMenu; #include "bspf.hxx" #include "Variant.hxx" #include "Command.hxx" #include "Widget.hxx" /** * Popup or dropdown widget which, when clicked, "pop up" a list of items and * lets the user pick on of them. * * Implementation wise, when the user selects an item, then a kPopUpItemSelectedCmd * is broadcast, with data being equal to the tag value of the selected entry. */ class PopUpWidget : public Widget, public CommandSender { public: PopUpWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const VariantList& items, const string& label, int labelWidth = 0, int cmd = 0); virtual ~PopUpWidget() = default; int getTop() const override { return _y + 1; } int getBottom() const override { return _y + 1 + getHeight(); } /** Add the given items to the widget. */ void addItems(const VariantList& items); /** Various selection methods passed directly to the underlying menu See ContextMenu.hxx for more information. */ void setSelected(const Variant& tag, const Variant& def = EmptyVariant); void setSelectedIndex(int idx, bool changed = false); void setSelectedMax(bool changed = false); void clearSelection(); int getSelected() const; const string& getSelectedName() const; const Variant& getSelectedTag() const; bool wantsFocus() const override { return true; } protected: void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; #ifdef FLAT_UI void handleMouseEntered() override; void handleMouseLeft() override; #endif bool handleEvent(Event::Type e) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void drawWidget(bool hilite) override; private: unique_ptr myMenu; int myArrowsY; int myTextY; string _label; int _labelWidth; bool _changed; private: // Following constructors and assignment operators not supported PopUpWidget() = delete; PopUpWidget(const PopUpWidget&) = delete; PopUpWidget(PopUpWidget&&) = delete; PopUpWidget& operator=(const PopUpWidget&) = delete; PopUpWidget& operator=(PopUpWidget&&) = delete; }; #endif stella-5.1.1/src/gui/ProgressDialog.cxx000066400000000000000000000057731324334165500200470ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "Widget.hxx" #include "Dialog.hxx" #include "Font.hxx" #include "DialogContainer.hxx" #include "ProgressDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ProgressDialog::ProgressDialog(GuiObject* boss, const GUI::Font& font, const string& message) : Dialog(boss->instance(), boss->parent()), myMessage(nullptr), mySlider(nullptr), myStart(0), myFinish(0), myStep(0) { const int fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), lineHeight = font.getLineHeight(); int xpos, ypos, lwidth; // Calculate real dimensions lwidth = font.getStringWidth(message); _w = lwidth + 2 * fontWidth; _h = lineHeight * 5; xpos = fontWidth; ypos = lineHeight; myMessage = new StaticTextWidget(this, font, xpos, ypos, lwidth, fontHeight, message, TextAlign::Center); myMessage->setTextColor(kTextColorEm); xpos = fontWidth; ypos += 2 * lineHeight; mySlider = new SliderWidget(this, font, xpos, ypos, lwidth, lineHeight, "", 0, 0); mySlider->setMinValue(1); mySlider->setMaxValue(100); open(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ProgressDialog::setMessage(const string& message) { myMessage->setLabel(message); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ProgressDialog::setRange(int start, int finish, int step) { myStart = start; myFinish = finish; myStep = int((step / 100.0) * (myFinish - myStart + 1)); mySlider->setMinValue(myStart); mySlider->setMaxValue(myFinish); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ProgressDialog::setProgress(int progress) { // Only increase the progress bar if we have arrived at a new step if(progress - mySlider->getValue() > myStep) { mySlider->setValue(progress); // Since this dialog is usually called in a tight loop that doesn't // yield, we need to manually tell the framebuffer that a redraw is // necessary // This isn't really an ideal solution, since all redrawing and // event handling is suspended until the dialog is closed instance().frameBuffer().update(); } } stella-5.1.1/src/gui/ProgressDialog.hxx000066400000000000000000000031171324334165500200420ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PROGRESS_DIALOG_HXX #define PROGRESS_DIALOG_HXX class GuiObject; class StaticTextWidget; class SliderWidget; #include "bspf.hxx" class ProgressDialog : public Dialog { public: ProgressDialog(GuiObject* boss, const GUI::Font& font, const string& message); virtual ~ProgressDialog() = default; void setMessage(const string& message); void setRange(int begin, int end, int step); void setProgress(int progress); private: StaticTextWidget* myMessage; SliderWidget* mySlider; int myStart, myFinish, myStep; private: // Following constructors and assignment operators not supported ProgressDialog() = delete; ProgressDialog(const ProgressDialog&) = delete; ProgressDialog(ProgressDialog&&) = delete; ProgressDialog& operator=(const ProgressDialog&) = delete; ProgressDialog& operator=(ProgressDialog&&) = delete; }; #endif stella-5.1.1/src/gui/RadioButtonWidget.cxx000066400000000000000000000147701324334165500205160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "FBSurface.hxx" #include "Font.hxx" #include "Dialog.hxx" #include "RadioButtonWidget.hxx" /* Radiobutton bitmaps */ #ifndef FLAT_UI static uInt32 radio_img_outercircle[14] = { 0b00001111110000, 0b00111111111100, 0b01110000001110, 0b01100000000110, 0b11000000000011, 0b11000000000011, 0b11000000000011, 0b11000000000011, 0b11000000000011, 0b11000000000011, 0b01100000000110, 0b01110000001110, 0b00111111111100, 0b00001111110000 }; static uInt32 radio_img_innercircle[10] = { 0b0011111100, 0b0111111110, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b0111111110, 0b0011111100 }; static uInt32 radio_img_active[8] = { 0b00111100, 0b01111110, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b01111110, 0b00111100 }; static uInt32 radio_img_inactive[8] = { 0b00111100, 0b01111110, 0b11100111, 0b11000011, 0b11000011, 0b11100111, 0b01111110, 0b00111100 }; #else static uInt32 radio_img_outercircle[14] = { 0b00001111110000, 0b00110000001100, 0b01000000000010, 0b01000000000010, 0b10000000000001, 0b10000000000001, 0b10000000000001, 0b10000000000001, 0b10000000000001, 0b10000000000001, 0b01000000000010, 0b01000000000010, 0b00110000001100, 0b00001111110000 }; static uInt32 radio_img_innercircle[12] = { 0b000111111000, 0b011111111110, 0b011111111110, 0b111111111111, 0b111111111111, 0b111111111111, 0b111111111111, 0b111111111111, 0b111111111111, 0b011111111110, 0b011111111110, 0b000111111000 }; static uInt32 radio_img_active[10] = { 0b0011111100, 0b0111111110, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b0111111110, 0b0011111100, }; static uInt32 radio_img_inactive[10] = { 0b0011111100, 0b0111111110, 0b1111001111, 0b1110000111, 0b1100000011, 0b1100000011, 0b1110000111, 0b1111001111, 0b0111111110, 0b0011111100 }; #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RadioButtonWidget::RadioButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, RadioButtonGroup* group, int cmd) : CheckboxWidget(boss, font, x, y, label, cmd), myGroup(group) { _flags = WIDGET_ENABLED; _bgcolor = _bgcolorhi = kWidColor; _editable = true; if(label == "") _w = 14; else _w = font.getStringWidth(label) + 20; _h = font.getFontHeight() < 14 ? 14 : font.getFontHeight(); // Depending on font size, either the font or box will need to be // centered vertically if(_h > 14) // center box _boxY = (_h - 14) / 2; else // center text _textY = (14 - _font.getFontHeight()) / 2; setFill(CheckboxWidget::Normal); myGroup->addWidget(this); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RadioButtonWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { if(isEnabled() && _editable && x >= 0 && x < _w && y >= 0 && y < _h) { if(!_state) setState(true); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RadioButtonWidget::setState(bool state, bool send) { if(_state != state) { _state = state; setDirty(); if(_state && send) sendCommand(_cmd, _state, _id); if (state) myGroup->select(this); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RadioButtonWidget::setFill(FillType type) { switch(type) { case CheckboxWidget::Normal: _img = radio_img_active; break; case CheckboxWidget::Inactive: _img = radio_img_inactive; break; default: break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RadioButtonWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); #ifndef FLAT_UI // Draw the outer bounding circle s.drawBitmap(radio_img_outercircle, _x, _y + _boxY, kShadowColor, 14, 14); // Draw the inner bounding circle with enabled color s.drawBitmap(radio_img_innercircle, _x + 2, _y + _boxY + 2, isEnabled() ? _bgcolor : uInt32(kColor), 10, 10); // draw state if(_state) s.drawBitmap(_img, _x + 3, _y + _boxY + 3, isEnabled() ? kCheckColor : kShadowColor); #else // Draw the outer bounding circle s.drawBitmap(radio_img_outercircle, _x, _y + _boxY, hilite ? kScrollColorHi : kShadowColor, 14, 14); // Draw the inner bounding circle with enabled color s.drawBitmap(radio_img_innercircle, _x + 1, _y + _boxY + 1, isEnabled() ? _bgcolor : kColor, 12, 12); // draw state if(_state) s.drawBitmap(_img, _x + 2, _y + _boxY + 2, isEnabled() ? hilite ? kScrollColorHi : kCheckColor : kShadowColor, 10); #endif // Finally draw the label s.drawString(_font, _label, _x + 20, _y + _textY, _w, isEnabled() ? kTextColor : kColor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RadioButtonGroup::addWidget(RadioButtonWidget* widget) { myWidgets.push_back(widget); // set first button as default widget->setState(myWidgets.size() == 1, false); mySelected = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RadioButtonGroup::select(RadioButtonWidget* widget) { uInt32 i = 0; for(const auto& w : myWidgets) { if(w == widget) { setSelected(i); break; } i++; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RadioButtonGroup::setSelected(uInt32 selected) { uInt32 i = 0; mySelected = selected; for(const auto& w : myWidgets) { (static_cast(w))->setState(i == mySelected); i++; } } stella-5.1.1/src/gui/RadioButtonWidget.hxx000066400000000000000000000047171324334165500205230ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef RADIOBUTTON_WIDGET_HXX #define RADIOBUTTON_WIDGET_HXX #include "bspf.hxx" #include "Widget.hxx" class Dialog; class RadioButtonGroup; class RadioButtonWidget : public CheckboxWidget { public: RadioButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, RadioButtonGroup* group, int cmd = 0); void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void setState(bool state, bool send = true); protected: void setFill(FillType type); void drawWidget(bool hilite) override; private: RadioButtonGroup* myGroup; private: // Following constructors and assignment operators not supported RadioButtonWidget() = delete; RadioButtonWidget(const RadioButtonWidget&) = delete; RadioButtonWidget(RadioButtonWidget&&) = delete; RadioButtonWidget& operator=(const RadioButtonWidget&) = delete; RadioButtonWidget& operator=(RadioButtonWidget&&) = delete; }; class RadioButtonGroup { public: RadioButtonGroup() = default; // add widget to group void addWidget(RadioButtonWidget* widget); // tell the group which widget was selected void select(RadioButtonWidget* widget); void setSelected(uInt32 selected); uInt32 getSelected() { return mySelected; } private: WidgetArray myWidgets; uInt32 mySelected; private: // Following constructors and assignment operators not supported RadioButtonGroup(const RadioButtonGroup&) = delete; RadioButtonGroup(RadioButtonGroup&&) = delete; RadioButtonGroup& operator=(const RadioButtonGroup&) = delete; RadioButtonGroup& operator=(RadioButtonGroup&&) = delete; }; #endif stella-5.1.1/src/gui/Rect.hxx000066400000000000000000000123631324334165500160160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef RECT_HXX #define RECT_HXX #include #include "bspf.hxx" namespace GUI { /* This small class is an helper for position and size values. */ struct Point { uInt32 x; //!< The horizontal part of the point uInt32 y; //!< The vertical part of the point Point() : x(0), y(0) { } Point(const Point& p) : x(p.x), y(p.y) { } explicit Point(uInt32 x1, uInt32 y1) : x(x1), y(y1) { } Point(const string& p) { char c = '\0'; x = y = 0; istringstream buf(p); buf >> x >> c >> y; if(c != 'x') x = y = 0; } Point& operator=(const Point & p) { x = p.x; y = p.y; return *this; } bool operator==(const Point & p) const { return x == p.x && y == p.y; } bool operator!=(const Point & p) const { return x != p.x || y != p.y; } friend ostream& operator<<(ostream& os, const Point& p) { os << p.x << "x" << p.y; return os; } }; struct Size { uInt32 w; //!< The width part of the size uInt32 h; //!< The height part of the size Size() : w(0), h(0) { } Size(const Size& s) : w(s.w), h(s.h) { } explicit Size(uInt32 w1, uInt32 h1) : w(w1), h(h1) { } Size(const string& s) { char c = '\0'; w = h = 0; istringstream buf(s); buf >> w >> c >> h; if(c != 'x') w = h = 0; } bool valid() const { return w > 0 && h > 0; } Size& operator=(const Size& s) { w = s.w; h = s.h; return *this; } bool operator==(const Size& s) const { return w == s.w && h == s.h; } bool operator!=(const Size& s) const { return w != s.w || h != s.h; } bool operator<(const Size& s) const { return w < s.w && h < s.h; } bool operator<=(const Size& s) const { return w <= s.w && h <= s.h; } bool operator>(const Size& s) const { return w > s.w && h > s.h; } bool operator>=(const Size& s) const { return w >= s.w && h >= s.h; } friend ostream& operator<<(ostream& os, const Size& s) { os << s.w << "x" << s.h; return os; } }; /* This small class is an helper for rectangles. Note: This implementation is built around the assumption that (top,left) is part of the rectangle, but (bottom,right) is not! This is reflected in various methods, including contains(), intersects() and others. Another very wide spread approach to rectangle classes treats (bottom,right) also as a part of the rectangle. Coneptually, both are sound, but the approach we use saves many intermediate computations (like computing the height in our case is done by doing this: height = bottom - top; while in the alternate system, it would be height = bottom - top + 1; When writing code using our Rect class, always keep this principle in mind! */ struct Rect { uInt32 top, left; //!< The point at the top left of the rectangle (part of the rect). uInt32 bottom, right; //!< The point at the bottom right of the rectangle (not part of the rect). Rect() : top(0), left(0), bottom(0), right(0) { } Rect(const Rect& s) : top(s.top), left(s.left), bottom(s.bottom), right(s.right) { } Rect& operator=(const Rect&) = default; Rect(uInt32 w, uInt32 h) : top(0), left(0), bottom(h), right(w) { } Rect(const Point& p, uInt32 w, uInt32 h) : top(p.y), left(p.x), bottom(h), right(w) { } Rect(uInt32 x1, uInt32 y1, uInt32 x2, uInt32 y2) : top(y1), left(x1), bottom(y2), right(x2) { assert(valid()); } uInt32 x() const { return left; } uInt32 y() const { return top; } Point point() const { return Point(x(), y()); } uInt32 width() const { return right - left; } uInt32 height() const { return bottom - top; } Size size() const { return Size(width(), height()); } void setWidth(uInt32 aWidth) { right = left + aWidth; } void setHeight(uInt32 aHeight) { bottom = top + aHeight; } void setSize(const Size& size) { setWidth(size.w); setHeight(size.h); } void setBounds(uInt32 x1, uInt32 y1, uInt32 x2, uInt32 y2) { top = y1; left = x1; bottom = y2; right = x2; assert(valid()); } bool valid() const { return (left <= right && top <= bottom); } bool empty() const { return top == 0 && left == 0 && bottom == 0 && right == 0; } void moveTo(uInt32 x, uInt32 y) { bottom += y - top; right += x - left; top = y; left = x; } void moveTo(const Point& p) { moveTo(p.x, p.y); } friend ostream& operator<<(ostream& os, const Rect& r) { os << r.point() << "," << r.size(); return os; } }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - static const Rect EmptyRect; } // End of namespace GUI #endif stella-5.1.1/src/gui/RomAuditDialog.cxx000066400000000000000000000167261324334165500177670ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Launcher.hxx" #include "LauncherFilterDialog.hxx" #include "BrowserDialog.hxx" #include "DialogContainer.hxx" #include "EditTextWidget.hxx" #include "ProgressDialog.hxx" #include "FSNode.hxx" #include "Font.hxx" #include "MessageBox.hxx" #include "FrameBuffer.hxx" #include "MD5.hxx" #include "Props.hxx" #include "PropsSet.hxx" #include "Settings.hxx" #include "RomAuditDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomAuditDialog::RomAuditDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent), myConfirmMsg(nullptr), myMaxWidth(max_w), myMaxHeight(max_h) { const int vBorder = 10; const int hBorder = 10; const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Audit path" + ELLIPSIS) + 20, buttonHeight = font.getLineHeight() + 4, lwidth = font.getStringWidth("ROMs without properties (skipped) "); int xpos, ypos = vBorder; WidgetArray wid; // Set real dimensions _w = 54 * fontWidth + 10; _h = 7 * (lineHeight + 4) + 10; // Audit path ButtonWidget* romButton = new ButtonWidget(this, font, hBorder, ypos, buttonWidth, buttonHeight, "Audit path" + ELLIPSIS, kChooseAuditDirCmd); wid.push_back(romButton); xpos = hBorder + buttonWidth + 10; myRomPath = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - hBorder, lineHeight, ""); wid.push_back(myRomPath); // Show results of ROM audit ypos += buttonHeight + 16; new StaticTextWidget(this, font, hBorder, ypos, lwidth, fontHeight, "ROMs with properties (renamed) ", TextAlign::Left); myResults1 = new EditTextWidget(this, font, hBorder + lwidth, ypos - 2, _w - hBorder*2 - lwidth, lineHeight, ""); myResults1->setEditable(false, true); ypos += buttonHeight; new StaticTextWidget(this, font, hBorder, ypos, lwidth, fontHeight, "ROMs without properties (skipped) ", TextAlign::Left); myResults2 = new EditTextWidget(this, font, hBorder + lwidth, ypos - 2, _w - hBorder*2 - lwidth, lineHeight, ""); myResults2->setEditable(false, true); ypos += buttonHeight + 8; new StaticTextWidget(this, font, hBorder, ypos, _w - 20, fontHeight, "(*) WARNING: operation cannot be undone!", TextAlign::Left); // Add OK and Cancel buttons addOKCancelBGroup(wid, font, "Audit", "Done"); addBGroupToFocusList(wid); // Create file browser dialog myBrowser = make_unique(this, font, myMaxWidth, myMaxHeight); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomAuditDialog::~RomAuditDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomAuditDialog::loadConfig() { const string& currentdir = instance().launcher().currentNode().getShortPath(); const string& path = currentdir == "" ? instance().settings().getString("romdir") : currentdir; myRomPath->setText(path); myResults1->setText(""); myResults2->setText(""); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomAuditDialog::auditRoms() { const string& auditPath = myRomPath->getText(); myResults1->setText(""); myResults2->setText(""); FilesystemNode node(auditPath); FSList files; files.reserve(2048); node.getChildren(files, FilesystemNode::kListFilesOnly); // Create a progress dialog box to show the progress of processing // the ROMs, since this is usually a time-consuming operation ProgressDialog progress(this, instance().frameBuffer().font(), "Auditing ROM files ..."); progress.setRange(0, int(files.size()) - 1, 5); // Create a entry for the GameList for each file Properties props; int renamed = 0, notfound = 0; for(uInt32 idx = 0; idx < files.size(); idx++) { bool renameSucceeded = false; string extension; if(files[idx].isFile() && LauncherFilterDialog::isValidRomName(files[idx], extension)) { // Calculate the MD5 so we can get the rest of the info // from the PropertiesSet (stella.pro) const string& md5 = MD5::hash(files[idx]); if(instance().propSet().getMD5(md5, props)) { const string& name = props.get(Cartridge_Name); // Only rename the file if we found a valid properties entry if(name != "" && name != files[idx].getName()) { const string& newfile = node.getPath() + name + "." + extension; if(files[idx].getPath() != newfile && files[idx].rename(newfile)) renameSucceeded = true; } } if(renameSucceeded) ++renamed; else ++notfound; } // Update the progress bar, indicating one more ROM has been processed progress.setProgress(idx); } progress.close(); myResults1->setText(Variant(renamed).toString()); myResults2->setText(Variant(notfound).toString()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomAuditDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case GuiObject::kOKCmd: if(!myConfirmMsg) { StringList msg; msg.push_back("This operation cannot be undone. Your ROMs"); msg.push_back("will be modified, and as such there is a chance"); msg.push_back("that files may be lost. You are recommended"); msg.push_back("to back up your files before proceeding."); msg.push_back(""); msg.push_back("If you're sure you want to proceed with the"); msg.push_back("audit, click 'OK', otherwise click 'Cancel'."); myConfirmMsg = make_unique (this, instance().frameBuffer().font(), msg, myMaxWidth, myMaxHeight, kConfirmAuditCmd, "OK", "Cancel", false); } myConfirmMsg->show(); break; case kConfirmAuditCmd: auditRoms(); instance().launcher().reload(); break; case kChooseAuditDirCmd: myBrowser->show("Select ROM directory to audit", myRomPath->getText(), BrowserDialog::Directories, kAuditDirChosenCmd); break; case kAuditDirChosenCmd: { FilesystemNode dir(myBrowser->getResult()); myRomPath->setText(dir.getShortPath()); myResults1->setText(""); myResults2->setText(""); break; } default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/gui/RomAuditDialog.hxx000066400000000000000000000046071324334165500177670ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ROM_AUDIT_DIALOG_HXX #define ROM_AUDIT_DIALOG_HXX class OSystem; class GuiObject; class DialogContainer; class EditTextWidget; class StaticTextWidget; class BrowserDialog; namespace GUI { class MessageBox; } #include "Dialog.hxx" #include "Command.hxx" #include "FSNode.hxx" class RomAuditDialog : public Dialog { public: RomAuditDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h); virtual ~RomAuditDialog(); private: void loadConfig() override; void auditRoms(); void openBrowser(const string& title, const string& startpath, FilesystemNode::ListMode mode, int cmd); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: enum { kChooseAuditDirCmd = 'RAsl', // audit dir select kAuditDirChosenCmd = 'RAch', // audit dir changed kConfirmAuditCmd = 'RAcf' // confirm rom audit }; // Select a new ROM audit path unique_ptr myBrowser; // ROM audit path EditTextWidget* myRomPath; // Show the results of the ROM audit EditTextWidget* myResults1; EditTextWidget* myResults2; // Show a message about the dangers of using this function unique_ptr myConfirmMsg; // Maximum width and height for this dialog int myMaxWidth, myMaxHeight; private: // Following constructors and assignment operators not supported RomAuditDialog() = delete; RomAuditDialog(const RomAuditDialog&) = delete; RomAuditDialog(RomAuditDialog&&) = delete; RomAuditDialog& operator=(const RomAuditDialog&) = delete; RomAuditDialog& operator=(RomAuditDialog&&) = delete; }; #endif stella-5.1.1/src/gui/RomInfoWidget.cxx000066400000000000000000000140411324334165500176240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "EventHandler.hxx" #include "FrameBuffer.hxx" #include "Dialog.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "OSystem.hxx" #include "Settings.hxx" #include "Props.hxx" #include "PNGLibrary.hxx" #include "Rect.hxx" #include "Widget.hxx" #include "TIAConstants.hxx" #include "RomInfoWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RomInfoWidget::RomInfoWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : Widget(boss, font, x, y, w, h), mySurfaceIsValid(false), myHaveProperties(false), myAvail(w > 400 ? GUI::Size(640, TIAConstants::maxViewableHeight*2) : GUI::Size(320, TIAConstants::maxViewableHeight)) { _flags = WIDGET_ENABLED; _bgcolor = _bgcolorhi = kWidColor; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::loadConfig() { // The ROM may have changed since we were last in the browser, either // by saving a different image or through a change in video renderer, // so we reload the properties if(myHaveProperties) parseProperties(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::setProperties(const Properties& props) { myHaveProperties = true; myProperties = props; // Decide whether the information should be shown immediately if(instance().eventHandler().state() == EventHandlerState::LAUNCHER) parseProperties(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::clearProperties() { myHaveProperties = mySurfaceIsValid = false; if(mySurface) mySurface->setVisible(mySurfaceIsValid); // Decide whether the information should be shown immediately if(instance().eventHandler().state() == EventHandlerState::LAUNCHER) setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::parseProperties() { // Check if a surface has ever been created; if so, we use it // The surface will always be the maximum size, but sometimes we'll // only draw certain parts of it if(mySurface == nullptr) { mySurface = instance().frameBuffer().allocateSurface(320*2, TIAConstants::maxViewableHeight*2); mySurface->attributes().smoothing = true; mySurface->applyAttributes(); dialog().addSurface(mySurface); } // Initialize to empty properties entry mySurfaceErrorMsg = ""; mySurfaceIsValid = true; myRomInfo.clear(); // Get a valid filename representing a snapshot file for this rom const string& filename = instance().snapshotLoadDir() + myProperties.get(Cartridge_Name) + ".png"; // Read the PNG file try { instance().png().loadImage(filename, *mySurface); // Scale surface to available image area const GUI::Rect& src = mySurface->srcRect(); float scale = std::min(float(myAvail.w) / src.width(), float(myAvail.h) / src.height()); mySurface->setDstSize(uInt32(src.width() * scale), uInt32(src.height() * scale)); } catch(const runtime_error& e) { mySurfaceIsValid = false; mySurfaceErrorMsg = e.what(); } if(mySurface) mySurface->setVisible(mySurfaceIsValid); // Now add some info for the message box below the image myRomInfo.push_back("Name: " + myProperties.get(Cartridge_Name)); myRomInfo.push_back("Manufacturer: " + myProperties.get(Cartridge_Manufacturer)); myRomInfo.push_back("Model: " + myProperties.get(Cartridge_ModelNo)); myRomInfo.push_back("Rarity: " + myProperties.get(Cartridge_Rarity)); myRomInfo.push_back("Note: " + myProperties.get(Cartridge_Note)); bool swappedPorts = myProperties.get(Console_SwapPorts) == "YES"; myRomInfo.push_back("Controllers: " + (!swappedPorts ? myProperties.get(Controller_Left) + " (left), " + myProperties.get(Controller_Right) + " (right)" : myProperties.get(Controller_Right) + " (left), " + myProperties.get(Controller_Left) + " (right)")); #if 0 myRomInfo.push_back("YStart/Height: " + myProperties.get(Display_YStart) + " " + myProperties.get(Display_Height)); #endif setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void RomInfoWidget::drawWidget(bool hilite) { FBSurface& s = dialog().surface(); const int yoff = myAvail.h + 10; s.fillRect(_x+2, _y+2, _w-4, _h-4, kWidColor); s.box(_x, _y, _w, _h, kColor, kShadowColor); s.box(_x, _y+yoff, _w, _h-yoff, kColor, kShadowColor); if(!myHaveProperties) return; if(mySurfaceIsValid) { const GUI::Rect& dst = mySurface->dstRect(); uInt32 x = _x + ((_w - dst.width()) >> 1); uInt32 y = _y + ((yoff - dst.height()) >> 1); // Make sure when positioning the snapshot surface that we take // the dialog surface position into account const GUI::Rect& s_dst = s.dstRect(); mySurface->setDstPos(x + s_dst.x(), y + s_dst.y()); } else if(mySurfaceErrorMsg != "") { const GUI::Font& font = instance().frameBuffer().font(); uInt32 x = _x + ((_w - font.getStringWidth(mySurfaceErrorMsg)) >> 1); uInt32 y = _y + ((yoff - font.getLineHeight()) >> 1); s.drawString(font, mySurfaceErrorMsg, x, y, _w - 10, _textcolor); } int xpos = _x + 5, ypos = _y + yoff + 10; for(const auto& info: myRomInfo) { s.drawString(_font, info, xpos, ypos, _w - 10, _textcolor); ypos += _font.getLineHeight(); } } stella-5.1.1/src/gui/RomInfoWidget.hxx000066400000000000000000000043031324334165500176310ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef ROM_INFO_WIDGET_HXX #define ROM_INFO_WIDGET_HXX class FBSurface; class Properties; namespace GUI { struct Size; } #include "Widget.hxx" #include "bspf.hxx" class RomInfoWidget : public Widget { public: RomInfoWidget(GuiObject *boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~RomInfoWidget() = default; void setProperties(const Properties& props); void clearProperties(); void loadConfig() override; protected: void drawWidget(bool hilite) override; private: void parseProperties(); private: // Surface pointer holding the PNG image shared_ptr mySurface; // Whether the surface should be redrawn by drawWidget() bool mySurfaceIsValid; // Some ROM properties info, as well as 'tEXt' chunks from the PNG image StringList myRomInfo; // The properties for the currently selected ROM Properties myProperties; // Indicates if the current properties should actually be used bool myHaveProperties; // Indicates if an error occurred in creating/displaying the surface string mySurfaceErrorMsg; // How much space available for the PNG image GUI::Size myAvail; private: // Following constructors and assignment operators not supported RomInfoWidget() = delete; RomInfoWidget(const RomInfoWidget&) = delete; RomInfoWidget(RomInfoWidget&&) = delete; RomInfoWidget& operator=(const RomInfoWidget&) = delete; RomInfoWidget& operator=(RomInfoWidget&&) = delete; }; #endif stella-5.1.1/src/gui/ScrollBarWidget.cxx000066400000000000000000000174661324334165500201540ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "OSystem.hxx" #include "Dialog.hxx" #include "FBSurface.hxx" #include "ScrollBarWidget.hxx" #include "bspf.hxx" /* * TODO: * - Allow for a horizontal scrollbar, too? * - If there are less items than fit on one pages, no scrolling can be done * and we thus should not highlight the arrows/slider. */ #define UP_DOWN_BOX_HEIGHT 18 // Up arrow static uInt32 up_arrow[8] = { 0b00011000, 0b00011000, 0b00111100, 0b00111100, 0b01111110, 0b01111110, 0b11111111, 0b11111111 }; // Down arrow static uInt32 down_arrow[8] = { 0b11111111, 0b11111111, 0b01111110, 0b01111110, 0b00111100, 0b00111100, 0b00011000, 0b00011000 }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ScrollBarWidget::ScrollBarWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : Widget(boss, font, x, y, w, h), CommandSender(boss), _numEntries(0), _entriesPerPage(0), _currentPos(0), _wheel_lines(0), _part(kNoPart), _draggingPart(kNoPart), _sliderHeight(0), _sliderPos(0), _sliderDeltaMouseDownPos(0) { _flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG; _bgcolor = kWidColor; _bgcolorhi = kWidColor; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { // Ignore subsequent mouse clicks when the slider is being moved if(_draggingPart == kSliderPart) return; int old_pos = _currentPos; // Do nothing if there are less items than fit on one page if(_numEntries <= _entriesPerPage) return; if (y <= UP_DOWN_BOX_HEIGHT) { // Up arrow _currentPos--; _draggingPart = kUpArrowPart; } else if(y >= _h - UP_DOWN_BOX_HEIGHT) { // Down arrow _currentPos++; _draggingPart = kDownArrowPart; } else if(y < _sliderPos) { _currentPos -= _entriesPerPage; } else if(y >= _sliderPos + _sliderHeight) { _currentPos += _entriesPerPage; } else { _draggingPart = kSliderPart; _sliderDeltaMouseDownPos = y - _sliderPos; } // Make sure that _currentPos is still inside the bounds checkBounds(old_pos); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { _draggingPart = kNoPart; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::handleMouseWheel(int x, int y, int direction) { int old_pos = _currentPos; if(_numEntries < _entriesPerPage) return; if(direction < 0) _currentPos -= _wheel_lines ? _wheel_lines : _WHEEL_LINES; else _currentPos += _wheel_lines ? _wheel_lines : _WHEEL_LINES; // Make sure that _currentPos is still inside the bounds checkBounds(old_pos); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::handleMouseMoved(int x, int y) { // Do nothing if there are less items than fit on one page if(_numEntries <= _entriesPerPage) return; if(_draggingPart == kSliderPart) { int old_pos = _currentPos; _sliderPos = y - _sliderDeltaMouseDownPos; if(_sliderPos < UP_DOWN_BOX_HEIGHT) _sliderPos = UP_DOWN_BOX_HEIGHT; if(_sliderPos > _h - UP_DOWN_BOX_HEIGHT - _sliderHeight) _sliderPos = _h - UP_DOWN_BOX_HEIGHT - _sliderHeight; _currentPos = (_sliderPos - UP_DOWN_BOX_HEIGHT) * (_numEntries - _entriesPerPage) / (_h - 2 * UP_DOWN_BOX_HEIGHT - _sliderHeight); checkBounds(old_pos); } else { int old_part = _part; if(y <= UP_DOWN_BOX_HEIGHT) // Up arrow _part = kUpArrowPart; else if(y >= _h - UP_DOWN_BOX_HEIGHT) // Down arrow _part = kDownArrowPart; else if(y < _sliderPos) _part = kPageUpPart; else if(y >= _sliderPos + _sliderHeight) _part = kPageDownPart; else _part = kSliderPart; if (old_part != _part) setDirty(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ScrollBarWidget::handleMouseClicks(int x, int y, MouseButton b) { // Let continuous mouse clicks come through, as the scroll buttons need them return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::checkBounds(int old_pos) { if(_numEntries <= _entriesPerPage || _currentPos < 0) _currentPos = 0; else if(_currentPos > _numEntries - _entriesPerPage) _currentPos = _numEntries - _entriesPerPage; if (old_pos != _currentPos) { recalc(); sendCommand(GuiObject::kSetPositionCmd, _currentPos, _id); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::handleMouseEntered() { setFlags(WIDGET_HILITED); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::handleMouseLeft() { _part = kNoPart; clearFlags(WIDGET_HILITED); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::recalc() { //cerr << "ScrollBarWidget::recalc()\n"; if(_numEntries > _entriesPerPage) { _sliderHeight = (_h - 2 * UP_DOWN_BOX_HEIGHT) * _entriesPerPage / _numEntries; if(_sliderHeight < UP_DOWN_BOX_HEIGHT) _sliderHeight = UP_DOWN_BOX_HEIGHT; _sliderPos = UP_DOWN_BOX_HEIGHT + (_h - 2 * UP_DOWN_BOX_HEIGHT - _sliderHeight) * _currentPos / (_numEntries - _entriesPerPage); if(_sliderPos < 0) _sliderPos = 0; } else { _sliderHeight = _h - 2 * UP_DOWN_BOX_HEIGHT; _sliderPos = UP_DOWN_BOX_HEIGHT; } setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ScrollBarWidget::drawWidget(bool hilite) { //cerr << "ScrollBarWidget::drawWidget\n"; FBSurface& s = _boss->dialog().surface(); int bottomY = _y + _h; bool isSinglePage = (_numEntries <= _entriesPerPage); s.frameRect(_x, _y, _w, _h, kShadowColor); if(_draggingPart != kNoPart) _part = _draggingPart; // Up arrow s.frameRect(_x, _y, _w, UP_DOWN_BOX_HEIGHT, kColor); s.drawBitmap(up_arrow, _x+3, _y+5, isSinglePage ? kColor : (hilite && _part == kUpArrowPart) ? kScrollColorHi : kScrollColor, 8); // Down arrow s.frameRect(_x, bottomY - UP_DOWN_BOX_HEIGHT, _w, UP_DOWN_BOX_HEIGHT, kColor); s.drawBitmap(down_arrow, _x+3, bottomY - UP_DOWN_BOX_HEIGHT + 5, isSinglePage ? kColor : (hilite && _part == kDownArrowPart) ? kScrollColorHi : kScrollColor, 8); // Slider if(!isSinglePage) { s.fillRect(_x, _y + _sliderPos, _w, _sliderHeight, (hilite && _part == kSliderPart) ? kScrollColorHi : kScrollColor); s.frameRect(_x, _y + _sliderPos, _w, _sliderHeight, kColor); int y = _y + _sliderPos + _sliderHeight / 2; s.hLine(_x + 2, y - 2, _x + _w - 3, kWidColor); s.hLine(_x + 2, y, _x + _w - 3, kWidColor); s.hLine(_x + 2, y + 2, _x + _w - 3, kWidColor); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int ScrollBarWidget::_WHEEL_LINES = 4; stella-5.1.1/src/gui/ScrollBarWidget.hxx000066400000000000000000000047171324334165500201540ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SCROLL_BAR_WIDGET_HXX #define SCROLL_BAR_WIDGET_HXX class GuiObject; #include "Widget.hxx" #include "Command.hxx" #include "bspf.hxx" enum { kScrollBarWidth = 14 }; class ScrollBarWidget : public Widget, public CommandSender { public: ScrollBarWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~ScrollBarWidget() = default; void recalc(); void handleMouseWheel(int x, int y, int direction) override; static void setWheelLines(int lines) { _WHEEL_LINES = lines; } static int getWheelLines() { return _WHEEL_LINES; } private: void drawWidget(bool hilite) override; void checkBounds(int old_pos); void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseMoved(int x, int y) override; bool handleMouseClicks(int x, int y, MouseButton b) override; void handleMouseEntered() override; void handleMouseLeft() override; public: int _numEntries; int _entriesPerPage; int _currentPos; int _wheel_lines; private: enum Part { kNoPart, kUpArrowPart, kDownArrowPart, kSliderPart, kPageUpPart, kPageDownPart }; Part _part; Part _draggingPart; int _sliderHeight; int _sliderPos; int _sliderDeltaMouseDownPos; static int _WHEEL_LINES; private: // Following constructors and assignment operators not supported ScrollBarWidget() = delete; ScrollBarWidget(const ScrollBarWidget&) = delete; ScrollBarWidget(ScrollBarWidget&&) = delete; ScrollBarWidget& operator=(const ScrollBarWidget&) = delete; ScrollBarWidget& operator=(ScrollBarWidget&&) = delete; }; #endif stella-5.1.1/src/gui/SnapshotDialog.cxx000066400000000000000000000200171324334165500200260ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "BrowserDialog.hxx" #include "EditTextWidget.hxx" #include "FSNode.hxx" #include "Font.hxx" #include "LauncherDialog.hxx" #include "PopUpWidget.hxx" #include "Settings.hxx" #include "SnapshotDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SnapshotDialog::SnapshotDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font) : Dialog(osystem, parent), myFont(font) { const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), buttonWidth = font.getStringWidth("Save path" + ELLIPSIS) + 20, buttonHeight = font.getLineHeight() + 4; const int vBorder = 10; int xpos, ypos, lwidth, fwidth; WidgetArray wid; ButtonWidget* b; // Set real dimensions _w = 53 * fontWidth + 8; _h = 10 * (lineHeight + 4) + 10; xpos = vBorder; ypos = vBorder; // Snapshot path (save files) b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Save path" + ELLIPSIS, kChooseSnapSaveDirCmd); wid.push_back(b); xpos += buttonWidth + 10; mySnapSavePath = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(mySnapSavePath); // Snapshot path (load files) xpos = vBorder; ypos += buttonHeight + 3; b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, "Load path" + ELLIPSIS, kChooseSnapLoadDirCmd); wid.push_back(b); xpos += buttonWidth + 10; mySnapLoadPath = new EditTextWidget(this, font, xpos, ypos + 2, _w - xpos - 10, lineHeight, ""); wid.push_back(mySnapLoadPath); // Snapshot naming lwidth = font.getStringWidth("Continuous snapshot interval "); fwidth = font.getStringWidth("internal database"); VariantList items; VarList::push_back(items, "actual ROM name", "rom"); VarList::push_back(items, "internal database", "int"); xpos = vBorder+10; ypos += buttonHeight + 8; mySnapName = new PopUpWidget(this, font, xpos, ypos, fwidth, lineHeight, items, "Save snapshots according to ", lwidth); wid.push_back(mySnapName); // Snapshot interval (continuous mode) items.clear(); VarList::push_back(items, "1 second", "1"); VarList::push_back(items, "2 seconds", "2"); VarList::push_back(items, "3 seconds", "3"); VarList::push_back(items, "4 seconds", "4"); VarList::push_back(items, "5 seconds", "5"); VarList::push_back(items, "6 seconds", "6"); VarList::push_back(items, "7 seconds", "7"); VarList::push_back(items, "8 seconds", "8"); VarList::push_back(items, "9 seconds", "9"); VarList::push_back(items, "10 seconds", "10"); ypos += buttonHeight; mySnapInterval = new PopUpWidget(this, font, xpos, ypos, fwidth, lineHeight, items, "Continuous snapshot interval ", lwidth); wid.push_back(mySnapInterval); // Booleans for saving snapshots fwidth = font.getStringWidth("When saving snapshots:"); xpos = vBorder; ypos += buttonHeight + 5; new StaticTextWidget(this, font, xpos, ypos, fwidth, lineHeight, "When saving snapshots:", TextAlign::Left); // Snapshot single or multiple saves xpos += 30; ypos += lineHeight + 3; mySnapSingle = new CheckboxWidget(this, font, xpos, ypos, "Overwrite existing files"); wid.push_back(mySnapSingle); // Snapshot in 1x mode (ignore scaling) ypos += mySnapSingle->getHeight() + 4; mySnap1x = new CheckboxWidget(this, font, xpos, ypos, "Ignore scaling (1x mode)"); wid.push_back(mySnap1x); // Add Defaults, OK and Cancel buttons b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, font.getStringWidth("Defaults") + 20, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SnapshotDialog::~SnapshotDialog() { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SnapshotDialog::loadConfig() { const Settings& settings = instance().settings(); mySnapSavePath->setText(settings.getString("snapsavedir")); mySnapLoadPath->setText(settings.getString("snaploaddir")); mySnapName->setSelected(instance().settings().getString("snapname"), "int"); mySnapInterval->setSelected(instance().settings().getString("ssinterval"), "2"); mySnapSingle->setState(settings.getBool("sssingle")); mySnap1x->setState(settings.getBool("ss1x")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SnapshotDialog::saveConfig() { instance().settings().setValue("snapsavedir", mySnapSavePath->getText()); instance().settings().setValue("snaploaddir", mySnapLoadPath->getText()); instance().settings().setValue("snapname", mySnapName->getSelectedTag().toString()); instance().settings().setValue("sssingle", mySnapSingle->getState()); instance().settings().setValue("ss1x", mySnap1x->getState()); instance().settings().setValue("ssinterval", mySnapInterval->getSelectedTag().toString()); // Flush changes to disk and inform the OSystem instance().saveConfig(); instance().setConfigPaths(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SnapshotDialog::setDefaults() { mySnapSavePath->setText(instance().defaultSaveDir()); mySnapLoadPath->setText(instance().defaultLoadDir()); mySnapSingle->setState(false); mySnap1x->setState(false); mySnapInterval->setSelected("2", "2"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SnapshotDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch (cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; case kChooseSnapSaveDirCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary createBrowser(); myBrowser->show("Select snapshot save directory", mySnapSavePath->getText(), BrowserDialog::Directories, kSnapSaveDirChosenCmd); break; case kChooseSnapLoadDirCmd: // This dialog is resizable under certain conditions, so we need // to re-create it as necessary createBrowser(); myBrowser->show("Select snapshot load directory", mySnapLoadPath->getText(), BrowserDialog::Directories, kSnapLoadDirChosenCmd); break; case kSnapSaveDirChosenCmd: mySnapSavePath->setText(myBrowser->getResult().getShortPath()); break; case kSnapLoadDirChosenCmd: mySnapLoadPath->setText(myBrowser->getResult().getShortPath()); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SnapshotDialog::createBrowser() { uInt32 w = 0, h = 0; getResizableBounds(w, h); // Create file browser dialog if(!myBrowser || uInt32(myBrowser->getWidth()) != w || uInt32(myBrowser->getHeight()) != h) myBrowser = make_unique(this, myFont, w, h); } stella-5.1.1/src/gui/SnapshotDialog.hxx000066400000000000000000000044201324334165500200330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SNAPSHOT_DIALOG_HXX #define SNAPSHOT_DIALOG_HXX class OSystem; class GuiObject; class DialogContainer; class CheckboxWidget; class PopUpWidget; class EditTextWidget; class SliderWidget; class StaticTextWidget; class BrowserDialog; #include "Dialog.hxx" #include "Command.hxx" class SnapshotDialog : public Dialog { public: SnapshotDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); virtual ~SnapshotDialog(); private: void loadConfig() override; void saveConfig() override; void setDefaults() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; void createBrowser(); private: enum { kChooseSnapSaveDirCmd = 'LOss', // snapshot dir (save files) kChooseSnapLoadDirCmd = 'LOsl', // snapshot dir (load files) kSnapSaveDirChosenCmd = 'snsc', // snap chosen (save files) kSnapLoadDirChosenCmd = 'snlc' // snap chosen (load files) }; const GUI::Font& myFont; // Config paths EditTextWidget* mySnapSavePath; EditTextWidget* mySnapLoadPath; PopUpWidget* mySnapName; PopUpWidget* mySnapInterval; CheckboxWidget* mySnapSingle; CheckboxWidget* mySnap1x; unique_ptr myBrowser; private: // Following constructors and assignment operators not supported SnapshotDialog() = delete; SnapshotDialog(const SnapshotDialog&) = delete; SnapshotDialog(SnapshotDialog&&) = delete; SnapshotDialog& operator=(const SnapshotDialog&) = delete; SnapshotDialog& operator=(SnapshotDialog&&) = delete; }; #endif stella-5.1.1/src/gui/StellaFont.hxx000066400000000000000000000705161324334165500172000ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Generated by src/tools/convbdf on Wed Jul 31 13:02:19 2013. //============================================================================ #ifndef STELLA_FONT_DATA_HXX #define STELLA_FONT_DATA_HXX #include "Font.hxx" /* Font information: name: 6x10-ISO8859-1 facename: -Misc-Fixed-Medium-R-Normal--10-100-75-75-C-60-ISO8859-1 w x h: 6x10 bbx: 6 10 0 -2 size: 95 ascent: 8 descent: 2 first char: 32 (0x20) last char: 126 (0x7e) default char: 32 (0x20) proportional: no Public domain terminal emulator font. Share and enjoy. */ namespace GUI { // Font character bitmap data. static const uInt16 stella_font_bits[] = { /* Character 32 (0x20): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | | | | | | | | | | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 33 (0x21): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | * | | * | | * | | | | * | | | | | +------+ */ 0x0000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x2000, 0x0000, 0x0000, /* Character 34 (0x22): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * * | | * * | | * * | | | | | | | | | | | | | +------+ */ 0x0000, 0x5000, 0x5000, 0x5000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 35 (0x23): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * * | | * * | |***** | | * * | |***** | | * * | | * * | | | | | +------+ */ 0x0000, 0x5000, 0x5000, 0xf800, 0x5000, 0xf800, 0x5000, 0x5000, 0x0000, 0x0000, /* Character 36 (0x24): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | *** | |* * | | *** | | * * | | *** | | * | | | | | +------+ */ 0x0000, 0x2000, 0x7000, 0xa000, 0x7000, 0x2800, 0x7000, 0x2000, 0x0000, 0x0000, /* Character 37 (0x25): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * * | |* * * | | * * | | * | | * * | |* * * | |* * | | | | | +------+ */ 0x0000, 0x4800, 0xa800, 0x5000, 0x2000, 0x5000, 0xa800, 0x9000, 0x0000, 0x0000, /* Character 38 (0x26): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | |* * | |* * | | * | |* * * | |* * | | ** * | | | | | +------+ */ 0x0000, 0x4000, 0xa000, 0xa000, 0x4000, 0xa800, 0x9000, 0x6800, 0x0000, 0x0000, /* Character 39 (0x27): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | * | | | | | | | | | | | | | +------+ */ 0x0000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 40 (0x28): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0x1000, 0x2000, 0x4000, 0x4000, 0x4000, 0x2000, 0x1000, 0x0000, 0x0000, /* Character 41 (0x29): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0x4000, 0x2000, 0x1000, 0x1000, 0x1000, 0x2000, 0x4000, 0x0000, 0x0000, /* Character 42 (0x2a): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | |* * | | * * | |***** | | * * | |* * | | | | | | | +------+ */ 0x0000, 0x0000, 0x8800, 0x5000, 0xf800, 0x5000, 0x8800, 0x0000, 0x0000, 0x0000, /* Character 43 (0x2b): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | * | | * | |***** | | * | | * | | | | | | | +------+ */ 0x0000, 0x0000, 0x2000, 0x2000, 0xf800, 0x2000, 0x2000, 0x0000, 0x0000, 0x0000, /* Character 44 (0x2c): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | | | | | | | ** | | * | | * | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3000, 0x2000, 0x4000, 0x0000, /* Character 45 (0x2d): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | | |***** | | | | | | | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xf800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 46 (0x2e): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | | | | | | | * | | *** | | * | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2000, 0x7000, 0x2000, 0x0000, /* Character 47 (0x2f): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | * | | * | | * | |* | |* | | | | | +------+ */ 0x0000, 0x0800, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x8000, 0x0000, 0x0000, /* Character 48 (0x30): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * * | |* * | |* * | |* * | | * * | | * | | | | | +------+ */ 0x0000, 0x2000, 0x5000, 0x8800, 0x8800, 0x8800, 0x5000, 0x2000, 0x0000, 0x0000, /* Character 49 (0x31): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | ** | |* * | | * | | * | | * | |***** | | | | | +------+ */ 0x0000, 0x2000, 0x6000, 0xa000, 0x2000, 0x2000, 0x2000, 0xf800, 0x0000, 0x0000, /* Character 50 (0x32): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | | * | | ** | | * | |* | |***** | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x0800, 0x3000, 0x4000, 0x8000, 0xf800, 0x0000, 0x0000, /* Character 51 (0x33): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |***** | | * | | * | | ** | | * | |* * | | *** | | | | | +------+ */ 0x0000, 0xf800, 0x0800, 0x1000, 0x3000, 0x0800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 52 (0x34): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | ** | | * * | |* * | |***** | | * | | * | | | | | +------+ */ 0x0000, 0x1000, 0x3000, 0x5000, 0x9000, 0xf800, 0x1000, 0x1000, 0x0000, 0x0000, /* Character 53 (0x35): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |***** | |* | |* ** | |** * | | * | |* * | | *** | | | | | +------+ */ 0x0000, 0xf800, 0x8000, 0xb000, 0xc800, 0x0800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 54 (0x36): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | ** | | * | |* | |* ** | |** * | |* * | | *** | | | | | +------+ */ 0x0000, 0x3000, 0x4000, 0x8000, 0xb000, 0xc800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 55 (0x37): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |***** | | * | | * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0xf800, 0x0800, 0x1000, 0x1000, 0x2000, 0x4000, 0x4000, 0x0000, 0x0000, /* Character 56 (0x38): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | |* * | | *** | |* * | |* * | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x8800, 0x7000, 0x8800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 57 (0x39): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | |* ** | | ** * | | * | | * | | ** | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x9800, 0x6800, 0x0800, 0x1000, 0x6000, 0x0000, 0x0000, /* Character 58 (0x3a): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | * | | *** | | * | | | | * | | *** | | * | | | +------+ */ 0x0000, 0x0000, 0x2000, 0x7000, 0x2000, 0x0000, 0x2000, 0x7000, 0x2000, 0x0000, /* Character 59 (0x3b): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | * | | *** | | * | | | | ** | | * | | * | | | +------+ */ 0x0000, 0x0000, 0x2000, 0x7000, 0x2000, 0x0000, 0x3000, 0x2000, 0x4000, 0x0000, /* Character 60 (0x3c): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0x0800, 0x1000, 0x2000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0000, 0x0000, /* Character 61 (0x3d): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |***** | | | |***** | | | | | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0xf800, 0x0000, 0xf800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 62 (0x3e): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0x4000, 0x2000, 0x1000, 0x0800, 0x1000, 0x2000, 0x4000, 0x0000, 0x0000, /* Character 63 (0x3f): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | | * | | * | | * | | | | * | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x1000, 0x2000, 0x2000, 0x0000, 0x2000, 0x0000, 0x0000, /* Character 64 (0x40): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | |* ** | |* * * | |* ** | |* | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x9800, 0xa800, 0xb000, 0x8000, 0x7000, 0x0000, 0x0000, /* Character 65 (0x41): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * * | |* * | |* * | |***** | |* * | |* * | | | | | +------+ */ 0x0000, 0x2000, 0x5000, 0x8800, 0x8800, 0xf800, 0x8800, 0x8800, 0x0000, 0x0000, /* Character 66 (0x42): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |**** | | * * | | * * | | *** | | * * | | * * | |**** | | | | | +------+ */ 0x0000, 0xf000, 0x4800, 0x4800, 0x7000, 0x4800, 0x4800, 0xf000, 0x0000, 0x0000, /* Character 67 (0x43): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | |* | |* | |* | |* * | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x8000, 0x8000, 0x8000, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 68 (0x44): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |**** | | * * | | * * | | * * | | * * | | * * | |**** | | | | | +------+ */ 0x0000, 0xf000, 0x4800, 0x4800, 0x4800, 0x4800, 0x4800, 0xf000, 0x0000, 0x0000, /* Character 69 (0x45): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |***** | |* | |* | |**** | |* | |* | |***** | | | | | +------+ */ 0x0000, 0xf800, 0x8000, 0x8000, 0xf000, 0x8000, 0x8000, 0xf800, 0x0000, 0x0000, /* Character 70 (0x46): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |***** | |* | |* | |**** | |* | |* | |* | | | | | +------+ */ 0x0000, 0xf800, 0x8000, 0x8000, 0xf000, 0x8000, 0x8000, 0x8000, 0x0000, 0x0000, /* Character 71 (0x47): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | |* | |* | |* ** | |* * | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x8000, 0x8000, 0x9800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 72 (0x48): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | |* * | |***** | |* * | |* * | |* * | | | | | +------+ */ 0x0000, 0x8800, 0x8800, 0x8800, 0xf800, 0x8800, 0x8800, 0x8800, 0x0000, 0x0000, /* Character 73 (0x49): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | | * | | * | | * | | * | | * | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, 0x0000, /* Character 74 (0x4a): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | | * | | * | | * | | * | |* * | | ** | | | | | +------+ */ 0x0000, 0x3800, 0x1000, 0x1000, 0x1000, 0x1000, 0x9000, 0x6000, 0x0000, 0x0000, /* Character 75 (0x4b): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | |* * | |** | |* * | |* * | |* * | | | | | +------+ */ 0x0000, 0x8800, 0x9000, 0xa000, 0xc000, 0xa000, 0x9000, 0x8800, 0x0000, 0x0000, /* Character 76 (0x4c): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* | |* | |* | |* | |* | |* | |***** | | | | | +------+ */ 0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0xf800, 0x0000, 0x0000, /* Character 77 (0x4d): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | |** ** | |* * * | |* * | |* * | |* * | | | | | +------+ */ 0x0000, 0x8800, 0x8800, 0xd800, 0xa800, 0x8800, 0x8800, 0x8800, 0x0000, 0x0000, /* Character 78 (0x4e): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | |** * | |* * * | |* ** | |* * | |* * | | | | | +------+ */ 0x0000, 0x8800, 0x8800, 0xc800, 0xa800, 0x9800, 0x8800, 0x8800, 0x0000, 0x0000, /* Character 79 (0x4f): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | |* * | |* * | |* * | |* * | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 80 (0x50): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |**** | |* * | |* * | |**** | |* | |* | |* | | | | | +------+ */ 0x0000, 0xf000, 0x8800, 0x8800, 0xf000, 0x8000, 0x8000, 0x8000, 0x0000, 0x0000, /* Character 81 (0x51): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | |* * | |* * | |* * | |* * * | | *** | | * | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x8800, 0x8800, 0x8800, 0xa800, 0x7000, 0x0800, 0x0000, /* Character 82 (0x52): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |**** | |* * | |* * | |**** | |* * | |* * | |* * | | | | | +------+ */ 0x0000, 0xf000, 0x8800, 0x8800, 0xf000, 0xa000, 0x9000, 0x8800, 0x0000, 0x0000, /* Character 83 (0x53): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | |* * | |* | | *** | | * | |* * | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x8800, 0x8000, 0x7000, 0x0800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 84 (0x54): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |***** | | * | | * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0xf800, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, /* Character 85 (0x55): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | |* * | |* * | |* * | |* * | | *** | | | | | +------+ */ 0x0000, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 86 (0x56): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | |* * | | * * | | * * | | * * | | * | | | | | +------+ */ 0x0000, 0x8800, 0x8800, 0x8800, 0x5000, 0x5000, 0x5000, 0x2000, 0x0000, 0x0000, /* Character 87 (0x57): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | |* * | |* * * | |* * * | |** ** | |* * | | | | | +------+ */ 0x0000, 0x8800, 0x8800, 0x8800, 0xa800, 0xa800, 0xd800, 0x8800, 0x0000, 0x0000, /* Character 88 (0x58): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | | * * | | * | | * * | |* * | |* * | | | | | +------+ */ 0x0000, 0x8800, 0x8800, 0x5000, 0x2000, 0x5000, 0x8800, 0x8800, 0x0000, 0x0000, /* Character 89 (0x59): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* * | |* * | | * * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0x8800, 0x8800, 0x5000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, /* Character 90 (0x5a): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |***** | | * | | * | | * | | * | |* | |***** | | | | | +------+ */ 0x0000, 0xf800, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0xf800, 0x0000, 0x0000, /* Character 91 (0x5b): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | | * | | * | | * | | * | | * | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x4000, 0x4000, 0x4000, 0x4000, 0x4000, 0x7000, 0x0000, 0x0000, /* Character 92 (0x5c): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* | |* | | * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0x8000, 0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0800, 0x0000, 0x0000, /* Character 93 (0x5d): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | *** | | * | | * | | * | | * | | * | | *** | | | | | +------+ */ 0x0000, 0x7000, 0x1000, 0x1000, 0x1000, 0x1000, 0x1000, 0x7000, 0x0000, 0x0000, /* Character 94 (0x5e): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * * | |* * | | | | | | | | | | | | | +------+ */ 0x0000, 0x2000, 0x5000, 0x8800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 95 (0x5f): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | | | | | | | | | | |***** | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xf800, 0x0000, /* Character 96 (0x60): width 6 bbx ( 6, 10, 0, -2 ) +------+ | * | | * | | | | | | | | | | | | | | | | | +------+ */ 0x2000, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 97 (0x61): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | *** | | * | | **** | |* * | | **** | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x7000, 0x0800, 0x7800, 0x8800, 0x7800, 0x0000, 0x0000, /* Character 98 (0x62): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* | |* | |* ** | |** * | |* * | |** * | |* ** | | | | | +------+ */ 0x0000, 0x8000, 0x8000, 0xb000, 0xc800, 0x8800, 0xc800, 0xb000, 0x0000, 0x0000, /* Character 99 (0x63): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | *** | |* * | |* | |* * | | *** | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x7000, 0x8800, 0x8000, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 100 (0x64): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | ** * | |* ** | |* * | |* ** | | ** * | | | | | +------+ */ 0x0000, 0x0800, 0x0800, 0x6800, 0x9800, 0x8800, 0x9800, 0x6800, 0x0000, 0x0000, /* Character 101 (0x65): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | *** | |* * | |***** | |* | | *** | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x7000, 0x8800, 0xf800, 0x8000, 0x7000, 0x0000, 0x0000, /* Character 102 (0x66): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | ** | | * * | | * | |**** | | * | | * | | * | | | | | +------+ */ 0x0000, 0x3000, 0x4800, 0x4000, 0xf000, 0x4000, 0x4000, 0x4000, 0x0000, 0x0000, /* Character 103 (0x67): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | **** | |* * | |* * | | **** | | * | |* * | | *** | +------+ */ 0x0000, 0x0000, 0x0000, 0x7800, 0x8800, 0x8800, 0x7800, 0x0800, 0x8800, 0x7000, /* Character 104 (0x68): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* | |* | |* ** | |** * | |* * | |* * | |* * | | | | | +------+ */ 0x0000, 0x8000, 0x8000, 0xb000, 0xc800, 0x8800, 0x8800, 0x8800, 0x0000, 0x0000, /* Character 105 (0x69): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | | | ** | | * | | * | | * | | *** | | | | | +------+ */ 0x0000, 0x2000, 0x0000, 0x6000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, 0x0000, /* Character 106 (0x6a): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | | | ** | | * | | * | | * | | * * | | * * | | ** | +------+ */ 0x0000, 0x0800, 0x0000, 0x1800, 0x0800, 0x0800, 0x0800, 0x4800, 0x4800, 0x3000, /* Character 107 (0x6b): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | |* | |* | |* * | |* * | |*** | |* * | |* * | | | | | +------+ */ 0x0000, 0x8000, 0x8000, 0x8800, 0x9000, 0xe000, 0x9000, 0x8800, 0x0000, 0x0000, /* Character 108 (0x6c): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | ** | | * | | * | | * | | * | | * | | *** | | | | | +------+ */ 0x0000, 0x6000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x7000, 0x0000, 0x0000, /* Character 109 (0x6d): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |** * | |* * * | |* * * | |* * * | |* * | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0xd000, 0xa800, 0xa800, 0xa800, 0x8800, 0x0000, 0x0000, /* Character 110 (0x6e): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |* ** | |** * | |* * | |* * | |* * | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0xb000, 0xc800, 0x8800, 0x8800, 0x8800, 0x0000, 0x0000, /* Character 111 (0x6f): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | *** | |* * | |* * | |* * | | *** | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x7000, 0x8800, 0x8800, 0x8800, 0x7000, 0x0000, 0x0000, /* Character 112 (0x70): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |* ** | |** * | |* * | |** * | |* ** | |* | |* | +------+ */ 0x0000, 0x0000, 0x0000, 0xb000, 0xc800, 0x8800, 0xc800, 0xb000, 0x8000, 0x8000, /* Character 113 (0x71): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | ** * | |* ** | |* * | |* ** | | ** * | | * | | * | +------+ */ 0x0000, 0x0000, 0x0000, 0x6800, 0x9800, 0x8800, 0x9800, 0x6800, 0x0800, 0x0800, /* Character 114 (0x72): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |* ** | |** * | |* | |* | |* | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0xb000, 0xc800, 0x8000, 0x8000, 0x8000, 0x0000, 0x0000, /* Character 115 (0x73): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | | *** | |* | | *** | | * | |**** | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x7000, 0x8000, 0x7000, 0x0800, 0xf000, 0x0000, 0x0000, /* Character 116 (0x74): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | |**** | | * | | * | | * * | | ** | | | | | +------+ */ 0x0000, 0x4000, 0x4000, 0xf000, 0x4000, 0x4000, 0x4800, 0x3000, 0x0000, 0x0000, /* Character 117 (0x75): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |* * | |* * | |* * | |* ** | | ** * | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x8800, 0x8800, 0x8800, 0x9800, 0x6800, 0x0000, 0x0000, /* Character 118 (0x76): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |* * | |* * | | * * | | * * | | * | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x8800, 0x8800, 0x5000, 0x5000, 0x2000, 0x0000, 0x0000, /* Character 119 (0x77): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |* * | |* * | |* * * | |* * * | | * * | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x8800, 0x8800, 0xa800, 0xa800, 0x5000, 0x0000, 0x0000, /* Character 120 (0x78): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |* * | | * * | | * | | * * | |* * | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0x8800, 0x5000, 0x2000, 0x5000, 0x8800, 0x0000, 0x0000, /* Character 121 (0x79): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |* * | |* * | |* ** | | ** * | | * | |* * | | *** | +------+ */ 0x0000, 0x0000, 0x0000, 0x8800, 0x8800, 0x9800, 0x6800, 0x0800, 0x8800, 0x7000, /* Character 122 (0x7a): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | | | | |***** | | * | | * | | * | |***** | | | | | +------+ */ 0x0000, 0x0000, 0x0000, 0xf800, 0x1000, 0x2000, 0x4000, 0xf800, 0x0000, 0x0000, /* Character 123 (0x7b): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | ** | | * | | * | | ** | | * | | * | | ** | | | | | +------+ */ 0x0000, 0x1800, 0x2000, 0x1000, 0x6000, 0x1000, 0x2000, 0x1800, 0x0000, 0x0000, /* Character 124 (0x7c): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * | | * | | * | | * | | * | | * | | * | | | | | +------+ */ 0x0000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x0000, 0x0000, /* Character 125 (0x7d): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | ** | | * | | * | | ** | | * | | * | | ** | | | | | +------+ */ 0x0000, 0x6000, 0x1000, 0x2000, 0x1800, 0x2000, 0x1000, 0x6000, 0x0000, 0x0000, /* Character 126 (0x7e): width 6 bbx ( 6, 10, 0, -2 ) +------+ | | | * * | |* * * | |* * | | | | | | | | | | | | | +------+ */ 0x0000, 0x4800, 0xa800, 0x9000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; /* Exported structure definition. */ static const FontDesc stellaDesc = { "6x10-ISO8859-1", 6, 10, 6, 10, 0, -2, 8, 32, 95, stella_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ nullptr, /* fixed bbox*/ 32, sizeof(stella_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-5.1.1/src/gui/StellaLargeFont.hxx000066400000000000000000001621061324334165500201500ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Generated by src/tools/convbdf on Wed Jul 31 13:06:48 2013. //============================================================================ #ifndef STELLALARGE_FONT_DATA_HXX #define STELLALARGE_FONT_DATA_HXX #include "Font.hxx" /* Font information: name: 10x20-ISO8859-1 facename: -Misc-Fixed-Medium-R-Normal--20-200-75-75-C-100-ISO8859-1 w x h: 10x20 bbx: 10 20 0 -4 size: 95 ascent: 16 descent: 4 first char: 32 (0x20) last char: 126 (0x7e) default char: 32 (0x20) proportional: no Public domain font. Share and enjoy. */ namespace GUI { // Font character bitmap data. static const uInt16 stellaLarge_font_bits[] = { /* MODIFIED Character 29 (0x1d): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | XX XX XX | | XX XX XX | | XX XX XX | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0b0110110110000000, 0b0110110110000000, 0b0110110110000000, 0x0000, 0x0000, 0x0000, 0x0000, /* UNUSED Character 30 (0x1e): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* UNUSED Character 31 (0x1f): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 32 (0x20): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 33 (0x21): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0000, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 34 (0x22): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | ** ** | | * * | | | | | | | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x3300, 0x3300, 0x3300, 0x1200, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 35 (0x23): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | ** ** | | ** ** | | ** ** | | ********| | ** ** | | ** ** | | ** ** | | ******** | | ** ** | | ** ** | | ** ** | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0d80, 0x0d80, 0x0d80, 0x3fc0, 0x1b00, 0x1b00, 0x1b00, 0x7f80, 0x3600, 0x3600, 0x3600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 36 (0x24): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ****** | | ** ** ** | | ** ** | | ** ** | | ** ** | | ****** | | ** ** | | ** ** | | ** ** | | ** ** ** | | ****** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x3f00, 0x6d80, 0x6c00, 0x6c00, 0x6c00, 0x3f00, 0x0d80, 0x0d80, 0x0d80, 0x6d80, 0x3f00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 37 (0x25): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | *** ** | | ** ** ** | | ** **** | | *** ** | | ** | | ** | | ** | | ** | | ** *** | | **** **| | ** ** **| | ** *** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x3980, 0x6d80, 0x6f00, 0x3b00, 0x0600, 0x0600, 0x0c00, 0x0c00, 0x1b80, 0x1ec0, 0x36c0, 0x3380, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 38 (0x26): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | *** | | ** ** | | ** ** | | ** ** | | **** | | ** | | *** | | ** ** | | ** ** **| | ** *** | | ** ** | | *** **** | | **** **| | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x3600, 0x3600, 0x3c00, 0x1800, 0x3800, 0x6c00, 0x66c0, 0x6380, 0x6300, 0x7780, 0x3cc0, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 39 (0x27): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | * | | | | | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 40 (0x28): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0300, 0x0600, 0x0c00, 0x0c00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0c00, 0x0c00, 0x0600, 0x0300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 41 (0x29): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x3000, 0x1800, 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0c00, 0x0c00, 0x1800, 0x3000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 42 (0x2a): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | ** ** | | ** ** | | **** | | ******** | | **** | | ** ** | | ** ** | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3300, 0x3300, 0x1e00, 0x7f80, 0x1e00, 0x3300, 0x3300, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 43 (0x2b): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | ** | | ** | | ** | | ******** | | ** | | ** | | ** | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0c00, 0x7f80, 0x0c00, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 44 (0x2c): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | *** | | *** | | *** | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e00, 0x0e00, 0x1c00, 0x0000, 0x0000, 0x0000, /* Character 45 (0x2d): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | | | ******** | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 46 (0x2e): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | *** | | *** | | *** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e00, 0x0e00, 0x0e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 47 (0x2f): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0180, 0x0300, 0x0300, 0x0600, 0x0600, 0x0c00, 0x0c00, 0x1800, 0x1800, 0x3000, 0x3000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 48 (0x30): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x1e00, 0x3300, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x3300, 0x3300, 0x1e00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 49 (0x31): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | *** | | **** | | ** ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x1c00, 0x3c00, 0x6c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 50 (0x32): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** ** | | ** | | ** | | ** | | *** | | ** | | ** | | ** | | ** | | ******** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6180, 0x0180, 0x0180, 0x0300, 0x0e00, 0x1800, 0x3000, 0x6000, 0x6000, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 51 (0x33): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** ** | | ** | | ** | | *** | | ** | | ** | | ** ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6180, 0x0180, 0x0300, 0x0e00, 0x0300, 0x0180, 0x6180, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 52 (0x34): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | * | | ** | | *** | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ******** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0100, 0x0300, 0x0700, 0x0f00, 0x1b00, 0x3300, 0x6300, 0x6300, 0x7f80, 0x0300, 0x0300, 0x0300, 0x0300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 53 (0x35): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ******** | | ** | | ** | | ** | | ** | | ** *** | | *** ** | | ** | | ** | | ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7f80, 0x6000, 0x6000, 0x6000, 0x6000, 0x6e00, 0x7300, 0x0180, 0x0180, 0x0180, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 54 (0x36): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** * | | ** | | ** | | ** *** | | *** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6100, 0x6000, 0x6000, 0x6e00, 0x7300, 0x6180, 0x6180, 0x6180, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 55 (0x37): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ******** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7f80, 0x0180, 0x0180, 0x0300, 0x0300, 0x0600, 0x0600, 0x0c00, 0x0c00, 0x1800, 0x1800, 0x3000, 0x3000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 56 (0x38): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6180, 0x6180, 0x3300, 0x1e00, 0x3300, 0x6180, 0x6180, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 57 (0x39): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** *** | | *** ** | | ** | | ** | | * ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x3380, 0x1d80, 0x0180, 0x0180, 0x2180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 58 (0x3a): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | *** | | *** | | | | | | | | | | *** | | *** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e00, 0x0e00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e00, 0x0e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 59 (0x3b): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | *** | | *** | | | | | | | | | | *** | | *** | | *** | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e00, 0x0e00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0e00, 0x0e00, 0x1c00, 0x0000, 0x0000, 0x0000, /* Character 60 (0x3c): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | * | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | * | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0100, 0x0300, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0300, 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 61 (0x3d): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | ******** | | | | | | | | | | ******** | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 62 (0x3e): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | * | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | * | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x2000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0300, 0x0180, 0x0300, 0x0600, 0x0c00, 0x1800, 0x3000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 63 (0x3f): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** | | ** | | ** | | ** | | ** | | | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6180, 0x6180, 0x0300, 0x0600, 0x0c00, 0x0c00, 0x0c00, 0x0000, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 64 (0x40): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** **** | | ** ***** | | ** ** ** | | ** ** ** | | ** ** ** | | ** **** | | ** ** | | ** | | ** ** | | ***** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6780, 0x6f80, 0x6d80, 0x6d80, 0x6d80, 0x6f00, 0x6600, 0x6000, 0x3180, 0x1f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 65 (0x41): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ******** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x1e00, 0x3300, 0x3300, 0x6180, 0x6180, 0x6180, 0x7f80, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 66 (0x42): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7c00, 0x6600, 0x6300, 0x6300, 0x6300, 0x6600, 0x7e00, 0x6300, 0x6180, 0x6180, 0x6180, 0x6300, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 67 (0x43): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 68 (0x44): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7e00, 0x6300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6300, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 69 (0x45): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ******** | | ** | | ** | | ** | | ** | | ** | | ****** | | ** | | ** | | ** | | ** | | ** | | ******** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7f80, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7e00, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 70 (0x46): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ******** | | ** | | ** | | ** | | ** | | ** | | ****** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7f80, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7e00, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 71 (0x47): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** | | ** | | ** | | ** **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** *** | | **** * | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6000, 0x6000, 0x6000, 0x6780, 0x6180, 0x6180, 0x6180, 0x6180, 0x3380, 0x1e80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 72 (0x48): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ******** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x7f80, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 73 (0x49): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ******** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7f80, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 74 (0x4a): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ******| | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** ** | | ** ** | | ** ** | | *** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0fc0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x6300, 0x6300, 0x3600, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 75 (0x4b): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6300, 0x6300, 0x6600, 0x6600, 0x7c00, 0x6600, 0x6600, 0x6300, 0x6300, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 76 (0x4c): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 77 (0x4d): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | *** *** | | *** *** | | ******** | | ** ** ** | | ** ** ** | | ** ** ** | | ** ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x7380, 0x7380, 0x7f80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 78 (0x4e): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | *** ** | | *** ** | | **** ** | | **** ** | | ** ** ** | | ** ** ** | | ** **** | | ** **** | | ** *** | | ** *** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x7180, 0x7180, 0x7980, 0x7980, 0x6d80, 0x6d80, 0x6780, 0x6780, 0x6380, 0x6380, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 79 (0x4f): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 80 (0x50): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7e00, 0x6300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6300, 0x7e00, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 81 (0x51): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** ** | | ** **** | | ** ** | | ***** | | ** | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6d80, 0x6780, 0x3300, 0x1f00, 0x0180, 0x0000, 0x0000, 0x0000, /* Character 82 (0x52): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7e00, 0x6300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6300, 0x7e00, 0x6600, 0x6300, 0x6300, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 83 (0x53): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** | | ** | | ** | | **** | | ** | | ** | | ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6000, 0x6000, 0x3000, 0x1e00, 0x0300, 0x0180, 0x0180, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 84 (0x54): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ******** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7f80, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 85 (0x55): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 86 (0x56): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | **** | | **** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x3300, 0x3300, 0x3300, 0x1e00, 0x1e00, 0x1e00, 0x0c00, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 87 (0x57): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** ** | | ** ** ** | | ** ** ** | | ** ** ** | | *** *** | | *** *** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x7380, 0x7380, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 88 (0x58): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | **** | | ** | | **** | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x3300, 0x3300, 0x1e00, 0x1e00, 0x0c00, 0x1e00, 0x1e00, 0x3300, 0x3300, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 89 (0x59): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x3300, 0x3300, 0x1e00, 0x1e00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 90 (0x5a): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ******** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7f80, 0x0180, 0x0180, 0x0300, 0x0600, 0x0600, 0x0c00, 0x1800, 0x1800, 0x3000, 0x6000, 0x6000, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 91 (0x5b): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ****** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x3f00, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 92 (0x5c): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x3000, 0x3000, 0x1800, 0x1800, 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0300, 0x0300, 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 93 (0x5d): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ****** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x3f00, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x3f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 94 (0x5e): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | **** | | ** ** | | ** ** | | | | | | | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x1e00, 0x3300, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 95 (0x5f): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | *********| | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7fc0, 0x0000, 0x0000, 0x0000, /* Character 96 (0x60): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x1800, 0x0c00, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 97 (0x61): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ***** | | ** ** | | ** | | ******* | | ** ** | | ** ** | | ** ** | | ***** * | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1f00, 0x3180, 0x0180, 0x3f80, 0x6180, 0x6180, 0x6180, 0x3e80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 98 (0x62): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** *** | | *** ** | | ** ** | | ** ** | | ** ** | | ** ** | | *** ** | | ** *** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6e00, 0x7300, 0x6180, 0x6180, 0x6180, 0x6180, 0x7300, 0x6e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 99 (0x63): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ***** | | ** ** | | ** | | ** | | ** | | ** | | ** ** | | ***** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1f00, 0x3180, 0x6000, 0x6000, 0x6000, 0x6000, 0x3180, 0x1f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 100 (0x64): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | *** ** | | ** *** | | ** ** | | ** ** | | ** ** | | ** ** | | ** *** | | *** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x1d80, 0x3380, 0x6180, 0x6180, 0x6180, 0x6180, 0x3380, 0x1d80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 101 (0x65): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | **** | | ** ** | | ** ** | | ******** | | ** | | ** | | ** ** | | ***** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x7f80, 0x6000, 0x6000, 0x3180, 0x1f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 102 (0x66): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** ** | | ** ** | | ** | | ** | | ****** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0f00, 0x1980, 0x1980, 0x1800, 0x1800, 0x7e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 103 (0x67): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ***** * | | ** *** | | ** ** | | ** ** | | ** ** | | ***** | | ** | | ****** | | ** ** | | ** ** | | ** ** | | ****** | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e80, 0x6380, 0x6300, 0x6300, 0x6300, 0x3e00, 0x6000, 0x3f00, 0x6180, 0x6180, 0x6180, 0x3f00, /* Character 104 (0x68): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** *** | | *** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6e00, 0x7300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 105 (0x69): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | ** | | ** | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ******** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0000, 0x3c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 106 (0x6a): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | ** | | ** | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** ** | | ** ** | | ** ** | | ***** | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0180, 0x0000, 0x0780, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x3180, 0x3180, 0x3180, 0x1f00, /* Character 107 (0x6b): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** ** | | ** ** | | ** ** | | **** | | ***** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6300, 0x6600, 0x6c00, 0x7800, 0x7c00, 0x6600, 0x6300, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 108 (0x6c): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x3c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x7f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 109 (0x6d): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | * ** ** | | ******** | | ** ** ** | | ** ** ** | | ** ** ** | | ** ** ** | | ** ** ** | | ** ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5b00, 0x7f80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x6d80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 110 (0x6e): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ** *** | | *** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6e00, 0x7300, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 111 (0x6f): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6180, 0x6180, 0x6180, 0x6180, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 112 (0x70): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ** *** | | *** ** | | ** ** | | ** ** | | ** ** | | ** ** | | *** ** | | ** *** | | ** | | ** | | ** | | ** | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6e00, 0x7300, 0x6180, 0x6180, 0x6180, 0x6180, 0x7300, 0x6e00, 0x6000, 0x6000, 0x6000, 0x6000, /* Character 113 (0x71): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | *** ** | | ** *** | | ** ** | | ** ** | | ** ** | | ** ** | | ** *** | | *** ** | | ** | | ** | | ** | | ** | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1d80, 0x3380, 0x6180, 0x6180, 0x6180, 0x6180, 0x3380, 0x1d80, 0x0180, 0x0180, 0x0180, 0x0180, /* Character 114 (0x72): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ** **** | | *** ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6f00, 0x3980, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 115 (0x73): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ****** | | ** ** | | ** | | ****** | | ** | | ** | | ** ** | | ****** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3f00, 0x6180, 0x6000, 0x3f00, 0x0180, 0x0180, 0x6180, 0x3f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 116 (0x74): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | ** | | ** | | ** | | ****** | | ** | | ** | | ** | | ** | | ** | | ** ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0x7e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1980, 0x0f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 117 (0x75): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** *** | | *** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x3380, 0x1d80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 118 (0x76): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | **** | | **** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x3300, 0x3300, 0x1e00, 0x1e00, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 119 (0x77): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** ** | | ** ** ** | | ** ** ** | | ******** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6d80, 0x6d80, 0x6d80, 0x7f80, 0x3300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 120 (0x78): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ** ** | | ** ** | | **** | | ** | | ** | | **** | | ** ** | | ** ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x3300, 0x1e00, 0x0c00, 0x0c00, 0x1e00, 0x3300, 0x6180, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 121 (0x79): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** *** | | *** ** | | ** | | ** ** | | ** ** | | **** | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x6180, 0x3380, 0x1d80, 0x0180, 0x6180, 0x3300, 0x1e00, /* Character 122 (0x7a): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | | | | | | | | | | | ******* | | ** | | ** | | ** | | ** | | ** | | ** | | ******* | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3f80, 0x0180, 0x0300, 0x0600, 0x0c00, 0x1800, 0x3000, 0x3f80, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 123 (0x7b): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** | | ** | | ** | | ** | | ** | | **** | | ** | | ** | | ** | | ** | | ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0780, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x7800, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0780, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 124 (0x7c): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 125 (0x7d): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | **** | | ** | | ** | | ** | | ** | | ** | | **** | | ** | | ** | | ** | | ** | | ** | | **** | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x7800, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0780, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x7800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 126 (0x7e): width 10 bbx ( 10, 20, 0, -4 ) +----------+ | | | | | | | *** ** | | ** ** ** | | ** *** | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +----------+ */ 0x0000, 0x0000, 0x0000, 0x3980, 0x6d80, 0x6700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; /* Exported structure definition. */ static const FontDesc stellaLargeDesc = { "10x20-ISO8859-1", 10, 20, 10, 20, 0, -4, 16, 29, 98, stellaLarge_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ nullptr, /* fixed bbox*/ 32, sizeof(stellaLarge_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-5.1.1/src/gui/StellaMediumFont.hxx000066400000000000000000001446621324334165500203450ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Generated by src/tools/convbdf on Wed Jul 31 12:59:06 2013. //============================================================================ #ifndef STELLAMEDIUM_FONT_DATA_HXX #define STELLAMEDIUM_FONT_DATA_HXX #include "Font.hxx" /* Font information: name: 9x18B-ISO8859-1 facename: -Misc-Fixed-Bold-R-Normal--18-120-100-100-C-90-ISO8859-1 w x h: 9x18 bbx: 9 18 0 -4 size: 95 ascent: 14 descent: 4 first char: 30 (0x1e) last char: 126 (0x7e) default char: 30 (0x1e) proportional: no Public domain font. Share and enjoy. */ namespace GUI { // Font character bitmap data. static const uInt16 stellaMedium_font_bits[] = { /* MODIFIED Character 29 (0x1d): ellipsis width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | | XX XX XX| | XX XX XX| | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0b0110110110000000, 0b0110110110000000, 0x0000, 0x0000, 0x0000, 0x0000, /* MODIFIED Character 30 (0x1e): large centered rounded rectangle width 9 bbx ( 9, 15, 0, -3 ) +---------+ | ***** | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ******* | | ***** | +---------+ */ 0x3e00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x3e00, /* MODIFIED Character 31 (0x1f): large centered circle width 9 bbx ( 9, 15, 0, -3 ) +---------+ | | | | | | | | | | | *** | | ***** | | ******* | | ******* | | ******* | | ******* | | ***** | | *** | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3e00, 0x7f00, 0x7f00, 0x7f00, 0x7f00, 0x3e00, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 32 (0x20): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 33 (0x21): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 34 (0x22): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x3600, 0x3600, 0x3600, 0x3600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 35 (0x23): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | ** ** | | ** ** | | ******* | | ** ** | | ** ** | | ******* | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x3600, 0x3600, 0x3600, 0x7f00, 0x3600, 0x3600, 0x7f00, 0x3600, 0x3600, 0x3600, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 36 (0x24): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ****** | |** ** ** | |** ** | | **** | | **** | | **** | | ** ** | |** ** ** | | ****** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x7e00, 0xdb00, 0xd800, 0x7800, 0x3c00, 0x1e00, 0x1b00, 0xdb00, 0x7e00, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 37 (0x25): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** ** | |** **** | |** **** | | ** ** | | ** | | ** | | ** ** | | **** ** | | **** ** | |** *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7300, 0xde00, 0xde00, 0x6c00, 0x1800, 0x1800, 0x3600, 0x7b00, 0x7b00, 0xce00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 38 (0x26): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | |** ** | |** ** | |** ** | | *** | | *** ** | |** **** | |** ** | |** **** | | *** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7000, 0xd800, 0xd800, 0xd800, 0x7000, 0x7300, 0xde00, 0xcc00, 0xde00, 0x7300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 39 (0x27): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | ** | | ** | | ** | | ** | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 40 (0x28): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0c00, 0x1800, 0x1800, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x1800, 0x1800, 0x0c00, 0x0000, 0x0000, 0x0000, /* Character 41 (0x29): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x3000, 0x1800, 0x1800, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x1800, 0x1800, 0x3000, 0x0000, 0x0000, 0x0000, /* Character 42 (0x2a): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | ** | |** ** ** | | ****** | | **** | | ****** | |** ** ** | | ** | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0xdb00, 0x7e00, 0x3c00, 0x7e00, 0xdb00, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 43 (0x2b): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | ** | | ** | | ** | |******** | | ** | | ** | | ** | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0xff00, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 44 (0x2c): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | | *** | | *** | | ** | | ** | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x1c00, 0x0c00, 0x1800, 0x0000, 0x0000, /* Character 45 (0x2d): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | | | | | ******* | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 46 (0x2e): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | | *** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 47 (0x2f): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | |** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0300, 0x0600, 0x0600, 0x0c00, 0x1800, 0x1800, 0x3000, 0x6000, 0x6000, 0xc000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 48 (0x30): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x3600, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 49 (0x31): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | *** | | **** | |** ** | | ** | | ** | | ** | | ** | | ** | |******** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x3800, 0x7800, 0xd800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0xff00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 50 (0x32): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | | ** ** | | ** ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******* | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x6300, 0x0300, 0x0300, 0x0600, 0x0c00, 0x1800, 0x3000, 0x7f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 51 (0x33): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ******* | | ** | | ** | | ** | | *** | | ** | | ** | | ** | | ** ** | | **** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x0300, 0x0600, 0x0c00, 0x1c00, 0x0600, 0x0300, 0x0300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 52 (0x34): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | *** | | **** | | ** ** | | ** ** | | ** ** | | ******* | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0600, 0x0e00, 0x1e00, 0x3600, 0x6600, 0x6600, 0x7f00, 0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 53 (0x35): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ******* | | ** | | ** | | ** | | ***** | | ** | | ** | | ** | | ** ** | | **** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x6000, 0x6000, 0x6000, 0x7c00, 0x0600, 0x0300, 0x0300, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 54 (0x36): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | **** | | ** | | ** | | ** | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1e00, 0x3000, 0x6000, 0x6000, 0x7c00, 0x6600, 0x6300, 0x6300, 0x3600, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 55 (0x37): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ******* | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x0300, 0x0600, 0x0600, 0x0c00, 0x0c00, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 56 (0x38): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | | ** ** | | ** ** | | ** ** | | *** | | ** ** | | ** ** | | ** ** | | ** ** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x6300, 0x3600, 0x1c00, 0x3600, 0x6300, 0x6300, 0x3600, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 57 (0x39): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | | ** ** | | ** ** | | ** ** | | ** *** | | ***** | | ** | | ** | | ** | | **** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x6300, 0x6300, 0x3700, 0x1f00, 0x0300, 0x0300, 0x0600, 0x3c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 58 (0x3a): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | *** | | *** | | | | | | | | *** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x1c00, 0x0000, 0x0000, 0x0000, 0x1c00, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 59 (0x3b): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | *** | | *** | | | | | | | | *** | | *** | | ** | | ** | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x1c00, 0x0000, 0x0000, 0x0000, 0x1c00, 0x1c00, 0x0c00, 0x1800, 0x0000, 0x0000, /* Character 60 (0x3c): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 61 (0x3d): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | | | ******* | | | | | | ******* | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x0000, 0x0000, 0x7f00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 62 (0x3e): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6000, 0x3000, 0x1800, 0x0c00, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 63 (0x3f): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | | ** ** | | ** ** | | ** | | ** | | ** | | ** | | ** | | | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x6300, 0x0300, 0x0600, 0x0c00, 0x1800, 0x1800, 0x0000, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 64 (0x40): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ***** | | ** ** | |** ** **| |** * * **| |** * * **| |** * * **| |** * * **| |** **** | | ** | | ***** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x6300, 0xcd80, 0xd580, 0xd580, 0xd580, 0xd580, 0xcf00, 0x6000, 0x3e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 65 (0x41): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | * | | *** | | *** | | *** | | ** ** | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x1c00, 0x1c00, 0x1c00, 0x3600, 0x3e00, 0x3600, 0x6300, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 66 (0x42): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ****** | | ** ** | | ** ** | | ** ** | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x6300, 0x6300, 0x6300, 0x7e00, 0x6300, 0x6300, 0x6300, 0x6300, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 67 (0x43): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | **** | | ** ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** ** | | **** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1e00, 0x3300, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x3300, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 68 (0x44): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ***** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0x6600, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6600, 0x7c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 69 (0x45): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ******* | | ** | | ** | | ** | | ***** | | ** | | ** | | ** | | ** | | ******* | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x6000, 0x6000, 0x6000, 0x7c00, 0x6000, 0x6000, 0x6000, 0x6000, 0x7f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 70 (0x46): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ******* | | ** | | ** | | ** | | ***** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x6000, 0x6000, 0x6000, 0x7c00, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 71 (0x47): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | | ** ** | | ** ** | | ** | | ** | | ** *** | | ** ** | | ** ** | | ** ** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x6300, 0x6000, 0x6000, 0x6700, 0x6300, 0x6300, 0x3600, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 72 (0x48): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ******* | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x6300, 0x6300, 0x7f00, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 73 (0x49): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ****** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 74 (0x4a): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ** ** | | ** ** | | **** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0f00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x6600, 0x6600, 0x3c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 75 (0x4b): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | ** ** | | ** ** | | **** | | *** | | **** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6600, 0x6c00, 0x7800, 0x7000, 0x7800, 0x6c00, 0x6600, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 76 (0x4c): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******* | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x7f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 77 (0x4d): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | *** *** | | ******* | | ** * ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x7700, 0x7f00, 0x6b00, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 78 (0x4e): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | ** ** | | *** ** | | **** ** | | ** **** | | ** *** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x7300, 0x7b00, 0x6f00, 0x6700, 0x6300, 0x6300, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 79 (0x4f): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ***** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 80 (0x50): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | ***** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0x6600, 0x6300, 0x6300, 0x6600, 0x7c00, 0x6000, 0x6000, 0x6000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 81 (0x51): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** **** | | ** ** | | ***** | | **| | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6f00, 0x3600, 0x1f00, 0x0180, 0x0000, 0x0000, 0x0000, /* Character 82 (0x52): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x6300, 0x6300, 0x6300, 0x6300, 0x7e00, 0x6c00, 0x6600, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 83 (0x53): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ***** | | ** ** | | ** | | ** | | ***** | | ** | | ** | | ** | | ** ** | | ***** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x6300, 0x6000, 0x6000, 0x3e00, 0x0300, 0x0300, 0x0300, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 84 (0x54): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ****** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 85 (0x55): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x3600, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 86 (0x56): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | *** | | *** | | *** | | * | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x6300, 0x3600, 0x3600, 0x3600, 0x1c00, 0x1c00, 0x1c00, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 87 (0x57): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** * ** | | ** * ** | | ** * ** | | ******* | | *** *** | | * * | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x6300, 0x6300, 0x6b00, 0x6b00, 0x6b00, 0x7f00, 0x7700, 0x2200, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 88 (0x58): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** ** | | ** ** | | ** ** | | *** | | * | | * | | *** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x3600, 0x1c00, 0x0800, 0x0800, 0x1c00, 0x3600, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 89 (0x59): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | |** ** | |** ** | | ** ** | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xc300, 0xc300, 0x6600, 0x3c00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 90 (0x5a): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ******* | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ******* | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7f00, 0x0300, 0x0300, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x6000, 0x7f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 91 (0x5b): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | ***** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ***** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x3e00, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x3e00, 0x0000, 0x0000, 0x0000, /* Character 92 (0x5c): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | |** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0xc000, 0x6000, 0x6000, 0x3000, 0x1800, 0x1800, 0x0c00, 0x0600, 0x0600, 0x0300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 93 (0x5d): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | **** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x3c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x0c00, 0x3c00, 0x0000, 0x0000, 0x0000, /* Character 94 (0x5e): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | **** | | ** ** | |** ** | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x3c00, 0x6600, 0xc300, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 95 (0x5f): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | | | | | | | | | | | | | | |******** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff00, 0x0000, 0x0000, 0x0000, /* Character 96 (0x60): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | ** | | ** | | ** | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x3000, 0x1800, 0x0c00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 97 (0x61): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ***** | | ** | | ** | | ****** | | ** ** | | ** ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x0300, 0x0300, 0x3f00, 0x6300, 0x6300, 0x3f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 98 (0x62): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ** | | ** | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x7e00, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 99 (0x63): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ***** | | ** ** | | ** | | ** | | ** | | ** ** | | ***** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x6300, 0x6000, 0x6000, 0x6000, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 100 (0x64): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ** | | ** | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0300, 0x0300, 0x0300, 0x3f00, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x3f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 101 (0x65): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ***** | | ** ** | | ** ** | | ******* | | ** | | ** ** | | ***** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x6300, 0x6300, 0x7f00, 0x6000, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 102 (0x66): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** | | ** ** | | ** ** | | ** | | ** | | **** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x3600, 0x3000, 0x3000, 0x7800, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 103 (0x67): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ****** | | ** ** | | ** ** | | ** ** | | **** | | ** | | ***** | | ** ** | | ** ** | | ***** | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3f00, 0x6600, 0x6600, 0x6600, 0x3c00, 0x6000, 0x3e00, 0x6300, 0x6300, 0x3e00, 0x0000, /* Character 104 (0x68): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ** | | ** | | ****** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x7e00, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 105 (0x69): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ** | | | | **** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x0000, 0x7800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 106 (0x6a): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ** | | | | *** | | ** | | ** | | ** | | ** | | ** | | ** | | ** ** | | ** ** | | *** | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0600, 0x0600, 0x0000, 0x0e00, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x3600, 0x3600, 0x1c00, 0x0000, /* Character 107 (0x6b): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | ** | | ** | | ** | | ** ** | | ** ** | | **** | | **** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x6000, 0x6000, 0x6000, 0x6600, 0x6c00, 0x7800, 0x7800, 0x6c00, 0x6600, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 108 (0x6c): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 109 (0x6d): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | |******* | |** ** ** | |** ** ** | |** ** ** | |** ** ** | |** ** ** | |** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xfe00, 0xdb00, 0xdb00, 0xdb00, 0xdb00, 0xdb00, 0xc300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 110 (0x6e): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ** *** | | *** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6e00, 0x7300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 111 (0x6f): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | *** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1c00, 0x3600, 0x6300, 0x6300, 0x6300, 0x3600, 0x1c00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 112 (0x70): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ***** | | ** | | ** | | ** | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7c00, 0x6600, 0x6300, 0x6300, 0x6300, 0x6600, 0x7c00, 0x6000, 0x6000, 0x6000, 0x0000, /* Character 113 (0x71): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ***** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ***** | | ** | | ** | | ** | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1f00, 0x3300, 0x6300, 0x6300, 0x6300, 0x3300, 0x1f00, 0x0300, 0x0300, 0x0300, 0x0000, /* Character 114 (0x72): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ** *** | | *** ** | | ** | | ** | | ** | | ** | | ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6e00, 0x3b00, 0x3000, 0x3000, 0x3000, 0x3000, 0x3000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 115 (0x73): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ***** | | ** ** | | ** | | ***** | | ** | | ** ** | | ***** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3e00, 0x6300, 0x6000, 0x3e00, 0x0300, 0x6300, 0x3e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 116 (0x74): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | ** | | ** | | ****** | | ** | | ** | | ** | | ** | | ** ** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x7e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x1b00, 0x0e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 117 (0x75): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x6300, 0x3f00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 118 (0x76): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | *** | | *** | | * | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x3600, 0x3600, 0x1c00, 0x1c00, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 119 (0x77): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | |** ** | |** ** | |** ** ** | |** ** ** | |** ** ** | |******** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xc300, 0xc300, 0xdb00, 0xdb00, 0xdb00, 0xff00, 0x6600, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 120 (0x78): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ** ** | | ** ** | | *** | | * | | *** | | ** ** | | ** ** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x3600, 0x1c00, 0x0800, 0x1c00, 0x3600, 0x6300, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 121 (0x79): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ** ** | | ** ** | | ** ** | | ** ** | | ** ** | | *** | | *** | | ** | | * ** | | ** | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x6300, 0x6300, 0x3600, 0x3600, 0x3600, 0x1c00, 0x1c00, 0x1800, 0x5800, 0x3000, 0x0000, /* Character 122 (0x7a): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | | | | | | | ****** | | ** | | ** | | ** | | ** | | ** | | ****** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7e00, 0x0600, 0x0c00, 0x1800, 0x3000, 0x6000, 0x7e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 123 (0x7b): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | **** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | **** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x1e00, 0x3000, 0x3000, 0x3000, 0x3000, 0x6000, 0x3000, 0x3000, 0x3000, 0x3000, 0x1e00, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 124 (0x7c): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | ** | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, 0x0000, 0x0000, /* Character 125 (0x7d): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | *** | | ** | | ** | | ** | | ** | | *** | | ** | | ** | | ** | | ** | | *** | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x7000, 0x1800, 0x1800, 0x1800, 0x1800, 0x0e00, 0x1800, 0x1800, 0x1800, 0x1800, 0x7000, 0x0000, 0x0000, 0x0000, 0x0000, /* Character 126 (0x7e): width 9 bbx ( 9, 18, 0, -4 ) +---------+ | | | | | | | | | *** ** | |** ** ** | |** *** | | | | | | | | | | | | | | | | | | | | | | | +---------+ */ 0x0000, 0x0000, 0x0000, 0x0000, 0x7300, 0xdb00, 0xce00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }; /* Exported structure definition. */ static const FontDesc stellaMediumDesc = { "9x18B-ISO8859-1", 9, 18, 9, 18, 0, -4, 14, 29, 98, stellaMedium_font_bits, nullptr, /* no encode table*/ nullptr, /* fixed width*/ nullptr, /* fixed bbox*/ 32, // Originally 30 sizeof(stellaMedium_font_bits)/sizeof(uInt16) }; } // End of namespace GUI #endif stella-5.1.1/src/gui/StringListWidget.cxx000066400000000000000000000062151324334165500203610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "FBSurface.hxx" #include "Settings.hxx" #include "ScrollBarWidget.hxx" #include "StringListWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StringListWidget::StringListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, bool hilite) : ListWidget(boss, font, x, y, w, h, boss->instance().settings().getInt("listdelay") >= 300), _hilite(hilite) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StringListWidget::setList(const StringList& list) { _list = list; ListWidget::recalc(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StringListWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); int i, pos, len = int(_list.size()); // Draw a thin frame around the list. s.hLine(_x, _y, _x + _w - 1, kColor); s.hLine(_x, _y + _h - 1, _x + _w - 1, kShadowColor); s.vLine(_x, _y, _y + _h - 1, kColor); // Draw the list items for (i = 0, pos = _currentPos; i < _rows && pos < len; i++, pos++) { const int y = _y + 2 + _fontHeight * i; uInt32 textColor = kTextColor; // Draw the selected item inverted, on a highlighted background. if (_selectedItem == pos && _hilite) { if(_hasFocus && !_editMode) { s.fillRect(_x + 1, _y + 1 + _fontHeight * i, _w - 1, _fontHeight, kTextColorHi); textColor = kTextColorInv; } else s.frameRect(_x + 1, _y + 1 + _fontHeight * i, _w - 1, _fontHeight, kTextColorHi); } GUI::Rect r(getEditRect()); if (_selectedItem == pos && _editMode) { adjustOffset(); s.drawString(_font, editString(), _x + r.left, y, r.width(), textColor, TextAlign::Left, -_editScrollOffset, false); } else s.drawString(_font, _list[pos], _x + r.left, y, r.width(), textColor); } // Only draw the caret while editing, and if it's in the current viewport if(_editMode && (_selectedItem >= _scrollBar->_currentPos) && (_selectedItem < _scrollBar->_currentPos + _rows)) drawCaret(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GUI::Rect StringListWidget::getEditRect() const { GUI::Rect r(2, 1, _w - 2, _fontHeight); const int offset = (_selectedItem - _currentPos) * _fontHeight; r.top += offset; r.bottom += offset; return r; } stella-5.1.1/src/gui/StringListWidget.hxx000066400000000000000000000031371324334165500203660ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef STRING_LIST_WIDGET_HXX #define STRING_LIST_WIDGET_HXX #include "ListWidget.hxx" /** StringListWidget */ class StringListWidget : public ListWidget { public: StringListWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, bool hilite = true); virtual ~StringListWidget() = default; void setList(const StringList& list); bool wantsFocus() const override { return true; } protected: void drawWidget(bool hilite) override; GUI::Rect getEditRect() const override; protected: bool _hilite; private: // Following constructors and assignment operators not supported StringListWidget() = delete; StringListWidget(const StringListWidget&) = delete; StringListWidget(StringListWidget&&) = delete; StringListWidget& operator=(const StringListWidget&) = delete; StringListWidget& operator=(StringListWidget&&) = delete; }; #endif stella-5.1.1/src/gui/TabWidget.cxx000066400000000000000000000241161324334165500167650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "FBSurface.hxx" #include "Font.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "Widget.hxx" #include "TabWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TabWidget::TabWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : Widget(boss, font, x, y, w, h), CommandSender(boss), _tabWidth(40), _activeTab(-1), _firstTime(true) { _id = 0; // For dialogs with multiple tab widgets, they should specifically // call ::setID to differentiate among them _flags = WIDGET_ENABLED | WIDGET_CLEARBG; _bgcolor = kDlgColor; _bgcolorhi = kDlgColor; _textcolor = kTextColor; _textcolorhi = kTextColor; _tabHeight = font.getLineHeight() + 4; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TabWidget::~TabWidget() { for(auto& tab: _tabs) { delete tab.firstWidget; tab.firstWidget = nullptr; // _tabs[i].parentWidget is deleted elsewhere } _tabs.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TabWidget::getChildY() const { return getAbsY() + _tabHeight; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int TabWidget::addTab(const string& title) { // Add a new tab page _tabs.push_back(Tab(title)); int numTabs = int(_tabs.size()); // Determine the new tab width int newWidth = _font.getStringWidth(title) + 2 * kTabPadding; if (_tabWidth < newWidth) _tabWidth = newWidth; int maxWidth = (_w - kTabLeftOffset) / numTabs - kTabLeftOffset; if (_tabWidth > maxWidth) _tabWidth = maxWidth; // Activate the new tab setActiveTab(numTabs - 1); return _activeTab; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::setActiveTab(int tabID, bool show) { assert(0 <= tabID && tabID < int(_tabs.size())); if (_activeTab != -1) { // Exchange the widget lists, and switch to the new tab _tabs[_activeTab].firstWidget = _firstWidget; } _activeTab = tabID; _firstWidget = _tabs[tabID].firstWidget; // Let parent know about the tab change if(show) sendCommand(TabWidget::kTabChangedCmd, _activeTab, _id); } #if 0 // FIXME // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::disableTab(int tabID) { assert(0 <= tabID && tabID < int(_tabs.size())); _tabs[tabID].enabled = false; // TODO - also disable all widgets belonging to this tab } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::updateActiveTab() { if(_activeTab < 0) return; if(_tabs[_activeTab].parentWidget) _tabs[_activeTab].parentWidget->loadConfig(); setDirty(); // Redraw focused areas _boss->redrawFocus(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::activateTabs() { for(uInt32 i = 0; i <_tabs.size(); ++i) sendCommand(TabWidget::kTabChangedCmd, i-1, _id); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::cycleTab(int direction) { int tabID = _activeTab; // Don't do anything if no tabs have been defined if(tabID == -1) return; if(direction == -1) // Go to the previous tab, wrap around at beginning { tabID--; if(tabID == -1) tabID = int(_tabs.size()) - 1; } else if(direction == 1) // Go to the next tab, wrap around at end { tabID++; if(tabID == int(_tabs.size())) tabID = 0; } // Finally, select the active tab setActiveTab(tabID, true); updateActiveTab(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::setParentWidget(int tabID, Widget* parent) { assert(0 <= tabID && tabID < int(_tabs.size())); _tabs[tabID].parentWidget = parent; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { assert(y < _tabHeight); // Determine which tab was clicked int tabID = -1; x -= kTabLeftOffset; if (x >= 0 && x % (_tabWidth + kTabSpacing) < _tabWidth) { tabID = x / (_tabWidth + kTabSpacing); if (tabID >= int(_tabs.size())) tabID = -1; } // If a tab was clicked, switch to that pane if (tabID >= 0) { setActiveTab(tabID, true); updateActiveTab(); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::handleMouseEntered() { setFlags(WIDGET_HILITED); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::handleMouseLeft() { clearFlags(WIDGET_HILITED); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { default: sendCommand(cmd, data, _id); break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool TabWidget::handleEvent(Event::Type event) { bool handled = false; switch (event) { case Event::UIRight: case Event::UIPgDown: cycleTab(1); handled = true; break; case Event::UILeft: case Event::UIPgUp: cycleTab(-1); handled = true; break; default: break; } return handled; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::loadConfig() { if(_firstTime) { setActiveTab(_activeTab, true); _firstTime = false; } updateActiveTab(); } #ifndef FLAT_UI // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::box(int x, int y, int width, int height, uInt32 colorA, uInt32 colorB, bool omitBottom) { //cerr << "TabWidget::box\n"; FBSurface& s = _boss->dialog().surface(); s.hLine(x + 1, y, x + width - 2, colorA); s.hLine(x, y + 1, x + width - 1, colorA); s.vLine(x, y + 1, y + height - (omitBottom ? 1 : 2), colorA); s.vLine(x + 1, y, y + height - (omitBottom ? 2 : 1), colorA); if (!omitBottom) { s.hLine(x + 1, y + height - 2, x + width - 1, colorB); s.hLine(x + 1, y + height - 1, x + width - 2, colorB); } s.vLine(x + width - 1, y + 1, y + height - (omitBottom ? 1 : 2), colorB); s.vLine(x + width - 2, y + 1, y + height - (omitBottom ? 2 : 1), colorB); } #endif // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TabWidget::drawWidget(bool hilite) { // The tab widget is strange in that it acts as both a widget (obviously) // and a dialog (it contains other widgets). Because of the latter, // it must assume responsibility for refreshing all its children. Widget::setDirtyInChain(_tabs[_activeTab].firstWidget); FBSurface& s = dialog().surface(); const int left1 = _x + 1; const int right1 = _x + kTabLeftOffset + _activeTab * (_tabWidth + kTabSpacing); const int left2 = right1 + _tabWidth; const int right2 = _x + _w - 2; #ifndef FLAT_UI // Draw horizontal line s.hLine(left1, _y + _tabHeight - 2, right1, kShadowColor); s.hLine(left2, _y + _tabHeight - 2, right2, kShadowColor); #endif // Iterate over all tabs and draw them int i, x = _x + kTabLeftOffset; for (i = 0; i < int(_tabs.size()); ++i) { uInt32 fontcolor = _tabs[i].enabled ? kTextColor : kColor; #ifndef FLAT_UI uInt32 boxcolor = (i == _activeTab) ? kColor : kShadowColor; int yOffset = (i == _activeTab) ? 0 : 2; box(x, _y + yOffset, _tabWidth, _tabHeight - yOffset, boxcolor, boxcolor, (i == _activeTab)); s.drawString(_font, _tabs[i].title, x + kTabPadding, _y + yOffset / 2 + (_tabHeight - _fontHeight - 1), _tabWidth - 2 * kTabPadding, fontcolor, TextAlign::Center); #else int yOffset = (i == _activeTab) ? 0 : 1; s.fillRect(x, _y + 1, _tabWidth, _tabHeight - 1, (i == _activeTab) ? kDlgColor : kBGColorHi); // ? kWidColor : kDlgColor s.drawString(_font, _tabs[i].title, x + kTabPadding + yOffset, _y + yOffset + (_tabHeight - _fontHeight - 1), _tabWidth - 2 * kTabPadding, fontcolor, TextAlign::Center); if(i == _activeTab) { s.hLine(x, _y, x + _tabWidth - 1, kWidColor); s.vLine(x + _tabWidth, _y + 1, _y + _tabHeight - 1, kBGColorLo); } else s.hLine(x, _y + _tabHeight, x + _tabWidth, kWidColor); #endif x += _tabWidth + kTabSpacing; } #ifndef FLAT_UI // Draw a frame around the widget area (belows the tabs) s.hLine(left1, _y + _tabHeight - 1, right1, kColor); s.hLine(left2, _y + _tabHeight - 1, right2, kColor); s.hLine(_x+1, _y + _h - 2, _x + _w - 2, kShadowColor); s.hLine(_x+1, _y + _h - 1, _x + _w - 2, kColor); s.vLine(_x + _w - 2, _y + _tabHeight - 1, _y + _h - 2, kColor); s.vLine(_x + _w - 1, _y + _tabHeight - 1, _y + _h - 2, kShadowColor); #else // fill empty right space s.hLine(x - kTabSpacing + 1, _y + _tabHeight, _x + _w - 1, kWidColor); s.hLine(_x, _y + _h - 1, _x + _w - 1, kBGColorLo); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget* TabWidget::findWidget(int x, int y) { if (y < _tabHeight) { // Click was in the tab area return this; } else { // Iterate over all child widgets and find the one which was clicked return Widget::findWidgetInChain(_firstWidget, x, y - _tabHeight); } } stella-5.1.1/src/gui/TabWidget.hxx000066400000000000000000000067351324334165500170010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TAB_WIDGET_HXX #define TAB_WIDGET_HXX #include "bspf.hxx" #include "Command.hxx" #include "Widget.hxx" class TabWidget : public Widget, public CommandSender { public: enum { kTabChangedCmd = 'TBCH' }; public: TabWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~TabWidget(); // use Dialog::releaseFocus() when changing to another tab // Problem: how to add items to a tab? // First off, widget should allow non-dialog bosses, (i.e. also other widgets) // Could add a common base class for Widgets and Dialogs. // Then you add tabs using the following method, which returns a unique ID int addTab(const string& title); // Maybe we need to remove tabs again? Hm //void removeTab(int tabID); // Setting the active tab: void setActiveTab(int tabID, bool show = false); // void disableTab(int tabID); void activateTabs(); void cycleTab(int direction); // setActiveTab changes the value of _firstWidget. This means Widgets added afterwards // will be added to the active tab. void setParentWidget(int tabID, Widget* parent); int getTabWidth() { return _tabWidth; } int getTabHeight() { return _tabHeight; } int getActiveTab() { return _activeTab; } void loadConfig() override; protected: void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseEntered() override; void handleMouseLeft() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; bool handleEvent(Event::Type event) override; void drawWidget(bool hilite) override; Widget* findWidget(int x, int y) override; int getChildY() const override; private: struct Tab { string title; Widget* firstWidget; Widget* parentWidget; bool enabled; Tab(const string& t = "", Widget* first = nullptr, Widget* parent = nullptr, bool e = true) : title(t), firstWidget(first), parentWidget(parent), enabled(e) { } }; using TabList = vector; TabList _tabs; int _tabWidth; int _tabHeight; int _activeTab; bool _firstTime; enum { #ifndef FLAT_UI kTabLeftOffset = 4, kTabSpacing = 2, kTabPadding = 3 #else kTabLeftOffset = 0, kTabSpacing = 1, kTabPadding = 4 #endif }; private: #ifndef FLAT_UI void box(int x, int y, int width, int height, uInt32 colorA, uInt32 colorB, bool omitBottom); #endif void updateActiveTab(); private: // Following constructors and assignment operators not supported TabWidget() = delete; TabWidget(const TabWidget&) = delete; TabWidget(TabWidget&&) = delete; TabWidget& operator=(const TabWidget&) = delete; TabWidget& operator=(TabWidget&&) = delete; }; #endif stella-5.1.1/src/gui/TimeLineWidget.cxx000066400000000000000000000146161324334165500177710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Command.hxx" #include "Dialog.hxx" #include "Font.hxx" #include "FBSurface.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "TimeLineWidget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TimeLineWidget::TimeLineWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& label, uInt32 labelWidth, int cmd) : ButtonWidget(boss, font, x, y, w, h, label, cmd), _value(0), _valueMin(0), _valueMax(0), _isDragging(false), _labelWidth(labelWidth) { _flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE; _bgcolor = kDlgColor; _bgcolorhi = kDlgColor; if(!_label.empty() && _labelWidth == 0) _labelWidth = _font.getStringWidth(_label); _w = w + _labelWidth; _stepValue.reserve(100); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::setValue(uInt32 value) { value = BSPF::clamp(value, _valueMin, _valueMax); if(value != _value) { _value = value; setDirty(); sendCommand(_cmd, _value, _id); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::setMinValue(uInt32 value) { _valueMin = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::setMaxValue(uInt32 value) { _valueMax = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::setStepValues(const IntArray& steps) { _stepValue.clear(); // If no steps are defined, just use the maximum value if(steps.size() > 0) { // Try to allocate as infrequently as possible if(steps.size() > _stepValue.capacity()) _stepValue.reserve(2 * steps.size()); double scale = (_w - _labelWidth - 2) / double(steps.back()); // Skip the very last value; we take care of it outside the end of the loop for(uInt32 i = 0; i < steps.size() - 1; ++i) _stepValue.push_back(int(steps[i] * scale)); // Due to integer <-> double conversion, the last value is sometimes // slightly less than the maximum value; we assign it manually to fix this _stepValue.push_back(_w - _labelWidth - 2); } else _stepValue.push_back(0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::handleMouseMoved(int x, int y) { if(isEnabled() && _isDragging && x >= int(_labelWidth)) setValue(posToValue(x - _labelWidth)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { if(isEnabled() && b == MouseButton::LEFT) { _isDragging = true; handleMouseMoved(x, y); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { if(isEnabled() && _isDragging) sendCommand(_cmd, _value, _id); _isDragging = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::handleMouseWheel(int x, int y, int direction) { if(isEnabled()) { if(direction < 0 && _value < _valueMax) setValue(_value + 1); else if(direction > 0 && _value > _valueMin) setValue(_value - 1); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeLineWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); #ifndef FLAT_UI // Draw the label, if any if(_labelWidth > 0) s.drawString(_font, _label, _x, _y + 2, _labelWidth, isEnabled() ? kTextColor : kColor, TextAlign::Right); // Draw the box s.frameRect(_x + _labelWidth, _y, _w - _labelWidth, _h, kColor); // Fill the box s.fillRect(_x + _labelWidth + 1, _y + 1, _w - _labelWidth - 2, _h - 2, !isEnabled() ? kBGColorHi : kWidColor); // Draw the 'bar' int vp = valueToPos(_value); s.fillRect(_x + _labelWidth + 1, _y + 1, vp, _h - 2, !isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor); // add 4 tickmarks for 5 intervals int numTicks = std::min(5, int(_stepValue.size())); for(int i = 1; i < numTicks; ++i) { int idx = int((_stepValue.size() * i + numTicks / 2) / numTicks); if(idx > 1) { int tp = valueToPos(idx - 1); s.vLine(_x + _labelWidth + tp, _y + _h / 2, _y + _h - 2, tp > vp ? kSliderColor : kWidColor); } } #else // Draw the label, if any if(_labelWidth > 0) s.drawString(_font, _label, _x, _y + 2, _labelWidth, isEnabled() ? kTextColor : kColor, TextAlign::Left); // Draw the box s.frameRect(_x + _labelWidth, _y, _w - _labelWidth, _h, isEnabled() && hilite ? kSliderColorHi : kShadowColor); // Fill the box s.fillRect(_x + _labelWidth + 1, _y + 1, _w - _labelWidth - 2, _h - 2, !isEnabled() ? kBGColorHi : kWidColor); // Draw the 'bar' s.fillRect(_x + _labelWidth + 2, _y + 2, valueToPos(_value), _h - 4, !isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 TimeLineWidget::valueToPos(uInt32 value) { return _stepValue[BSPF::clamp(value, _valueMin, _valueMax)]; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uInt32 TimeLineWidget::posToValue(uInt32 pos) { // Find the interval in which 'pos' falls, and then the endpoint which // it is closest to for(uInt32 i = 0; i < _stepValue.size() - 1; ++i) if(pos >= _stepValue[i] && pos <= _stepValue[i+1]) return (_stepValue[i+1] - pos) < (pos - _stepValue[i]) ? i+1 : i; return _valueMax; } stella-5.1.1/src/gui/TimeLineWidget.hxx000066400000000000000000000044411324334165500177710ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIMELINE_WIDGET_HXX #define TIMELINE_WIDGET_HXX #include "Widget.hxx" class TimeLineWidget : public ButtonWidget { public: TimeLineWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& label = "", uInt32 labelWidth = 0, int cmd = 0); void setValue(uInt32 value); uInt32 getValue() const { return _value; } void setMinValue(uInt32 value); void setMaxValue(uInt32 value); uInt32 getMinValue() const { return _valueMin; } uInt32 getMaxValue() const { return _valueMax; } /** Steps are not necessarily linear in a timeline, so we need info on each interval instead. */ void setStepValues(const IntArray& steps); protected: void handleMouseMoved(int x, int y) override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; void drawWidget(bool hilite) override; uInt32 valueToPos(uInt32 value); uInt32 posToValue(uInt32 pos); protected: uInt32 _value; uInt32 _valueMin, _valueMax; bool _isDragging; uInt32 _labelWidth; uIntArray _stepValue; private: // Following constructors and assignment operators not supported TimeLineWidget() = delete; TimeLineWidget(const TimeLineWidget&) = delete; TimeLineWidget(TimeLineWidget&&) = delete; TimeLineWidget& operator=(const TimeLineWidget&) = delete; TimeLineWidget& operator=(TimeLineWidget&&) = delete; }; #endif stella-5.1.1/src/gui/TimeMachine.cxx000066400000000000000000000036131324334165500172750ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Dialog.hxx" #include "FrameBuffer.hxx" #include "TimeMachineDialog.hxx" #include "TimeMachine.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TimeMachine::TimeMachine(OSystem& osystem) : DialogContainer(osystem), myWidth(FrameBuffer::kFBMinW) { myBaseDialog = new TimeMachineDialog(myOSystem, *this, myWidth); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeMachine::requestResize() { uInt32 w, h; myBaseDialog->getResizableBounds(w, h); // If dialog is too large for given area, we need to resize it // Otherwise, make it 80% of the allowable width int newWidth = myWidth; if(w < FrameBuffer::kFBMinW) newWidth = w; else if(myBaseDialog->getWidth() != 0.8 * w) newWidth = uInt32(0.8 * w); // Only re-create when absolutely necessary if(myWidth != newWidth) { myWidth = newWidth; Dialog* oldPtr = myBaseDialog; delete myBaseDialog; myBaseDialog = new TimeMachineDialog(myOSystem, *this, myWidth); Dialog* newPtr = myBaseDialog; // Update the container stack; it may contain a reference to the old pointer if(oldPtr != newPtr) myDialogStack.replace(oldPtr, newPtr); } } stella-5.1.1/src/gui/TimeMachine.hxx000066400000000000000000000030001324334165500172700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIME_MACHINE_HXX #define TIME_MACHINE_HXX class OSystem; #include "DialogContainer.hxx" /** The base dialog for all time machine related UI items in Stella. @author Stephen Anthony */ class TimeMachine : public DialogContainer { public: TimeMachine(OSystem& osystem); virtual ~TimeMachine() = default; /** This dialog has an adjustable size. We need to make sure the dialog can fit within the given bounds. */ void requestResize() override; private: int myWidth; private: // Following constructors and assignment operators not supported TimeMachine() = delete; TimeMachine(const TimeMachine&) = delete; TimeMachine(TimeMachine&&) = delete; TimeMachine& operator=(const TimeMachine&) = delete; TimeMachine& operator=(TimeMachine&&) = delete; }; #endif stella-5.1.1/src/gui/TimeMachineDialog.cxx000066400000000000000000000265141324334165500204220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "Dialog.hxx" #include "Font.hxx" #include "EventHandler.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "OSystem.hxx" #include "Widget.hxx" #include "StateManager.hxx" #include "RewindManager.hxx" #include "TimeLineWidget.hxx" #include "Console.hxx" #include "TIA.hxx" #include "System.hxx" #include "TimeMachineDialog.hxx" #include "Base.hxx" using Common::Base; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TimeMachineDialog::TimeMachineDialog(OSystem& osystem, DialogContainer& parent, int width) : Dialog(osystem, parent) { const int BUTTON_W = 16, BUTTON_H = 14; static uInt32 PLAY[BUTTON_H] = { 0b0110000000000000, 0b0111100000000000, 0b0111111000000000, 0b0111111110000000, 0b0111111111100000, 0b0111111111111000, 0b0111111111111110, 0b0111111111111110, 0b0111111111111000, 0b0111111111100000, 0b0111111110000000, 0b0111111000000000, 0b0111100000000000, 0b0110000000000000 }; static uInt32 REWIND_ALL[BUTTON_H] = { 0, 0b0110000110000110, 0b0110001110001110, 0b0110011110011110, 0b0110111110111110, 0b0111111111111110, 0b0111111111111110, 0b0111111111111110, 0b0111111111111110, 0b0110111110111110, 0b0110011110011110, 0b0110001110001110, 0b0110000110000110, 0 }; static uInt32 REWIND_1[BUTTON_H] = { 0, 0b0000001100011100, 0b0000011100011100, 0b0000111100011100, 0b0001111100011100, 0b0011111100011100, 0b0111111100011100, 0b0111111100011100, 0b0011111100011100, 0b0001111100011100, 0b0000111100011100, 0b0000011100011100, 0b0000001100011100, 0 }; static uInt32 UNWIND_1[BUTTON_H] = { 0, 0b0011100011000000, 0b0011100011100000, 0b0011100011110000, 0b0011100011111000, 0b0011100011111100, 0b0011100011111110, 0b0011100011111110, 0b0011100011111100, 0b0011100011111000, 0b0011100011110000, 0b0011100011100000, 0b0011100011000000, 0 }; static uInt32 UNWIND_ALL[BUTTON_H] = { 0, 0b0110000110000110, 0b0111000111000110, 0b0111100111100110, 0b0111110111110110, 0b0111111111111110, 0b0111111111111110, 0b0111111111111110, 0b0111111111111110, 0b0111110111110110, 0b0111100111100110, 0b0111000111000110, 0b0110000110000110, 0 }; const GUI::Font& font = instance().frameBuffer().font(); const int H_BORDER = 6, BUTTON_GAP = 4, V_BORDER = 4; const int buttonWidth = BUTTON_W + 8, buttonHeight = BUTTON_H + 10, rowHeight = font.getLineHeight(); int xpos, ypos; // Set real dimensions _w = width; // Parent determines our width (based on window size) _h = V_BORDER * 2 + rowHeight + buttonHeight + 2; this->clearFlags(WIDGET_CLEARBG); // does only work combined with blending (0..100)! this->clearFlags(WIDGET_BORDER); xpos = H_BORDER; ypos = V_BORDER; // Add index info myCurrentIdxWidget = new StaticTextWidget(this, font, xpos, ypos, " ", TextAlign::Left, kBGColor); myCurrentIdxWidget->setTextColor(kColorInfo); myLastIdxWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("8888"), ypos, " ", TextAlign::Right, kBGColor); myLastIdxWidget->setTextColor(kColorInfo); // Add timeline const uInt32 tl_h = myCurrentIdxWidget->getHeight() / 2, tl_x = xpos + myCurrentIdxWidget->getWidth() + 8, tl_y = ypos + (myCurrentIdxWidget->getHeight() - tl_h) / 2 - 1, tl_w = myLastIdxWidget->getAbsX() - tl_x - 8; myTimeline = new TimeLineWidget(this, font, tl_x, tl_y, tl_w, tl_h, "", 0, kTimeline); myTimeline->setMinValue(0); ypos += rowHeight; // Add time info myCurrentTimeWidget = new StaticTextWidget(this, font, xpos, ypos + 3, "04:32 59", TextAlign::Left, kBGColor); myCurrentTimeWidget->setTextColor(kColorInfo); myLastTimeWidget = new StaticTextWidget(this, font, _w - H_BORDER - font.getStringWidth("XX:XX XX"), ypos + 3, "12:25 59", TextAlign::Right, kBGColor); myLastTimeWidget->setTextColor(kColorInfo); xpos = myCurrentTimeWidget->getRight() + BUTTON_GAP * 4; // Add buttons myRewindAllWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, REWIND_ALL, BUTTON_W, BUTTON_H, kRewindAll); xpos += buttonWidth + BUTTON_GAP; myRewind1Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, REWIND_1, BUTTON_W, BUTTON_H, kRewind1); xpos += buttonWidth + BUTTON_GAP*2; myPlayWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, PLAY, BUTTON_W, BUTTON_H, kPlay); xpos += buttonWidth + BUTTON_GAP*2; myUnwind1Widget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_1, BUTTON_W, BUTTON_H, kUnwind1); xpos += buttonWidth + BUTTON_GAP; myUnwindAllWidget = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight, UNWIND_ALL, BUTTON_W, BUTTON_H, kUnwindAll); xpos = myUnwindAllWidget->getRight() + BUTTON_GAP * 3; // Add message myMessageWidget = new StaticTextWidget(this, font, xpos, ypos + 3, " ", TextAlign::Left, kBGColor); myMessageWidget->setTextColor(kColorInfo); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeMachineDialog::center() { // Place on the bottom of the screen, centered horizontally const GUI::Size& screen = instance().frameBuffer().screenSize(); const GUI::Rect& dst = surface().dstRect(); surface().setDstPos((screen.w - dst.width()) >> 1, screen.h - dst.height() - 10); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeMachineDialog::loadConfig() { RewindManager& r = instance().state().rewindManager(); IntArray cycles = r.cyclesList(); // Set range and intervals for timeline uInt32 maxValue = cycles.size() > 1 ? uInt32(cycles.size() - 1) : 0; myTimeline->setMaxValue(maxValue); myTimeline->setStepValues(cycles); // Enable blending (only once is necessary) if(!surface().attributes().blending) { surface().attributes().blending = true; surface().attributes().blendalpha = 92; surface().applyAttributes(); } handleWinds(); myMessageWidget->setLabel(""); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeMachineDialog::handleKeyDown(StellaKey key, StellaMod mod) { // The following 'Alt' shortcuts duplicate the shortcuts in EventHandler // It is best to keep them the same, so changes in EventHandler mean we // need to update the logic here too if(StellaModTest::isAlt(mod)) { switch(key) { case KBDK_LEFT: // Alt-left(-shift) rewinds 1(10) states handleCommand(nullptr, StellaModTest::isShift(mod) ? kRewind10 : kRewind1, 0, 0); break; case KBDK_RIGHT: // Alt-right(-shift) unwinds 1(10) states handleCommand(nullptr, StellaModTest::isShift(mod) ? kUnwind10 : kUnwind1, 0, 0); break; case KBDK_DOWN: // Alt-down rewinds to start of list handleCommand(nullptr, kRewindAll, 0, 0); break; case KBDK_UP: // Alt-up rewinds to end of list handleCommand(nullptr, kUnwindAll, 0, 0); break; default: Dialog::handleKeyDown(key, mod); } } else if(key == KBDK_SPACE || key == KBDK_ESCAPE) handleCommand(nullptr, kPlay, 0, 0); else Dialog::handleKeyDown(key, mod); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeMachineDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kTimeline: { Int32 winds = myTimeline->getValue() - instance().state().rewindManager().getCurrentIdx() + 1; handleWinds(winds); break; } case kPlay: instance().eventHandler().leaveMenuMode(); break; case kRewind1: handleWinds(-1); break; case kRewind10: handleWinds(-10); break; case kRewindAll: handleWinds(-1000); break; case kUnwind1: handleWinds(1); break; case kUnwind10: handleWinds(10); break; case kUnwindAll: handleWinds(1000); break; default: Dialog::handleCommand(sender, cmd, data, 0); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string TimeMachineDialog::getTimeString(uInt64 cycles) { const Int32 scanlines = std::max(instance().console().tia().scanlinesLastFrame(), 240u); const bool isNTSC = scanlines <= 287; const Int32 NTSC_FREQ = 1193182; // ~76*262*60 const Int32 PAL_FREQ = 1182298; // ~76*312*50 const Int32 freq = isNTSC ? NTSC_FREQ : PAL_FREQ; // = cycles/second uInt32 minutes = uInt32(cycles / (freq * 60)); cycles -= minutes * (freq * 60); uInt32 seconds = uInt32(cycles / freq); cycles -= seconds * freq; uInt32 frames = uInt32(cycles / (scanlines * 76)); ostringstream time; time << Common::Base::toString(minutes, Common::Base::F_10_2) << ":"; time << Common::Base::toString(seconds, Common::Base::F_10_2) << "."; time << Common::Base::toString(frames, Common::Base::F_10_2); return time.str(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void TimeMachineDialog::handleWinds(Int32 numWinds) { RewindManager& r = instance().state().rewindManager(); if(numWinds) { uInt64 startCycles = instance().console().tia().cycles(); if(numWinds < 0) r.rewindStates(-numWinds); else if(numWinds > 0) r.unwindStates(numWinds); uInt64 elapsed = instance().console().tia().cycles() - startCycles; if(elapsed > 0) { string message = r.getUnitString(elapsed); // TODO: add message text from addState() myMessageWidget->setLabel((numWinds < 0 ? "(-" : "(+") + message + ")"); } } // Update time myCurrentTimeWidget->setLabel(getTimeString(r.getCurrentCycles() - r.getFirstCycles())); myLastTimeWidget->setLabel(getTimeString(r.getLastCycles() - r.getFirstCycles())); myTimeline->setValue(r.getCurrentIdx()-1); // Update index myCurrentIdxWidget->setValue(r.getCurrentIdx()); myLastIdxWidget->setValue(r.getLastIdx()); // Enable/disable buttons myRewindAllWidget->setEnabled(!r.atFirst()); myRewind1Widget->setEnabled(!r.atFirst()); myUnwindAllWidget->setEnabled(!r.atLast()); myUnwind1Widget->setEnabled(!r.atLast()); } stella-5.1.1/src/gui/TimeMachineDialog.hxx000066400000000000000000000047471324334165500204330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef TIME_MACHINE_DIALOG_HXX #define TIME_MACHINE_DIALOG_HXX class CommandSender; class DialogContainer; class OSystem; class TimeLineWidget; #include "Dialog.hxx" class TimeMachineDialog : public Dialog { public: TimeMachineDialog(OSystem& osystem, DialogContainer& parent, int width); virtual ~TimeMachineDialog() = default; private: void loadConfig() override; void handleKeyDown(StellaKey key, StellaMod mod) override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; /** This dialog uses its own positioning, so we override Dialog::center() */ void center() override; /** convert cycles into time */ string getTimeString(uInt64 cycles); /** re/unwind and update display */ void handleWinds(Int32 numWinds = 0); private: enum { kTimeline = 'TMtl', kPlay = 'TMpl', kRewindAll = 'TMra', kRewind10 = 'TMr1', kRewind1 = 'TMre', kUnwindAll = 'TMua', kUnwind10 = 'TMu1', kUnwind1 = 'TMun', }; TimeLineWidget* myTimeline; ButtonWidget* myPlayWidget; ButtonWidget* myRewindAllWidget; ButtonWidget* myRewind1Widget; ButtonWidget* myUnwind1Widget; ButtonWidget* myUnwindAllWidget; StaticTextWidget* myCurrentTimeWidget; StaticTextWidget* myLastTimeWidget; StaticTextWidget* myCurrentIdxWidget; StaticTextWidget* myLastIdxWidget; StaticTextWidget* myMessageWidget; private: // Following constructors and assignment operators not supported TimeMachineDialog() = delete; TimeMachineDialog(const TimeMachineDialog&) = delete; TimeMachineDialog(TimeMachineDialog&&) = delete; TimeMachineDialog& operator=(const TimeMachineDialog&) = delete; TimeMachineDialog& operator=(TimeMachineDialog&&) = delete; }; #endif stella-5.1.1/src/gui/UIDialog.cxx000066400000000000000000000300671324334165500165520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Dialog.hxx" #include "OSystem.hxx" #include "FrameBuffer.hxx" #include "FBSurface.hxx" #include "ListWidget.hxx" #include "PopUpWidget.hxx" #include "ScrollBarWidget.hxx" #include "Settings.hxx" #include "TabWidget.hxx" #include "Widget.hxx" #include "Font.hxx" #ifdef DEBUGGER_SUPPORT #include "DebuggerDialog.hxx" #endif #include "UIDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - UIDialog::UIDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font) : Dialog(osystem, parent) { const GUI::Font& ifont = instance().frameBuffer().infoFont(); const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; const int vBorder = 5; int xpos, ypos, tabID; int lwidth, pwidth = font.getStringWidth("Standard"); WidgetArray wid; VariantList items; ButtonWidget* b; const GUI::Size& ds = instance().frameBuffer().desktopSize(); // Set real dimensions _w = 37 * fontWidth + 10; _h = 11 * (lineHeight + 4) + 10; // The tab widget xpos = ypos = vBorder; myTab = new TabWidget(this, font, xpos, ypos, _w - 2*xpos, _h - buttonHeight - 20); addTabWidget(myTab); ////////////////////////////////////////////////////////// // 1) Launcher options tabID = myTab->addTab(" Launcher "); lwidth = font.getStringWidth("Exit to Launcher "); // Launcher width and height myLauncherWidthSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Launcher Width ", lwidth, kLWidthChanged); myLauncherWidthSlider->setMinValue(FrameBuffer::kFBMinW); myLauncherWidthSlider->setMaxValue(ds.w); myLauncherWidthSlider->setStepValue(10); wid.push_back(myLauncherWidthSlider); myLauncherWidthLabel = new StaticTextWidget(myTab, font, xpos + myLauncherWidthSlider->getWidth() + 4, ypos + 1, 4*fontWidth, fontHeight, "", TextAlign::Left); ypos += lineHeight + 4; myLauncherHeightSlider = new SliderWidget(myTab, font, xpos, ypos, pwidth, lineHeight, "Launcher Height ", lwidth, kLHeightChanged); myLauncherHeightSlider->setMinValue(FrameBuffer::kFBMinH); myLauncherHeightSlider->setMaxValue(ds.h); myLauncherHeightSlider->setStepValue(10); wid.push_back(myLauncherHeightSlider); myLauncherHeightLabel = new StaticTextWidget(myTab, font, xpos + myLauncherHeightSlider->getWidth() + 4, ypos + 1, 4*fontWidth, fontHeight, "", TextAlign::Left); ypos += lineHeight + 4; // Launcher font pwidth = font.getStringWidth("2x (1000x760)"); items.clear(); VarList::push_back(items, "Small", "small"); VarList::push_back(items, "Medium", "medium"); VarList::push_back(items, "Large", "large"); myLauncherFontPopup = new PopUpWidget(myTab, font, xpos, ypos+1, pwidth, lineHeight, items, "Launcher Font ", lwidth); wid.push_back(myLauncherFontPopup); ypos += lineHeight + 4; // ROM launcher info/snapshot viewer items.clear(); VarList::push_back(items, "Off", "0"); VarList::push_back(items, "1x (640x480) ", "1"); VarList::push_back(items, "2x (1000x760)", "2"); myRomViewerPopup = new PopUpWidget(myTab, font, xpos, ypos+1, pwidth, lineHeight, items, "ROM Info viewer ", lwidth); wid.push_back(myRomViewerPopup); ypos += lineHeight + 4; // Exit to Launcher pwidth = font.getStringWidth("If in use"); items.clear(); VarList::push_back(items, "If in use", "0"); VarList::push_back(items, "Always", "1"); myLauncherExitPopup = new PopUpWidget(myTab, font, xpos, ypos+1, pwidth, lineHeight, items, "Exit to Launcher ", lwidth); wid.push_back(myLauncherExitPopup); ypos += lineHeight + 4; // Add message concerning usage xpos = vBorder; ypos += 1*(lineHeight + 4); lwidth = ifont.getStringWidth("(*) Changes require application restart"); new StaticTextWidget(myTab, ifont, xpos, ypos, std::min(lwidth, _w-20), fontHeight, "(*) Changes require application restart", TextAlign::Left); // Add items for tab 0 addToFocusList(wid, myTab, tabID); ////////////////////////////////////////////////////////// // 3) Misc. options wid.clear(); tabID = myTab->addTab(" Misc. "); lwidth = font.getStringWidth("Interface Palette (*) "); pwidth = font.getStringWidth("Standard"); xpos = ypos = vBorder; // UI Palette ypos += 1; items.clear(); VarList::push_back(items, "Standard", "standard"); VarList::push_back(items, "Classic", "classic"); VarList::push_back(items, "Light", "light"); myPalettePopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Interface Palette (*) ", lwidth); wid.push_back(myPalettePopup); ypos += lineHeight + 4; // Delay between quick-selecting characters in ListWidget items.clear(); VarList::push_back(items, "Disabled", "0"); VarList::push_back(items, "300 ms", "300"); VarList::push_back(items, "400 ms", "400"); VarList::push_back(items, "500 ms", "500"); VarList::push_back(items, "600 ms", "600"); VarList::push_back(items, "700 ms", "700"); VarList::push_back(items, "800 ms", "800"); VarList::push_back(items, "900 ms", "900"); VarList::push_back(items, "1 second", "1000"); myListDelayPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "List quick delay ", lwidth); wid.push_back(myListDelayPopup); ypos += lineHeight + 4; // Number of lines a mouse wheel will scroll items.clear(); VarList::push_back(items, "1 line", "1"); VarList::push_back(items, "2 lines", "2"); VarList::push_back(items, "3 lines", "3"); VarList::push_back(items, "4 lines", "4"); VarList::push_back(items, "5 lines", "5"); VarList::push_back(items, "6 lines", "6"); VarList::push_back(items, "7 lines", "7"); VarList::push_back(items, "8 lines", "8"); VarList::push_back(items, "9 lines", "9"); VarList::push_back(items, "10 lines", "10"); myWheelLinesPopup = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Mouse wheel scroll ", lwidth); wid.push_back(myWheelLinesPopup); ypos += lineHeight + 4; // Add message concerning usage xpos = vBorder; ypos += 1*(lineHeight + 4); lwidth = ifont.getStringWidth("(*) Requires application restart"); new StaticTextWidget(myTab, ifont, xpos, ypos, std::min(lwidth, _w-20), fontHeight, "(*) Requires application restart", TextAlign::Left); // Add items for tab 2 addToFocusList(wid, myTab, tabID); // Activate the first tab myTab->setActiveTab(0); // Add Defaults, OK and Cancel buttons wid.clear(); b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UIDialog::loadConfig() { // Launcher size const GUI::Size& ls = instance().settings().getSize("launcherres"); uInt32 w = ls.w, h = ls.h; w = std::max(w, uInt32(FrameBuffer::kFBMinW)); h = std::max(h, uInt32(FrameBuffer::kFBMinH)); w = std::min(w, instance().frameBuffer().desktopSize().w); h = std::min(h, instance().frameBuffer().desktopSize().h); myLauncherWidthSlider->setValue(w); myLauncherWidthLabel->setValue(w); myLauncherHeightSlider->setValue(h); myLauncherHeightLabel->setValue(h); // Launcher font const string& font = instance().settings().getString("launcherfont"); myLauncherFontPopup->setSelected(font, "medium"); // ROM launcher info viewer const string& viewer = instance().settings().getString("romviewer"); myRomViewerPopup->setSelected(viewer, "0"); // Exit to launcher bool exitlauncher = instance().settings().getBool("exitlauncher"); myLauncherExitPopup->setSelected(exitlauncher ? "1" : "0", "0"); // UI palette const string& pal = instance().settings().getString("uipalette"); myPalettePopup->setSelected(pal, "standard"); // Listwidget quick delay const string& delay = instance().settings().getString("listdelay"); myListDelayPopup->setSelected(delay, "300"); // Mouse wheel lines const string& mw = instance().settings().getString("mwheel"); myWheelLinesPopup->setSelected(mw, "1"); myTab->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UIDialog::saveConfig() { // Launcher size instance().settings().setValue("launcherres", GUI::Size(myLauncherWidthSlider->getValue(), myLauncherHeightSlider->getValue())); // Launcher font instance().settings().setValue("launcherfont", myLauncherFontPopup->getSelectedTag().toString()); // ROM launcher info viewer instance().settings().setValue("romviewer", myRomViewerPopup->getSelectedTag().toString()); // Exit to Launcher instance().settings().setValue("exitlauncher", myLauncherExitPopup->getSelectedTag().toString()); // UI palette instance().settings().setValue("uipalette", myPalettePopup->getSelectedTag().toString()); // Listwidget quick delay instance().settings().setValue("listdelay", myListDelayPopup->getSelectedTag().toString()); ListWidget::setQuickSelectDelay(myListDelayPopup->getSelectedTag().toInt()); // Mouse wheel lines instance().settings().setValue("mwheel", myWheelLinesPopup->getSelectedTag().toString()); ScrollBarWidget::setWheelLines(myWheelLinesPopup->getSelectedTag().toInt()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UIDialog::setDefaults() { switch(myTab->getActiveTab()) { case 0: // Launcher options { uInt32 w = std::min(instance().frameBuffer().desktopSize().w, 900u); uInt32 h = std::min(instance().frameBuffer().desktopSize().h, 600u); myLauncherWidthSlider->setValue(w); myLauncherWidthLabel->setValue(w); myLauncherHeightSlider->setValue(h); myLauncherHeightLabel->setValue(h); myLauncherFontPopup->setSelected("medium", ""); myRomViewerPopup->setSelected("1", ""); myLauncherExitPopup->setSelected("0", ""); break; } case 1: // Misc. options myPalettePopup->setSelected("standard"); myListDelayPopup->setSelected("300"); myWheelLinesPopup->setSelected("4"); break; default: break; } _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void UIDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case kLWidthChanged: myLauncherWidthLabel->setValue(myLauncherWidthSlider->getValue()); break; case kLHeightChanged: myLauncherHeightLabel->setValue(myLauncherHeightSlider->getValue()); break; case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/gui/UIDialog.hxx000066400000000000000000000041671324334165500165610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef UI_DIALOG_HXX #define UI_DIALOG_HXX class CommandSender; class Dialog; class DialogContainer; class CheckboxWidget; class PopUpWidget; class SliderWidget; class StaticTextWidget; class TabWidget; class OSystem; #include "bspf.hxx" class UIDialog : public Dialog { public: UIDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font); virtual ~UIDialog() = default; private: void loadConfig() override; void saveConfig() override; void setDefaults() override; void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: TabWidget* myTab; // Launcher options SliderWidget* myLauncherWidthSlider; StaticTextWidget* myLauncherWidthLabel; SliderWidget* myLauncherHeightSlider; StaticTextWidget* myLauncherHeightLabel; PopUpWidget* myLauncherExitPopup; PopUpWidget* myLauncherFontPopup; PopUpWidget* myRomViewerPopup; // Misc options PopUpWidget* myPalettePopup; PopUpWidget* myListDelayPopup; PopUpWidget* myWheelLinesPopup; enum { kLWidthChanged = 'UIlw', kLHeightChanged = 'UIlh', }; private: // Following constructors and assignment operators not supported UIDialog() = delete; UIDialog(const UIDialog&) = delete; UIDialog(UIDialog&&) = delete; UIDialog& operator=(const UIDialog&) = delete; UIDialog& operator=(UIDialog&&) = delete; }; #endif stella-5.1.1/src/gui/VideoDialog.cxx000066400000000000000000000604631324334165500173060ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "Control.hxx" #include "Dialog.hxx" #include "Menu.hxx" #include "OSystem.hxx" #include "EditTextWidget.hxx" #include "PopUpWidget.hxx" #include "Console.hxx" #include "TIA.hxx" #include "Settings.hxx" #include "Widget.hxx" #include "Font.hxx" #include "TabWidget.hxx" #include "NTSCFilter.hxx" #include "TIASurface.hxx" #include "VideoDialog.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - VideoDialog::VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h) : Dialog(osystem, parent) { const int VGAP = 4; const int VBORDER = 8; const int HBORDER = 8; const int lineHeight = font.getLineHeight(), fontWidth = font.getMaxCharWidth(), fontHeight = font.getFontHeight(), buttonWidth = font.getStringWidth("Defaults") + 20, buttonHeight = font.getLineHeight() + 4; int xpos, ypos, tabID; int lwidth = font.getStringWidth("NTSC Aspect "), pwidth = font.getStringWidth("XXXXxXXXX"), swidth = 69; WidgetArray wid; VariantList items; // Set real dimensions _w = std::min(52 * fontWidth + 10, max_w); _h = std::min(16 * (lineHeight + VGAP) + 14, max_h); // The tab widget xpos = 2; ypos = 4; myTab = new TabWidget(this, font, xpos, ypos, _w - 2*xpos, _h - buttonHeight - 20); addTabWidget(myTab); xpos = HBORDER; ypos = VBORDER; ////////////////////////////////////////////////////////// // 1) General options tabID = myTab->addTab(" General "); // Video renderer myRenderer = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, instance().frameBuffer().supportedRenderers(), "Renderer ", lwidth); wid.push_back(myRenderer); ypos += lineHeight + VGAP; // TIA filters (will be dynamically filled later) myTIAZoom = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "TIA Zoom ", lwidth); wid.push_back(myTIAZoom); ypos += lineHeight + VGAP; // TIA Palette items.clear(); VarList::push_back(items, "Standard", "standard"); VarList::push_back(items, "Z26", "z26"); VarList::push_back(items, "User", "user"); myTIAPalette = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "TIA Palette ", lwidth); wid.push_back(myTIAPalette); ypos += lineHeight + VGAP; // TIA interpolation items.clear(); VarList::push_back(items, "Linear", "linear"); VarList::push_back(items, "Nearest", "nearest"); myTIAInterpolate = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "TIA Inter ", lwidth); wid.push_back(myTIAInterpolate); ypos += lineHeight + VGAP; // Timing to use between frames items.clear(); VarList::push_back(items, "Sleep", "sleep"); VarList::push_back(items, "Busy-wait", "busy"); myFrameTiming = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "Timing (*) ", lwidth); wid.push_back(myFrameTiming); ypos += lineHeight + VGAP; // Aspect ratio (NTSC mode) myNAspectRatio = new SliderWidget(myTab, font, xpos, ypos-1, pwidth, lineHeight, "NTSC Aspect ", lwidth, kNAspectRatioChanged); myNAspectRatio->setMinValue(80); myNAspectRatio->setMaxValue(120); wid.push_back(myNAspectRatio); myNAspectRatioLabel = new StaticTextWidget(myTab, font, xpos + myNAspectRatio->getWidth() + 4, ypos + 1, fontWidth * 3, fontHeight, "", TextAlign::Left); ypos += lineHeight + VGAP; // Aspect ratio (PAL mode) myPAspectRatio = new SliderWidget(myTab, font, xpos, ypos-1, pwidth, lineHeight, "PAL Aspect ", lwidth, kPAspectRatioChanged); myPAspectRatio->setMinValue(80); myPAspectRatio->setMaxValue(120); wid.push_back(myPAspectRatio); myPAspectRatioLabel = new StaticTextWidget(myTab, font, xpos + myPAspectRatio->getWidth() + 4, ypos + 1, fontWidth * 3, fontHeight, "", TextAlign::Left); ypos += lineHeight + VGAP; // Framerate myFrameRate = new SliderWidget(myTab, font, xpos, ypos-1, pwidth, lineHeight, "Framerate ", lwidth, kFrameRateChanged); myFrameRate->setMinValue(0); myFrameRate->setMaxValue(900); myFrameRate->setStepValue(10); wid.push_back(myFrameRate); myFrameRateLabel = new StaticTextWidget(myTab, font, xpos + myFrameRate->getWidth() + 4, ypos + 1, fontWidth * 4, fontHeight, "", TextAlign::Left); // Add message concerning usage const GUI::Font& infofont = instance().frameBuffer().infoFont(); ypos = myTab->getHeight() - 5 - fontHeight - infofont.getFontHeight() - 10; new StaticTextWidget(myTab, infofont, 10, ypos, font.getStringWidth("(*) Requires application restart"), fontHeight, "(*) Requires application restart", TextAlign::Left); // Move over to the next column xpos += myNAspectRatio->getWidth() + myNAspectRatioLabel->getWidth() + 30; ypos = VBORDER; // Fullscreen myFullscreen = new CheckboxWidget(myTab, font, xpos, ypos, "Fullscreen"); wid.push_back(myFullscreen); ypos += lineHeight + VGAP; // FS stretch myUseStretch = new CheckboxWidget(myTab, font, xpos, ypos, "Fullscreen Fill"); wid.push_back(myUseStretch); ypos += lineHeight + VGAP; // Use sync to vblank myUseVSync = new CheckboxWidget(myTab, font, xpos, ypos, "VSync"); wid.push_back(myUseVSync); ypos += (lineHeight + VGAP) * 2; // Skip progress load bars for SuperCharger ROMs // Doesn't really belong here, but I couldn't find a better place for it myFastSCBios = new CheckboxWidget(myTab, font, xpos, ypos, "Fast SC/AR BIOS"); wid.push_back(myFastSCBios); ypos += lineHeight + VGAP; // Show UI messages onscreen myUIMessages = new CheckboxWidget(myTab, font, xpos, ypos, "Show UI messages"); wid.push_back(myUIMessages); ypos += lineHeight + VGAP; // Center window (in windowed mode) myCenter = new CheckboxWidget(myTab, font, xpos, ypos, "Center window"); wid.push_back(myCenter); ypos += lineHeight + VGAP; // Use multi-threading myUseThreads = new CheckboxWidget(myTab, font, xpos, ypos, "Use multi-threading"); wid.push_back(myUseThreads); // Add items for tab 0 addToFocusList(wid, myTab, tabID); ////////////////////////////////////////////////////////// // 2) TV effects options wid.clear(); tabID = myTab->addTab(" TV Effects "); xpos = HBORDER; ypos = VBORDER; // TV Mode items.clear(); VarList::push_back(items, "Disabled", NTSCFilter::PRESET_OFF); VarList::push_back(items, "Composite", NTSCFilter::PRESET_COMPOSITE); VarList::push_back(items, "S-Video", NTSCFilter::PRESET_SVIDEO); VarList::push_back(items, "RGB", NTSCFilter::PRESET_RGB); VarList::push_back(items, "Bad adjust", NTSCFilter::PRESET_BAD); VarList::push_back(items, "Custom", NTSCFilter::PRESET_CUSTOM); lwidth = font.getStringWidth("TV Mode "); pwidth = font.getStringWidth("Bad adjust"); myTVMode = new PopUpWidget(myTab, font, xpos, ypos, pwidth, lineHeight, items, "TV Mode ", lwidth, kTVModeChanged); wid.push_back(myTVMode); ypos += lineHeight + VGAP; // Custom adjustables (using macro voodoo) xpos += 8+1; ypos += 0; pwidth = lwidth; lwidth = font.getStringWidth("Saturation "); #define CREATE_CUSTOM_SLIDERS(obj, desc) \ myTV ## obj = \ new SliderWidget(myTab, font, xpos, ypos-1, pwidth, lineHeight, \ desc, lwidth, kTV ## obj ##Changed); \ myTV ## obj->setMinValue(0); myTV ## obj->setMaxValue(100); \ wid.push_back(myTV ## obj); \ myTV ## obj ## Label = \ new StaticTextWidget(myTab, font, xpos+myTV ## obj->getWidth()+4, \ ypos+1, fontWidth*3, fontHeight, "", TextAlign::Left);\ ypos += lineHeight + VGAP; pwidth = swidth; CREATE_CUSTOM_SLIDERS(Contrast, "Contrast "); CREATE_CUSTOM_SLIDERS(Bright, "Brightness "); CREATE_CUSTOM_SLIDERS(Hue, "Hue "); CREATE_CUSTOM_SLIDERS(Satur, "Saturation "); CREATE_CUSTOM_SLIDERS(Gamma, "Gamma "); CREATE_CUSTOM_SLIDERS(Sharp, "Sharpness "); CREATE_CUSTOM_SLIDERS(Res, "Resolution "); CREATE_CUSTOM_SLIDERS(Artifacts, "Artifacts "); CREATE_CUSTOM_SLIDERS(Fringe, "Fringing "); CREATE_CUSTOM_SLIDERS(Bleed, "Bleeding "); xpos += myTVContrast->getWidth() + myTVContrastLabel->getWidth() + 36; ypos = VBORDER; lwidth = font.getStringWidth("Intensity "); pwidth = font.getMaxCharWidth() * 6; // TV Phosphor effect items.clear(); VarList::push_back(items, "Always", "always"); VarList::push_back(items, "Per-ROM", "byrom"); myTVPhosphor = new PopUpWidget(myTab, font, xpos, ypos, font.getStringWidth("Per-ROM"), lineHeight, items, "TV Phosphor ", font.getStringWidth("TV Phosphor ")); ypos += lineHeight + VGAP; // TV Phosphor default level xpos += 8-8+16; pwidth = swidth; CREATE_CUSTOM_SLIDERS(PhosLevel, "Default "); ypos += 6; // Scanline intensity and interpolation xpos -= 8+8; myTVScanLabel = new StaticTextWidget(myTab, font, xpos, ypos, font.getStringWidth("Scanline settings"), fontHeight, "Scanline settings", TextAlign::Left); ypos += lineHeight; xpos += 8+8; CREATE_CUSTOM_SLIDERS(ScanIntense, "Intensity "); myTVScanInterpolate = new CheckboxWidget(myTab, font, xpos, ypos, "Interpolation"); wid.push_back(myTVScanInterpolate); ypos += lineHeight + 6; // Adjustable presets xpos -= 8+8; int cloneWidth = font.getStringWidth("Clone Bad Adjust") + 20; #define CREATE_CLONE_BUTTON(obj, desc) \ myClone ## obj = \ new ButtonWidget(myTab, font, xpos, ypos, cloneWidth, buttonHeight,\ desc, kClone ## obj ##Cmd); \ wid.push_back(myClone ## obj); \ ypos += lineHeight + 4 + VGAP ypos += VGAP; CREATE_CLONE_BUTTON(Composite, "Clone Composite"); CREATE_CLONE_BUTTON(Svideo, "Clone S-Video"); CREATE_CLONE_BUTTON(RGB, "Clone RGB"); CREATE_CLONE_BUTTON(Bad, "Clone Bad Adjust"); CREATE_CLONE_BUTTON(Custom, "Revert"); // Add items for tab 2 addToFocusList(wid, myTab, tabID); // Activate the first tab myTab->setActiveTab(0); // Add Defaults, OK and Cancel buttons wid.clear(); ButtonWidget* b; b = new ButtonWidget(this, font, 10, _h - buttonHeight - 10, buttonWidth, buttonHeight, "Defaults", GuiObject::kDefaultsCmd); wid.push_back(b); addOKCancelBGroup(wid, font); addBGroupToFocusList(wid); // Disable certain functions when we know they aren't present #ifndef WINDOWED_SUPPORT myFullscreen->clearFlags(WIDGET_ENABLED); myCenter->clearFlags(WIDGET_ENABLED); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::loadConfig() { // Renderer settings myRenderer->setSelected(instance().settings().getString("video"), "default"); // TIA Filter // These are dynamically loaded, since they depend on the size of // the desktop and which renderer we're using const VariantList& items = instance().frameBuffer().supportedTIAZoomLevels(); myTIAZoom->addItems(items); myTIAZoom->setSelected(instance().settings().getString("tia.zoom"), "3"); // TIA Palette myTIAPalette->setSelected( instance().settings().getString("palette"), "standard"); // TIA interpolation const string& tia_inter = instance().settings().getBool("tia.inter") ? "linear" : "nearest"; myTIAInterpolate->setSelected(tia_inter, "nearest"); // Wait between frames myFrameTiming->setSelected( instance().settings().getString("timing"), "sleep"); // Aspect ratio setting (NTSC and PAL) myNAspectRatio->setValue(instance().settings().getInt("tia.aspectn")); myNAspectRatioLabel->setLabel(instance().settings().getString("tia.aspectn")); myPAspectRatio->setValue(instance().settings().getInt("tia.aspectp")); myPAspectRatioLabel->setLabel(instance().settings().getString("tia.aspectp")); // Framerate (0 or -1 means automatic framerate calculation) int rate = instance().settings().getInt("framerate"); myFrameRate->setValue(rate < 0 ? 0 : rate); myFrameRateLabel->setLabel(rate <= 0 ? "Auto" : instance().settings().getString("framerate")); // Fullscreen myFullscreen->setState(instance().settings().getBool("fullscreen")); // Fullscreen stretch setting myUseStretch->setState(instance().settings().getBool("tia.fsfill")); // Use sync to vertical blank myUseVSync->setState(instance().settings().getBool("vsync")); // Show UI messages myUIMessages->setState(instance().settings().getBool("uimessages")); // Center window myCenter->setState(instance().settings().getBool("center")); // Fast loading of Supercharger BIOS myFastSCBios->setState(instance().settings().getBool("fastscbios")); // Multi-threaded rendering myUseThreads->setState(instance().settings().getBool("threads")); // TV Mode myTVMode->setSelected( instance().settings().getString("tv.filter"), "0"); int preset = instance().settings().getInt("tv.filter"); handleTVModeChange(NTSCFilter::Preset(preset)); // TV Custom adjustables loadTVAdjustables(NTSCFilter::PRESET_CUSTOM); // TV phosphor mode myTVPhosphor->setSelected( instance().settings().getString("tv.phosphor"), "byrom"); // TV phosphor blend myTVPhosLevel->setValue(instance().settings().getInt("tv.phosblend")); myTVPhosLevelLabel->setLabel(instance().settings().getString("tv.phosblend")); // TV scanline intensity and interpolation myTVScanIntense->setValue(instance().settings().getInt("tv.scanlines")); myTVScanIntenseLabel->setLabel(instance().settings().getString("tv.scanlines")); myTVScanInterpolate->setState(instance().settings().getBool("tv.scaninter")); myTab->loadConfig(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::saveConfig() { // Renderer setting instance().settings().setValue("video", myRenderer->getSelectedTag().toString()); // TIA Filter instance().settings().setValue("tia.zoom", myTIAZoom->getSelectedTag().toString()); // TIA Palette instance().settings().setValue("palette", myTIAPalette->getSelectedTag().toString()); // Wait between frames instance().settings().setValue("timing", myFrameTiming->getSelectedTag().toString()); // TIA interpolation instance().settings().setValue("tia.inter", myTIAInterpolate->getSelectedTag().toString() == "linear" ? true : false); // Aspect ratio setting (NTSC and PAL) instance().settings().setValue("tia.aspectn", myNAspectRatioLabel->getLabel()); instance().settings().setValue("tia.aspectp", myPAspectRatioLabel->getLabel()); // Framerate int f = myFrameRate->getValue(); instance().settings().setValue("framerate", f); if(instance().hasConsole()) { // Make sure auto-frame calculation is only enabled when necessary instance().console().tia().enableAutoFrame(f <= 0); instance().console().setFramerate(float(f)); } // Fullscreen instance().settings().setValue("fullscreen", myFullscreen->getState()); // Fullscreen stretch setting instance().settings().setValue("tia.fsfill", myUseStretch->getState()); // Use sync to vertical blank instance().settings().setValue("vsync", myUseVSync->getState()); // Show UI messages instance().settings().setValue("uimessages", myUIMessages->getState()); // Center window instance().settings().setValue("center", myCenter->getState()); // Fast loading of Supercharger BIOS instance().settings().setValue("fastscbios", myFastSCBios->getState()); // Multi-threaded rendering instance().settings().setValue("threads", myUseThreads->getState()); if(instance().hasConsole()) instance().frameBuffer().tiaSurface().ntsc().enableThreading(myUseThreads->getState()); // TV Mode instance().settings().setValue("tv.filter", myTVMode->getSelectedTag().toString()); // TV Custom adjustables NTSCFilter::Adjustable adj; adj.hue = myTVHue->getValue(); adj.saturation = myTVSatur->getValue(); adj.contrast = myTVContrast->getValue(); adj.brightness = myTVBright->getValue(); adj.sharpness = myTVSharp->getValue(); adj.gamma = myTVGamma->getValue(); adj.resolution = myTVRes->getValue(); adj.artifacts = myTVArtifacts->getValue(); adj.fringing = myTVFringe->getValue(); adj.bleed = myTVBleed->getValue(); instance().frameBuffer().tiaSurface().ntsc().setCustomAdjustables(adj); // TV phosphor mode instance().settings().setValue("tv.phosphor", myTVPhosphor->getSelectedTag().toString()); // TV phosphor blend instance().settings().setValue("tv.phosblend", myTVPhosLevelLabel->getLabel()); Properties::setDefault(Display_PPBlend, myTVPhosLevelLabel->getLabel()); // TV scanline intensity and interpolation instance().settings().setValue("tv.scanlines", myTVScanIntenseLabel->getLabel()); instance().settings().setValue("tv.scaninter", myTVScanInterpolate->getState()); // Finally, issue a complete framebuffer re-initialization instance().createFrameBuffer(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::setDefaults() { switch(myTab->getActiveTab()) { case 0: // General { myRenderer->setSelectedIndex(0); myTIAZoom->setSelected("3", ""); myTIAPalette->setSelected("standard", ""); myFrameTiming->setSelected("sleep", ""); myTIAInterpolate->setSelected("nearest", ""); myNAspectRatio->setValue(90); myNAspectRatioLabel->setLabel("91"); myPAspectRatio->setValue(100); myPAspectRatioLabel->setLabel("109"); myFrameRate->setValue(0); myFrameRateLabel->setLabel("Auto"); myFullscreen->setState(false); myUseStretch->setState(true); myUseVSync->setState(true); myUIMessages->setState(true); myCenter->setState(false); myFastSCBios->setState(true); myUseThreads->setState(false); break; } case 1: // TV effects { myTVMode->setSelected("0", "0"); // TV phosphor mode myTVPhosphor->setSelected("byrom", "byrom"); // TV phosphor blend myTVPhosLevel->setValue(50); myTVPhosLevelLabel->setLabel("50"); // TV scanline intensity and interpolation myTVScanIntense->setValue(25); myTVScanIntenseLabel->setLabel("25"); myTVScanInterpolate->setState(true); // Make sure that mutually-exclusive items are not enabled at the same time handleTVModeChange(NTSCFilter::PRESET_OFF); loadTVAdjustables(NTSCFilter::PRESET_CUSTOM); break; } } _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::handleTVModeChange(NTSCFilter::Preset preset) { bool enable = preset == NTSCFilter::PRESET_CUSTOM; bool scanenable = preset != NTSCFilter::PRESET_OFF; myTVSharp->setEnabled(enable); myTVSharpLabel->setEnabled(enable); myTVHue->setEnabled(enable); myTVHueLabel->setEnabled(enable); myTVRes->setEnabled(enable); myTVResLabel->setEnabled(enable); myTVArtifacts->setEnabled(enable); myTVArtifactsLabel->setEnabled(enable); myTVFringe->setEnabled(enable); myTVFringeLabel->setEnabled(enable); myTVBleed->setEnabled(enable); myTVBleedLabel->setEnabled(enable); myTVBright->setEnabled(enable); myTVBrightLabel->setEnabled(enable); myTVContrast->setEnabled(enable); myTVContrastLabel->setEnabled(enable); myTVSatur->setEnabled(enable); myTVSaturLabel->setEnabled(enable); myTVGamma->setEnabled(enable); myTVGammaLabel->setEnabled(enable); myCloneComposite->setEnabled(enable); myCloneSvideo->setEnabled(enable); myCloneRGB->setEnabled(enable); myCloneBad->setEnabled(enable); myCloneCustom->setEnabled(enable); myTVScanLabel->setEnabled(scanenable); myTVScanIntense->setEnabled(scanenable); myTVScanIntenseLabel->setEnabled(scanenable); myTVScanInterpolate->setEnabled(scanenable); _dirty = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::loadTVAdjustables(NTSCFilter::Preset preset) { NTSCFilter::Adjustable adj; instance().frameBuffer().tiaSurface().ntsc().getAdjustables( adj, NTSCFilter::Preset(preset)); myTVSharp->setValue(adj.sharpness); myTVSharpLabel->setValue(adj.sharpness); myTVHue->setValue(adj.hue); myTVHueLabel->setValue(adj.hue); myTVRes->setValue(adj.resolution); myTVResLabel->setValue(adj.resolution); myTVArtifacts->setValue(adj.artifacts); myTVArtifactsLabel->setValue(adj.artifacts); myTVFringe->setValue(adj.fringing); myTVFringeLabel->setValue(adj.fringing); myTVBleed->setValue(adj.bleed); myTVBleedLabel->setValue(adj.bleed); myTVBright->setValue(adj.brightness); myTVBrightLabel->setValue(adj.brightness); myTVContrast->setValue(adj.contrast); myTVContrastLabel->setValue(adj.contrast); myTVSatur->setValue(adj.saturation); myTVSaturLabel->setValue(adj.saturation); myTVGamma->setValue(adj.gamma); myTVGammaLabel->setValue(adj.gamma); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void VideoDialog::handleCommand(CommandSender* sender, int cmd, int data, int id) { switch(cmd) { case GuiObject::kOKCmd: saveConfig(); close(); break; case GuiObject::kDefaultsCmd: setDefaults(); break; case kNAspectRatioChanged: myNAspectRatioLabel->setValue(myNAspectRatio->getValue()); break; case kPAspectRatioChanged: myPAspectRatioLabel->setValue(myPAspectRatio->getValue()); break; case kFrameRateChanged: if(myFrameRate->getValue() == 0) myFrameRateLabel->setLabel("Auto"); else myFrameRateLabel->setValue(myFrameRate->getValue()); break; case kTVModeChanged: handleTVModeChange(NTSCFilter::Preset(myTVMode->getSelectedTag().toInt())); break; case kTVSharpChanged: myTVSharpLabel->setValue(myTVSharp->getValue()); break; case kTVHueChanged: myTVHueLabel->setValue(myTVHue->getValue()); break; case kTVResChanged: myTVResLabel->setValue(myTVRes->getValue()); break; case kTVArtifactsChanged: myTVArtifactsLabel->setValue(myTVArtifacts->getValue()); break; case kTVFringeChanged: myTVFringeLabel->setValue(myTVFringe->getValue()); break; case kTVBleedChanged: myTVBleedLabel->setValue(myTVBleed->getValue()); break; case kTVBrightChanged: myTVBrightLabel->setValue(myTVBright->getValue()); break; case kTVContrastChanged: myTVContrastLabel->setValue(myTVContrast->getValue()); break; case kTVSaturChanged: myTVSaturLabel->setValue(myTVSatur->getValue()); break; case kTVGammaChanged: myTVGammaLabel->setValue(myTVGamma->getValue()); break; case kTVPhosLevelChanged: myTVPhosLevelLabel->setValue(myTVPhosLevel->getValue()); break; case kTVScanIntenseChanged: myTVScanIntenseLabel->setValue(myTVScanIntense->getValue()); break; case kCloneCompositeCmd: loadTVAdjustables(NTSCFilter::PRESET_COMPOSITE); break; case kCloneSvideoCmd: loadTVAdjustables(NTSCFilter::PRESET_SVIDEO); break; case kCloneRGBCmd: loadTVAdjustables(NTSCFilter::PRESET_RGB); break; case kCloneBadCmd: loadTVAdjustables(NTSCFilter::PRESET_BAD); break; case kCloneCustomCmd: loadTVAdjustables(NTSCFilter::PRESET_CUSTOM); break; default: Dialog::handleCommand(sender, cmd, data, 0); break; } } stella-5.1.1/src/gui/VideoDialog.hxx000066400000000000000000000111361324334165500173040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef VIDEO_DIALOG_HXX #define VIDEO_DIALOG_HXX class CommandSender; class CheckboxWidget; class DialogContainer; class PopUpWidget; class SliderWidget; class StaticTextWidget; class TabWidget; class OSystem; #include "Dialog.hxx" #include "NTSCFilter.hxx" #include "bspf.hxx" class VideoDialog : public Dialog { public: VideoDialog(OSystem& osystem, DialogContainer& parent, const GUI::Font& font, int max_w, int max_h); virtual ~VideoDialog() = default; private: void loadConfig() override; void saveConfig() override; void setDefaults() override; void handleTVModeChange(NTSCFilter::Preset); void loadTVAdjustables(NTSCFilter::Preset preset); void handleCommand(CommandSender* sender, int cmd, int data, int id) override; private: TabWidget* myTab; // General options PopUpWidget* myRenderer; PopUpWidget* myTIAZoom; PopUpWidget* myTIAPalette; PopUpWidget* myFrameTiming; PopUpWidget* myTIAInterpolate; SliderWidget* myNAspectRatio; StaticTextWidget* myNAspectRatioLabel; SliderWidget* myPAspectRatio; StaticTextWidget* myPAspectRatioLabel; SliderWidget* myFrameRate; StaticTextWidget* myFrameRateLabel; CheckboxWidget* myFullscreen; CheckboxWidget* myUseStretch; CheckboxWidget* myUseVSync; CheckboxWidget* myUIMessages; CheckboxWidget* myCenter; CheckboxWidget* myFastSCBios; CheckboxWidget* myUseThreads; // TV effects adjustables (custom mode) PopUpWidget* myTVMode; SliderWidget* myTVSharp; StaticTextWidget* myTVSharpLabel; SliderWidget* myTVHue; StaticTextWidget* myTVHueLabel; SliderWidget* myTVRes; StaticTextWidget* myTVResLabel; SliderWidget* myTVArtifacts; StaticTextWidget* myTVArtifactsLabel; SliderWidget* myTVFringe; StaticTextWidget* myTVFringeLabel; SliderWidget* myTVBleed; StaticTextWidget* myTVBleedLabel; SliderWidget* myTVBright; StaticTextWidget* myTVBrightLabel; SliderWidget* myTVContrast; StaticTextWidget* myTVContrastLabel; SliderWidget* myTVSatur; StaticTextWidget* myTVSaturLabel; SliderWidget* myTVGamma; StaticTextWidget* myTVGammaLabel; // TV phosphor effect PopUpWidget* myTVPhosphor; SliderWidget* myTVPhosLevel; StaticTextWidget* myTVPhosLevelLabel; // TV scanline intensity and interpolation StaticTextWidget* myTVScanLabel; SliderWidget* myTVScanIntense; StaticTextWidget* myTVScanIntenseLabel; CheckboxWidget* myTVScanInterpolate; // TV effects adjustables presets (custom mode) ButtonWidget* myCloneComposite; ButtonWidget* myCloneSvideo; ButtonWidget* myCloneRGB; ButtonWidget* myCloneBad; ButtonWidget* myCloneCustom; enum { kNAspectRatioChanged = 'VDan', kPAspectRatioChanged = 'VDap', kFrameRateChanged = 'VDfr', kTVModeChanged = 'VDtv', kTVSharpChanged = 'TVsh', kTVHueChanged = 'TVhu', kTVResChanged = 'TVrs', kTVArtifactsChanged = 'TVar', kTVFringeChanged = 'TVfr', kTVBleedChanged = 'TVbl', kTVBrightChanged = 'TVbr', kTVContrastChanged = 'TVct', kTVSaturChanged = 'TVsa', kTVGammaChanged = 'TVga', kTVScanIntenseChanged= 'TVsc', kTVPhosLevelChanged = 'TVpl', kCloneCompositeCmd = 'CLcp', kCloneSvideoCmd = 'CLsv', kCloneRGBCmd = 'CLrb', kCloneBadCmd = 'CLbd', kCloneCustomCmd = 'CLcu' }; private: // Following constructors and assignment operators not supported VideoDialog() = delete; VideoDialog(const VideoDialog&) = delete; VideoDialog(VideoDialog&&) = delete; VideoDialog& operator=(const VideoDialog&) = delete; VideoDialog& operator=(VideoDialog&&) = delete; }; #endif stella-5.1.1/src/gui/Widget.cxx000066400000000000000000000537141324334165500163440ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #include "bspf.hxx" #include "Command.hxx" #include "Dialog.hxx" #include "Font.hxx" #include "FBSurface.hxx" #include "GuiObject.hxx" #include "OSystem.hxx" #include "Widget.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget::Widget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h) : GuiObject(boss->instance(), boss->parent(), boss->dialog(), x, y, w, h), _boss(boss), _font(font), _id(-1), _flags(0), _hasFocus(false), _bgcolor(kWidColor), _bgcolorhi(kWidColor), _textcolor(kTextColor), _textcolorhi(kTextColorHi) { // Insert into the widget list of the boss _next = _boss->_firstWidget; _boss->_firstWidget = this; _fontWidth = _font.getMaxCharWidth(); _fontHeight = _font.getLineHeight(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget::~Widget() { delete _next; _next = nullptr; _focusList.clear(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Widget::draw() { if(!_dirty || !isVisible() || !_boss->isVisible()) return; _dirty = false; FBSurface& s = _boss->dialog().surface(); bool hasBorder = _flags & WIDGET_BORDER; int oldX = _x, oldY = _y; // Account for our relative position in the dialog _x = getAbsX(); _y = getAbsY(); // Clear background (unless alpha blending is enabled) if(_flags & WIDGET_CLEARBG) { int x = _x, y = _y, w = _w, h = _h; if(hasBorder) { x++; y++; w-=2; h-=2; } #ifndef FLAT_UI s.fillRect(x, y, w, h, (_flags & WIDGET_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor); #else s.fillRect(x, y, w, h, (_flags & WIDGET_HILITED) && isEnabled() ? _bgcolorhi : _bgcolor); #endif } // Draw border if(hasBorder) { #ifndef FLAT_UI s.box(_x, _y, _w, _h, kColor, kShadowColor); #else s.frameRect(_x, _y, _w, _h, (_flags & WIDGET_HILITED) && isEnabled() ? kScrollColorHi : kColor); #endif // !FLAT_UI _x += 4; _y += 4; _w -= 8; _h -= 8; } // Now perform the actual widget draw drawWidget((_flags & WIDGET_HILITED) ? true : false); // Restore x/y if (hasBorder) { _x -= 4; _y -= 4; _w += 8; _h += 8; } _x = oldX; _y = oldY; // Draw all children Widget* w = _firstWidget; while(w) { w->draw(); w = w->_next; } // Tell the framebuffer this area is dirty s.setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Widget::receivedFocus() { if(_hasFocus) return; _hasFocus = true; receivedFocusWidget(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Widget::lostFocus() { if(!_hasFocus) return; _hasFocus = false; lostFocusWidget(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Widget::setEnabled(bool e) { if(e) setFlags(WIDGET_ENABLED); else clearFlags(WIDGET_ENABLED); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget* Widget::findWidgetInChain(Widget* w, int x, int y) { while(w) { // Stop as soon as we find a widget that contains the point (x,y) if(x >= w->_x && x < w->_x + w->_w && y >= w->_y && y < w->_y + w->_h) break; w = w->_next; } if(w) w = w->findWidget(x - w->_x, y - w->_y); return w; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Widget::isWidgetInChain(Widget* w, Widget* find) { while(w) { // Stop as soon as we find the widget if(w == find) return true; w = w->_next; } return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Widget::isWidgetInChain(WidgetArray& list, Widget* find) { for(const auto& w: list) if(w == find) return true; return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Widget* Widget::setFocusForChain(GuiObject* boss, WidgetArray& arr, Widget* wid, int direction, bool emitFocusEvents) { FBSurface& s = boss->dialog().surface(); int size = int(arr.size()), pos = -1; Widget* tmp; for(int i = 0; i < size; ++i) { tmp = arr[i]; // Determine position of widget 'w' if(wid == tmp) pos = i; // Get area around widget // Note: we must use getXXX() methods and not access the variables // directly, since in some cases (notably those widgets with embedded // ScrollBars) the two quantities may be different int x = tmp->getAbsX() - 1, y = tmp->getAbsY() - 1, w = tmp->getWidth() + 2, h = tmp->getHeight() + 2; // First clear area surrounding all widgets if(tmp->_hasFocus) { if(emitFocusEvents) tmp->lostFocus(); else tmp->_hasFocus = false; s.frameRect(x, y, w, h, kDlgColor); tmp->setDirty(); s.setDirty(); } } // Figure out which which should be active if(pos == -1) return nullptr; else { int oldPos = pos; do { switch(direction) { case -1: // previous widget pos--; if(pos < 0) pos = size - 1; break; case +1: // next widget pos++; if(pos >= size) pos = 0; break; default: // pos already set break; } // break if all widgets should be disabled if(oldPos == pos) break; } while(!arr[pos]->isEnabled()); } // Now highlight the active widget tmp = arr[pos]; // Get area around widget // Note: we must use getXXX() methods and not access the variables // directly, since in some cases (notably those widgets with embedded // ScrollBars) the two quantities may be different int x = tmp->getAbsX() - 1, y = tmp->getAbsY() - 1, w = tmp->getWidth() + 2, h = tmp->getHeight() + 2; if(emitFocusEvents) tmp->receivedFocus(); else tmp->_hasFocus = true; s.frameRect(x, y, w, h, kWidFrameColor, FrameStyle::Dashed); tmp->setDirty(); s.setDirty(); return tmp; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Widget::setDirtyInChain(Widget* start) { while(start) { start->setDirty(); start = start->_next; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StaticTextWidget::StaticTextWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& text, TextAlign align, uInt32 shadowColor) : Widget(boss, font, x, y, w, h), _align(align) { _flags = WIDGET_ENABLED; _bgcolor = kDlgColor; _bgcolorhi = kDlgColor; _textcolor = kTextColor; _textcolorhi = kTextColor; _shadowcolor = shadowColor; _label = text; _editable = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - StaticTextWidget::StaticTextWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& text, TextAlign align, uInt32 shadowColor) : StaticTextWidget(boss, font, x, y, font.getStringWidth(text), font.getLineHeight(), text, align, shadowColor) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StaticTextWidget::setValue(int value) { char buf[256]; std::snprintf(buf, 255, "%d", value); _label = buf; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StaticTextWidget::setLabel(const string& label) { _label = label; setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void StaticTextWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); s.drawString(_font, _label, _x, _y, _w, isEnabled() ? _textcolor : uInt32(kColor), _align, 0, true, _shadowcolor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& label, int cmd) : StaticTextWidget(boss, font, x, y, w, h, label, TextAlign::Center), CommandSender(boss), _cmd(cmd), _useBitmap(false) { _flags = WIDGET_ENABLED | WIDGET_BORDER | WIDGET_CLEARBG; _bgcolor = kBtnColor; _bgcolorhi = kBtnColorHi; _textcolor = kBtnTextColor; _textcolorhi = kBtnTextColorHi; _editable = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int dw, const string& label, int cmd) : ButtonWidget(boss, font, x, y, font.getStringWidth(label) + dw, font.getLineHeight() + 4, label, cmd) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, int cmd) : ButtonWidget(boss, font, x, y, 20, label, cmd) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ButtonWidget::ButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, uInt32* bitmap, int bmw, int bmh, int cmd) : ButtonWidget(boss, font, x, y, w, h, "", cmd) { _bitmap = bitmap; _bmh = bmh; _bmw = bmw; _useBitmap = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ButtonWidget::handleMouseEntered() { setFlags(WIDGET_HILITED); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ButtonWidget::handleMouseLeft() { clearFlags(WIDGET_HILITED); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool ButtonWidget::handleEvent(Event::Type e) { if(!isEnabled()) return false; switch(e) { case Event::UISelect: // Simulate mouse event handleMouseUp(0, 0, MouseButton::LEFT, 0); return true; default: return false; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ButtonWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { if(isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) { clearFlags(WIDGET_HILITED); sendCommand(_cmd, 0, _id); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void ButtonWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); if (!_useBitmap) s.drawString(_font, _label, _x, _y + (_h - _fontHeight)/2 + 1, _w, !isEnabled() ? hilite ? uInt32(kColor) : uInt32(kBGColorLo) : hilite ? _textcolorhi : _textcolor, _align); else s.drawBitmap(_bitmap, _x + (_w - _bmw) / 2, _y + (_h - _bmh) / 2, !isEnabled() ? hilite ? uInt32(kColor) : uInt32(kBGColorLo) : hilite ? _textcolorhi : _textcolor, _bmw, _bmh); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* 8x8 checkbox bitmap */ #ifndef FLAT_UI static uInt32 checked_img_active[8] = { 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111, 0b11111111 }; static uInt32 checked_img_inactive[8] = { 0b11111111, 0b11111111, 0b11100111, 0b11000011, 0b11000011, 0b11100111, 0b11111111, 0b11111111 }; static uInt32 checked_img_circle[8] = { 0b00011000, 0b01111110, 0b01111110, 0b11111111, 0b11111111, 0b01111110, 0b01111110, 0b00011000 }; #else static uInt32 checked_img_active[10] = { 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111 }; static uInt32 checked_img_inactive[10] = { 0b1111111111, 0b1111111111, 0b1111001111, 0b1110000111, 0b1100000011, 0b1100000011, 0b1110000111, 0b1111001111, 0b1111111111, 0b1111111111 }; static uInt32 checked_img_circle[10] = { 0b0001111000, 0b0111111110, 0b0111111110, 0b1111111111, 0b1111111111, 0b1111111111, 0b1111111111, 0b0111111110, 0b0111111110, 0b0001111000 }; #endif // !FLAT_UI // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CheckboxWidget::CheckboxWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, int cmd) : ButtonWidget(boss, font, x, y, 16, 16, label, cmd), _state(false), _holdFocus(true), _drawBox(true), _changed(false), _fillColor(kColor), _boxY(0), _textY(0) { _flags = WIDGET_ENABLED; _bgcolor = _bgcolorhi = kWidColor; _editable = true; if(label == "") _w = 14; else _w = font.getStringWidth(label) + 20; _h = font.getFontHeight() < 14 ? 14 : font.getFontHeight(); // Depending on font size, either the font or box will need to be // centered vertically if(_h > 14) // center box _boxY = (_h - 14) / 2; else // center text _textY = (14 - _font.getFontHeight()) / 2; setFill(CheckboxWidget::Normal); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::handleMouseEntered() { setFlags(WIDGET_HILITED); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::handleMouseLeft() { clearFlags(WIDGET_HILITED); setDirty(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { if(isEnabled() && _editable && x >= 0 && x < _w && y >= 0 && y < _h) { toggleState(); // We only send a command when the widget has been changed interactively sendCommand(_cmd, _state, _id); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::setEditable(bool editable) { _editable = editable; if(_editable) { _bgcolor = kWidColor; } else { _bgcolor = kBGColorHi; setFill(CheckboxWidget::Inactive); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::setFill(FillType type) { switch(type) { case CheckboxWidget::Normal: _img = checked_img_active; _drawBox = true; break; case CheckboxWidget::Inactive: _img = checked_img_inactive; _drawBox = true; break; case CheckboxWidget::Circle: _img = checked_img_circle; _drawBox = false; break; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::setState(bool state, bool changed) { if(_state != state) { _state = state; setDirty(); } _changed = changed; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void CheckboxWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); #ifndef FLAT_UI // Draw the box if(_drawBox) s.box(_x, _y + _boxY, 14, 14, kColor, kShadowColor); // Do we draw a square or cross? s.fillRect(_x + 2, _y + _boxY + 2, 10, 10, _changed ? uInt32(kDbgChangedColor) : isEnabled() ? _bgcolor : uInt32(kColor)); if(_state) s.drawBitmap(_img, _x + 3, _y + _boxY + 3, isEnabled() ? kCheckColor : kShadowColor); #else if(_drawBox) s.frameRect(_x, _y + _boxY, 14, 14, hilite ? kScrollColorHi : kShadowColor); // Do we draw a square or cross? s.fillRect(_x + 1, _y + _boxY + 1, 12, 12, _changed ? kDbgChangedColor : isEnabled() ? _bgcolor : kColor); if(_state) s.drawBitmap(_img, _x + 2, _y + _boxY + 2, isEnabled() ? hilite ? kScrollColorHi : kCheckColor : kShadowColor, 10); #endif // Finally draw the label s.drawString(_font, _label, _x + 20, _y + _textY, _w, isEnabled() ? kTextColor : kColor); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SliderWidget::SliderWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& label, int labelWidth, int cmd) : ButtonWidget(boss, font, x, y, w, h, label, cmd), _value(0), _stepValue(1), _valueMin(0), _valueMax(100), _isDragging(false), _labelWidth(labelWidth) { _flags = WIDGET_ENABLED | WIDGET_TRACK_MOUSE; _bgcolor = kDlgColor; _bgcolorhi = kDlgColor; if(!_label.empty() && _labelWidth == 0) _labelWidth = _font.getStringWidth(_label); _w = w + _labelWidth; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::setValue(int value) { if(value < _valueMin) value = _valueMin; else if(value > _valueMax) value = _valueMax; if(value != _value) { _value = value; setDirty(); sendCommand(_cmd, _value, _id); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::setMinValue(int value) { _valueMin = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::setMaxValue(int value) { _valueMax = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::setStepValue(int value) { _stepValue = value; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::handleMouseMoved(int x, int y) { // TODO: when the mouse is dragged outside the widget, the slider should // snap back to the old value. if(isEnabled() && _isDragging && x >= int(_labelWidth)) setValue(posToValue(x - _labelWidth)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::handleMouseDown(int x, int y, MouseButton b, int clickCount) { if(isEnabled() && b == MouseButton::LEFT) { _isDragging = true; handleMouseMoved(x, y); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount) { if(isEnabled() && _isDragging) sendCommand(_cmd, _value, _id); _isDragging = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::handleMouseWheel(int x, int y, int direction) { if(isEnabled()) { if(direction < 0) handleEvent(Event::UIUp); else if(direction > 0) handleEvent(Event::UIDown); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SliderWidget::handleEvent(Event::Type e) { if(!isEnabled()) return false; switch(e) { case Event::UIDown: case Event::UILeft: case Event::UIPgDown: setValue(_value - _stepValue); break; case Event::UIUp: case Event::UIRight: case Event::UIPgUp: setValue(_value + _stepValue); break; case Event::UIHome: setValue(_valueMin); break; case Event::UIEnd: setValue(_valueMax); break; default: return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SliderWidget::drawWidget(bool hilite) { FBSurface& s = _boss->dialog().surface(); #ifndef FLAT_UI // Draw the label, if any if(_labelWidth > 0) s.drawString(_font, _label, _x, _y + 2, _labelWidth, isEnabled() ? kTextColor : kColor, TextAlign::Right); // Draw the box s.box(_x + _labelWidth, _y, _w - _labelWidth, _h, kColor, kShadowColor); // Fill the box s.fillRect(_x + _labelWidth + 2, _y + 2, _w - _labelWidth - 4, _h - 4, !isEnabled() ? kBGColorHi : kWidColor); // Draw the 'bar' s.fillRect(_x + _labelWidth + 2, _y + 2, valueToPos(_value), _h - 4, !isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor); #else // Draw the label, if any if(_labelWidth > 0) s.drawString(_font, _label, _x, _y + 2, _labelWidth, isEnabled() ? kTextColor : kColor, TextAlign::Left); // Draw the box s.frameRect(_x + _labelWidth, _y, _w - _labelWidth, _h, isEnabled() && hilite ? kSliderColorHi : kShadowColor); // Fill the box s.fillRect(_x + _labelWidth + 1, _y + 1, _w - _labelWidth - 2, _h - 2, !isEnabled() ? kBGColorHi : kWidColor); // Draw the 'bar' s.fillRect(_x + _labelWidth + 2, _y + 2, valueToPos(_value), _h - 4, !isEnabled() ? kColor : hilite ? kSliderColorHi : kSliderColor); #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int SliderWidget::valueToPos(int value) { if(value < _valueMin) value = _valueMin; else if(value > _valueMax) value = _valueMax; int range = std::max(_valueMax - _valueMin, 1); // don't divide by zero return ((_w - _labelWidth - 4) * (value - _valueMin) / range); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int SliderWidget::posToValue(int pos) { int value = (pos) * (_valueMax - _valueMin) / (_w - _labelWidth - 4) + _valueMin; // Scale the position to the correct interval (according to step value) return value - (value % _stepValue); } stella-5.1.1/src/gui/Widget.hxx000066400000000000000000000267071324334165500163530ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. // // Based on code from ScummVM - Scumm Interpreter // Copyright (C) 2002-2004 The ScummVM project //============================================================================ #ifndef WIDGET_HXX #define WIDGET_HXX class Dialog; namespace GUI { class Font; } #include #include "bspf.hxx" #include "Event.hxx" #include "GuiObject.hxx" enum { WIDGET_ENABLED = 1 << 0, WIDGET_INVISIBLE = 1 << 1, WIDGET_HILITED = 1 << 2, WIDGET_BORDER = 1 << 3, WIDGET_CLEARBG = 1 << 4, WIDGET_TRACK_MOUSE = 1 << 5, WIDGET_RETAIN_FOCUS = 1 << 6, WIDGET_WANTS_TAB = 1 << 7, WIDGET_WANTS_RAWDATA = 1 << 8 }; /** This is the base class for all widgets. @author Stephen Anthony */ class Widget : public GuiObject { friend class Dialog; public: Widget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h); virtual ~Widget(); virtual int getAbsX() const override { return _x + _boss->getChildX(); } virtual int getAbsY() const override { return _y + _boss->getChildY(); } virtual int getLeft() const { return _x; } virtual int getTop() const { return _y; } virtual int getRight() const { return _x + getWidth(); } virtual int getBottom() const { return _y + getHeight(); } virtual bool handleText(char text) { return false; } virtual bool handleKeyDown(StellaKey key, StellaMod mod) { return false; } virtual bool handleKeyUp(StellaKey key, StellaMod mod) { return false; } virtual void handleMouseDown(int x, int y, MouseButton b, int clickCount) { } virtual void handleMouseUp(int x, int y, MouseButton b, int clickCount) { } virtual void handleMouseEntered() { } virtual void handleMouseLeft() { } virtual void handleMouseMoved(int x, int y) { } virtual void handleMouseWheel(int x, int y, int direction) { } virtual bool handleMouseClicks(int x, int y, MouseButton b) { return false; } virtual void handleJoyDown(int stick, int button) { } virtual void handleJoyUp(int stick, int button) { } virtual void handleJoyAxis(int stick, int axis, int value) { } virtual bool handleJoyHat(int stick, int hat, JoyHat value) { return false; } virtual bool handleEvent(Event::Type event) { return false; } void draw() override; void receivedFocus(); void lostFocus(); void addFocusWidget(Widget* w) override { _focusList.push_back(w); } void addToFocusList(WidgetArray& list) override { Vec::append(_focusList, list); } /** Set/clear WIDGET_ENABLED flag */ void setEnabled(bool e); void setFlags(int flags) { _flags |= flags; setDirty(); } void clearFlags(int flags) { _flags &= ~flags; setDirty(); } int getFlags() const { return _flags; } bool isEnabled() const { return _flags & WIDGET_ENABLED; } bool isVisible() const override { return !(_flags & WIDGET_INVISIBLE); } virtual bool wantsFocus() const { return _flags & WIDGET_RETAIN_FOCUS; } bool wantsTab() const { return _flags & WIDGET_WANTS_TAB; } bool wantsRaw() const { return _flags & WIDGET_WANTS_RAWDATA; } void setID(int id) { _id = id; } int getID() const { return _id; } virtual const GUI::Font& font() const { return _font; } void setTextColor(uInt32 color) { _textcolor = color; } void setTextColorHi(uInt32 color) { _textcolorhi = color; } void setBGColor(uInt32 color) { _bgcolor = color; } void setBGColorHi(uInt32 color) { _bgcolorhi = color; } void setShadowColor(uInt32 color) { _shadowcolor = color; } virtual void loadConfig() { } protected: virtual void drawWidget(bool hilite) { } virtual void receivedFocusWidget() { } virtual void lostFocusWidget() { } virtual Widget* findWidget(int x, int y) { return this; } void releaseFocus() override { assert(_boss); _boss->releaseFocus(); } // By default, delegate unhandled commands to the boss void handleCommand(CommandSender* sender, int cmd, int data, int id) override { assert(_boss); _boss->handleCommand(sender, cmd, data, id); } protected: GuiObject* _boss; const GUI::Font& _font; Widget* _next; int _id; int _flags; bool _hasFocus; int _fontWidth; int _fontHeight; uInt32 _bgcolor; uInt32 _bgcolorhi; uInt32 _textcolor; uInt32 _textcolorhi; uInt32 _shadowcolor; public: static Widget* findWidgetInChain(Widget* start, int x, int y); /** Determine if 'find' is in the chain pointed to by 'start' */ static bool isWidgetInChain(Widget* start, Widget* find); /** Determine if 'find' is in the widget array */ static bool isWidgetInChain(WidgetArray& list, Widget* find); /** Select either previous, current, or next widget in chain to have focus, and deselects all others */ static Widget* setFocusForChain(GuiObject* boss, WidgetArray& arr, Widget* w, int direction, bool emitFocusEvents = true); /** Sets all widgets in this chain to be dirty (must be redrawn) */ static void setDirtyInChain(Widget* start); private: // Following constructors and assignment operators not supported Widget() = delete; Widget(const Widget&) = delete; Widget(Widget&&) = delete; Widget& operator=(const Widget&) = delete; Widget& operator=(Widget&&) = delete; }; /* StaticTextWidget */ class StaticTextWidget : public Widget { public: StaticTextWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& text, TextAlign align = TextAlign::Left, uInt32 shadowColor = 0); StaticTextWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& text, TextAlign align = TextAlign::Left, uInt32 shadowColor = 0); void setValue(int value); void setLabel(const string& label); void setAlign(TextAlign align) { _align = align; } const string& getLabel() const { return _label; } bool isEditable() const { return _editable; } protected: void drawWidget(bool hilite) override; protected: string _label; bool _editable; TextAlign _align; private: // Following constructors and assignment operators not supported StaticTextWidget() = delete; StaticTextWidget(const StaticTextWidget&) = delete; StaticTextWidget(StaticTextWidget&&) = delete; StaticTextWidget& operator=(const StaticTextWidget&) = delete; StaticTextWidget& operator=(StaticTextWidget&&) = delete; }; /* ButtonWidget */ class ButtonWidget : public StaticTextWidget, public CommandSender { public: ButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& label, int cmd = 0); ButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int dw, const string& label, int cmd = 0); ButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, int cmd = 0); ButtonWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int dw, int dh, uInt32* bitmap, int bmw, int bmh, int cmd = 0); void setCmd(int cmd) { _cmd = cmd; } int getCmd() const { return _cmd; } protected: void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseEntered() override; void handleMouseLeft() override; bool handleEvent(Event::Type event) override; void drawWidget(bool hilite) override; protected: int _cmd; bool _useBitmap; uInt32* _bitmap; int _bmw, _bmh; private: // Following constructors and assignment operators not supported ButtonWidget() = delete; ButtonWidget(const ButtonWidget&) = delete; ButtonWidget(ButtonWidget&&) = delete; ButtonWidget& operator=(const ButtonWidget&) = delete; ButtonWidget& operator=(ButtonWidget&&) = delete; }; /* CheckboxWidget */ class CheckboxWidget : public ButtonWidget { public: enum { kCheckActionCmd = 'CBAC' }; enum FillType { Normal, Inactive, Circle }; public: CheckboxWidget(GuiObject* boss, const GUI::Font& font, int x, int y, const string& label, int cmd = 0); void setEditable(bool editable); void setFill(FillType type); void setState(bool state, bool changed = false); void toggleState() { setState(!_state); } bool getState() const { return _state; } void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseEntered() override; void handleMouseLeft() override; static int boxSize() { return 14; } // box is square protected: void drawWidget(bool hilite) override; protected: bool _state; bool _holdFocus; bool _drawBox; bool _changed; uInt32* _img; uInt32 _fillColor; int _boxY; int _textY; private: // Following constructors and assignment operators not supported CheckboxWidget() = delete; CheckboxWidget(const CheckboxWidget&) = delete; CheckboxWidget(CheckboxWidget&&) = delete; CheckboxWidget& operator=(const CheckboxWidget&) = delete; CheckboxWidget& operator=(CheckboxWidget&&) = delete; }; /* SliderWidget */ class SliderWidget : public ButtonWidget { public: SliderWidget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h, const string& label = "", int labelWidth = 0, int cmd = 0); void setValue(int value); int getValue() const { return _value; } void setMinValue(int value); int getMinValue() const { return _valueMin; } void setMaxValue(int value); int getMaxValue() const { return _valueMax; } void setStepValue(int value); int getStepValue() const { return _stepValue; } protected: void handleMouseMoved(int x, int y) override; void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; void handleMouseWheel(int x, int y, int direction) override; bool handleEvent(Event::Type event) override; void drawWidget(bool hilite) override; int valueToPos(int value); int posToValue(int pos); protected: int _value, _stepValue; int _valueMin, _valueMax; bool _isDragging; int _labelWidth; private: // Following constructors and assignment operators not supported SliderWidget() = delete; SliderWidget(const SliderWidget&) = delete; SliderWidget(SliderWidget&&) = delete; SliderWidget& operator=(const SliderWidget&) = delete; SliderWidget& operator=(SliderWidget&&) = delete; }; #endif stella-5.1.1/src/gui/module.mk000066400000000000000000000025451324334165500162070ustar00rootroot00000000000000MODULE := src/gui MODULE_OBJS := \ src/gui/AboutDialog.o \ src/gui/AudioDialog.o \ src/gui/BrowserDialog.o \ src/gui/CheckListWidget.o \ src/gui/ColorWidget.o \ src/gui/ComboDialog.o \ src/gui/CommandDialog.o \ src/gui/CommandMenu.o \ src/gui/ConfigPathDialog.o \ src/gui/ContextMenu.o \ src/gui/DeveloperDialog.o \ src/gui/DialogContainer.o \ src/gui/Dialog.o \ src/gui/EditableWidget.o \ src/gui/EditTextWidget.o \ src/gui/EventMappingWidget.o \ src/gui/FileListWidget.o \ src/gui/Font.o \ src/gui/GameInfoDialog.o \ src/gui/GameList.o \ src/gui/GlobalPropsDialog.o \ src/gui/HelpDialog.o \ src/gui/InputDialog.o \ src/gui/InputTextDialog.o \ src/gui/JoystickDialog.o \ src/gui/LauncherDialog.o \ src/gui/LauncherFilterDialog.o \ src/gui/Launcher.o \ src/gui/ListWidget.o \ src/gui/LoggerDialog.o \ src/gui/Menu.o \ src/gui/MessageBox.o \ src/gui/OptionsDialog.o \ src/gui/PopUpWidget.o \ src/gui/ProgressDialog.o \ src/gui/RadioButtonWidget.o \ src/gui/RomAuditDialog.o \ src/gui/RomInfoWidget.o \ src/gui/ScrollBarWidget.o \ src/gui/SnapshotDialog.o \ src/gui/StringListWidget.o \ src/gui/TabWidget.o \ src/gui/TimeLineWidget.o \ src/gui/TimeMachineDialog.o \ src/gui/TimeMachine.o \ src/gui/UIDialog.o \ src/gui/VideoDialog.o \ src/gui/Widget.o MODULE_DIRS += \ src/gui # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/libpng/000077500000000000000000000000001324334165500150525ustar00rootroot00000000000000stella-5.1.1/src/libpng/module.mk000066400000000000000000000007421324334165500166730ustar00rootroot00000000000000MODULE := src/libpng MODULE_OBJS := \ src/libpng/png.o \ src/libpng/pngerror.o \ src/libpng/pngget.o \ src/libpng/pngmem.o \ src/libpng/pngpread.o \ src/libpng/pngread.o \ src/libpng/pngrio.o \ src/libpng/pngrtran.o \ src/libpng/pngrutil.o \ src/libpng/pngset.o \ src/libpng/pngtrans.o \ src/libpng/pngwio.o \ src/libpng/pngwrite.o \ src/libpng/pngwtran.o \ src/libpng/pngwutil.o MODULE_DIRS += \ src/libpng # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/libpng/png.c000066400000000000000000004643071324334165500160200ustar00rootroot00000000000000 /* png.c - location for general purpose libpng functions * * Last changed in libpng 1.6.33 [September 28, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ typedef png_libpng_version_1_6_34 Your_png_h_is_not_version_1_6_34; #ifdef __GNUC__ /* The version tests may need to be added to, but the problem warning has * consistently been fixed in GCC versions which obtain wide-spread release. * The problem is that many versions of GCC rearrange comparison expressions in * the optimizer in such a way that the results of the comparison will change * if signed integer overflow occurs. Such comparisons are not permitted in * ANSI C90, however GCC isn't clever enough to work out that that do not occur * below in png_ascii_from_fp and png_muldiv, so it produces a warning with * -Wextra. Unfortunately this is highly dependent on the optimizer and the * machine architecture so the warning comes and goes unpredictably and is * impossible to "fix", even were that a good idea. */ #if __GNUC__ == 7 && __GNUC_MINOR__ == 1 #define GCC_STRICT_OVERFLOW 1 #endif /* GNU 7.1.x */ #endif /* GNU */ #ifndef GCC_STRICT_OVERFLOW #define GCC_STRICT_OVERFLOW 0 #endif /* Tells libpng that we have already handled the first "num_bytes" bytes * of the PNG file signature. If the PNG data is embedded into another * stream we can set num_bytes = 8 so that libpng will not attempt to read * or write any of the magic bytes before it starts on the IHDR. */ #ifdef PNG_READ_SUPPORTED void PNGAPI png_set_sig_bytes(png_structrp png_ptr, int num_bytes) { unsigned int nb = (unsigned int)num_bytes; png_debug(1, "in png_set_sig_bytes"); if (png_ptr == NULL) return; if (num_bytes < 0) nb = 0; if (nb > 8) png_error(png_ptr, "Too many bytes for PNG signature"); png_ptr->sig_bytes = (png_byte)nb; } /* Checks whether the supplied bytes match the PNG signature. We allow * checking less than the full 8-byte signature so that those apps that * already read the first few bytes of a file to determine the file type * can simply check the remaining bytes for extra assurance. Returns * an integer less than, equal to, or greater than zero if sig is found, * respectively, to be less than, to match, or be greater than the correct * PNG signature (this is the same behavior as strcmp, memcmp, etc). */ int PNGAPI png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check) { png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; if (num_to_check > 8) num_to_check = 8; else if (num_to_check < 1) return (-1); if (start > 7) return (-1); if (start + num_to_check > 8) num_to_check = 8 - start; return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check))); } #endif /* READ */ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) /* Function to allocate memory for zlib */ PNG_FUNCTION(voidpf /* PRIVATE */, png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED) { png_alloc_size_t num_bytes = size; if (png_ptr == NULL) return NULL; if (items >= (~(png_alloc_size_t)0)/size) { png_warning (png_voidcast(png_structrp, png_ptr), "Potential overflow in png_zalloc()"); return NULL; } num_bytes *= items; return png_malloc_warn(png_voidcast(png_structrp, png_ptr), num_bytes); } /* Function to free memory for zlib */ void /* PRIVATE */ png_zfree(voidpf png_ptr, voidpf ptr) { png_free(png_voidcast(png_const_structrp,png_ptr), ptr); } /* Reset the CRC variable to 32 bits of 1's. Care must be taken * in case CRC is > 32 bits to leave the top bits 0. */ void /* PRIVATE */ png_reset_crc(png_structrp png_ptr) { /* The cast is safe because the crc is a 32-bit value. */ png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); } /* Calculate the CRC over a section of data. We can only pass as * much data to this routine as the largest single buffer size. We * also check that this data will actually be used before going to the * trouble of calculating it. */ void /* PRIVATE */ png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length) { int need_crc = 1; if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) need_crc = 0; } else /* critical */ { if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) need_crc = 0; } /* 'uLong' is defined in zlib.h as unsigned long; this means that on some * systems it is a 64-bit value. crc32, however, returns 32 bits so the * following cast is safe. 'uInt' may be no more than 16 bits, so it is * necessary to perform a loop here. */ if (need_crc != 0 && length > 0) { uLong crc = png_ptr->crc; /* Should never issue a warning */ do { uInt safe_length = (uInt)length; #ifndef __COVERITY__ if (safe_length == 0) safe_length = (uInt)-1; /* evil, but safe */ #endif crc = crc32(crc, ptr, safe_length); /* The following should never issue compiler warnings; if they do the * target system has characteristics that will probably violate other * assumptions within the libpng code. */ ptr += safe_length; length -= safe_length; } while (length > 0); /* And the following is always safe because the crc is only 32 bits. */ png_ptr->crc = (png_uint_32)crc; } } /* Check a user supplied version number, called from both read and write * functions that create a png_struct. */ int png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) { /* Libpng versions 1.0.0 and later are binary compatible if the version * string matches through the second '.'; we must recompile any * applications that use any older library version. */ if (user_png_ver != NULL) { int i = -1; int found_dots = 0; do { i++; if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i]) png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; if (user_png_ver[i] == '.') found_dots++; } while (found_dots < 2 && user_png_ver[i] != 0 && PNG_LIBPNG_VER_STRING[i] != 0); } else png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0) { #ifdef PNG_WARNINGS_SUPPORTED size_t pos = 0; char m[128]; pos = png_safecat(m, (sizeof m), pos, "Application built with libpng-"); pos = png_safecat(m, (sizeof m), pos, user_png_ver); pos = png_safecat(m, (sizeof m), pos, " but running with "); pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING); PNG_UNUSED(pos) png_warning(png_ptr, m); #endif #ifdef PNG_ERROR_NUMBERS_SUPPORTED png_ptr->flags = 0; #endif return 0; } /* Success return. */ return 1; } /* Generic function to create a png_struct for either read or write - this * contains the common initialization. */ PNG_FUNCTION(png_structp /* PRIVATE */, png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { png_struct create_struct; # ifdef PNG_SETJMP_SUPPORTED jmp_buf create_jmp_buf; # endif /* This temporary stack-allocated structure is used to provide a place to * build enough context to allow the user provided memory allocator (if any) * to be called. */ memset(&create_struct, 0, (sizeof create_struct)); /* Added at libpng-1.2.6 */ # ifdef PNG_USER_LIMITS_SUPPORTED create_struct.user_width_max = PNG_USER_WIDTH_MAX; create_struct.user_height_max = PNG_USER_HEIGHT_MAX; # ifdef PNG_USER_CHUNK_CACHE_MAX /* Added at libpng-1.2.43 and 1.4.0 */ create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; # endif # ifdef PNG_USER_CHUNK_MALLOC_MAX /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists * in png_struct regardless. */ create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; # endif # endif /* The following two API calls simply set fields in png_struct, so it is safe * to do them now even though error handling is not yet set up. */ # ifdef PNG_USER_MEM_SUPPORTED png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn); # else PNG_UNUSED(mem_ptr) PNG_UNUSED(malloc_fn) PNG_UNUSED(free_fn) # endif /* (*error_fn) can return control to the caller after the error_ptr is set, * this will result in a memory leak unless the error_fn does something * extremely sophisticated. The design lacks merit but is implicit in the * API. */ png_set_error_fn(&create_struct, error_ptr, error_fn, warn_fn); # ifdef PNG_SETJMP_SUPPORTED if (!setjmp(create_jmp_buf)) # endif { # ifdef PNG_SETJMP_SUPPORTED /* Temporarily fake out the longjmp information until we have * successfully completed this function. This only works if we have * setjmp() support compiled in, but it is safe - this stuff should * never happen. */ create_struct.jmp_buf_ptr = &create_jmp_buf; create_struct.jmp_buf_size = 0; /*stack allocation*/ create_struct.longjmp_fn = longjmp; # endif /* Call the general version checker (shared with read and write code): */ if (png_user_version_check(&create_struct, user_png_ver) != 0) { png_structrp png_ptr = png_voidcast(png_structrp, png_malloc_warn(&create_struct, (sizeof *png_ptr))); if (png_ptr != NULL) { /* png_ptr->zstream holds a back-pointer to the png_struct, so * this can only be done now: */ create_struct.zstream.zalloc = png_zalloc; create_struct.zstream.zfree = png_zfree; create_struct.zstream.opaque = png_ptr; # ifdef PNG_SETJMP_SUPPORTED /* Eliminate the local error handling: */ create_struct.jmp_buf_ptr = NULL; create_struct.jmp_buf_size = 0; create_struct.longjmp_fn = 0; # endif *png_ptr = create_struct; /* This is the successful return point */ return png_ptr; } } } /* A longjmp because of a bug in the application storage allocator or a * simple failure to allocate the png_struct. */ return NULL; } /* Allocate the memory for an info_struct for the application. */ PNG_FUNCTION(png_infop,PNGAPI png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED) { png_inforp info_ptr; png_debug(1, "in png_create_info_struct"); if (png_ptr == NULL) return NULL; /* Use the internal API that does not (or at least should not) error out, so * that this call always returns ok. The application typically sets up the * error handling *after* creating the info_struct because this is the way it * has always been done in 'example.c'. */ info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr, (sizeof *info_ptr))); if (info_ptr != NULL) memset(info_ptr, 0, (sizeof *info_ptr)); return info_ptr; } /* This function frees the memory associated with a single info struct. * Normally, one would use either png_destroy_read_struct() or * png_destroy_write_struct() to free an info struct, but this may be * useful for some applications. From libpng 1.6.0 this function is also used * internally to implement the png_info release part of the 'struct' destroy * APIs. This ensures that all possible approaches free the same data (all of * it). */ void PNGAPI png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr) { png_inforp info_ptr = NULL; png_debug(1, "in png_destroy_info_struct"); if (png_ptr == NULL) return; if (info_ptr_ptr != NULL) info_ptr = *info_ptr_ptr; if (info_ptr != NULL) { /* Do this first in case of an error below; if the app implements its own * memory management this can lead to png_free calling png_error, which * will abort this routine and return control to the app error handler. * An infinite loop may result if it then tries to free the same info * ptr. */ *info_ptr_ptr = NULL; png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); memset(info_ptr, 0, (sizeof *info_ptr)); png_free(png_ptr, info_ptr); } } /* Initialize the info structure. This is now an internal function (0.89) * and applications using it are urged to use png_create_info_struct() * instead. Use deprecated in 1.6.0, internal use removed (used internally it * is just a memset). * * NOTE: it is almost inconceivable that this API is used because it bypasses * the user-memory mechanism and the user error handling/warning mechanisms in * those cases where it does anything other than a memset. */ PNG_FUNCTION(void,PNGAPI png_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size), PNG_DEPRECATED) { png_inforp info_ptr = *ptr_ptr; png_debug(1, "in png_info_init_3"); if (info_ptr == NULL) return; if ((sizeof (png_info)) > png_info_struct_size) { *ptr_ptr = NULL; /* The following line is why this API should not be used: */ free(info_ptr); info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL, (sizeof *info_ptr))); if (info_ptr == NULL) return; *ptr_ptr = info_ptr; } /* Set everything to 0 */ memset(info_ptr, 0, (sizeof *info_ptr)); } /* The following API is not called internally */ void PNGAPI png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, int freer, png_uint_32 mask) { png_debug(1, "in png_data_freer"); if (png_ptr == NULL || info_ptr == NULL) return; if (freer == PNG_DESTROY_WILL_FREE_DATA) info_ptr->free_me |= mask; else if (freer == PNG_USER_WILL_FREE_DATA) info_ptr->free_me &= ~mask; else png_error(png_ptr, "Unknown freer parameter in png_data_freer"); } void PNGAPI png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, int num) { png_debug(1, "in png_free_data"); if (png_ptr == NULL || info_ptr == NULL) return; #ifdef PNG_TEXT_SUPPORTED /* Free text item num or (if num == -1) all text items */ if (info_ptr->text != NULL && ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0) { if (num != -1) { png_free(png_ptr, info_ptr->text[num].key); info_ptr->text[num].key = NULL; } else { int i; for (i = 0; i < info_ptr->num_text; i++) png_free(png_ptr, info_ptr->text[i].key); png_free(png_ptr, info_ptr->text); info_ptr->text = NULL; info_ptr->num_text = 0; info_ptr->max_text = 0; } } #endif #ifdef PNG_tRNS_SUPPORTED /* Free any tRNS entry */ if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0) { info_ptr->valid &= ~PNG_INFO_tRNS; png_free(png_ptr, info_ptr->trans_alpha); info_ptr->trans_alpha = NULL; info_ptr->num_trans = 0; } #endif #ifdef PNG_sCAL_SUPPORTED /* Free any sCAL entry */ if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->scal_s_width); png_free(png_ptr, info_ptr->scal_s_height); info_ptr->scal_s_width = NULL; info_ptr->scal_s_height = NULL; info_ptr->valid &= ~PNG_INFO_sCAL; } #endif #ifdef PNG_pCAL_SUPPORTED /* Free any pCAL entry */ if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->pcal_purpose); png_free(png_ptr, info_ptr->pcal_units); info_ptr->pcal_purpose = NULL; info_ptr->pcal_units = NULL; if (info_ptr->pcal_params != NULL) { int i; for (i = 0; i < info_ptr->pcal_nparams; i++) png_free(png_ptr, info_ptr->pcal_params[i]); png_free(png_ptr, info_ptr->pcal_params); info_ptr->pcal_params = NULL; } info_ptr->valid &= ~PNG_INFO_pCAL; } #endif #ifdef PNG_iCCP_SUPPORTED /* Free any profile entry */ if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->iccp_name); png_free(png_ptr, info_ptr->iccp_profile); info_ptr->iccp_name = NULL; info_ptr->iccp_profile = NULL; info_ptr->valid &= ~PNG_INFO_iCCP; } #endif #ifdef PNG_sPLT_SUPPORTED /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ if (info_ptr->splt_palettes != NULL && ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0) { if (num != -1) { png_free(png_ptr, info_ptr->splt_palettes[num].name); png_free(png_ptr, info_ptr->splt_palettes[num].entries); info_ptr->splt_palettes[num].name = NULL; info_ptr->splt_palettes[num].entries = NULL; } else { int i; for (i = 0; i < info_ptr->splt_palettes_num; i++) { png_free(png_ptr, info_ptr->splt_palettes[i].name); png_free(png_ptr, info_ptr->splt_palettes[i].entries); } png_free(png_ptr, info_ptr->splt_palettes); info_ptr->splt_palettes = NULL; info_ptr->splt_palettes_num = 0; info_ptr->valid &= ~PNG_INFO_sPLT; } } #endif #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED if (info_ptr->unknown_chunks != NULL && ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0) { if (num != -1) { png_free(png_ptr, info_ptr->unknown_chunks[num].data); info_ptr->unknown_chunks[num].data = NULL; } else { int i; for (i = 0; i < info_ptr->unknown_chunks_num; i++) png_free(png_ptr, info_ptr->unknown_chunks[i].data); png_free(png_ptr, info_ptr->unknown_chunks); info_ptr->unknown_chunks = NULL; info_ptr->unknown_chunks_num = 0; } } #endif #ifdef PNG_eXIf_SUPPORTED /* Free any eXIf entry */ if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0) { # ifdef PNG_READ_eXIf_SUPPORTED if (info_ptr->eXIf_buf) { png_free(png_ptr, info_ptr->eXIf_buf); info_ptr->eXIf_buf = NULL; } # endif if (info_ptr->exif) { png_free(png_ptr, info_ptr->exif); info_ptr->exif = NULL; } info_ptr->valid &= ~PNG_INFO_eXIf; } #endif #ifdef PNG_hIST_SUPPORTED /* Free any hIST entry */ if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->hist); info_ptr->hist = NULL; info_ptr->valid &= ~PNG_INFO_hIST; } #endif /* Free any PLTE entry that was internally allocated */ if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0) { png_free(png_ptr, info_ptr->palette); info_ptr->palette = NULL; info_ptr->valid &= ~PNG_INFO_PLTE; info_ptr->num_palette = 0; } #ifdef PNG_INFO_IMAGE_SUPPORTED /* Free any image bits attached to the info structure */ if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0) { if (info_ptr->row_pointers != NULL) { png_uint_32 row; for (row = 0; row < info_ptr->height; row++) png_free(png_ptr, info_ptr->row_pointers[row]); png_free(png_ptr, info_ptr->row_pointers); info_ptr->row_pointers = NULL; } info_ptr->valid &= ~PNG_INFO_IDAT; } #endif if (num != -1) mask &= ~PNG_FREE_MUL; info_ptr->free_me &= ~mask; } #endif /* READ || WRITE */ /* This function returns a pointer to the io_ptr associated with the user * functions. The application should free any memory associated with this * pointer before png_write_destroy() or png_read_destroy() are called. */ png_voidp PNGAPI png_get_io_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); return (png_ptr->io_ptr); } #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) # ifdef PNG_STDIO_SUPPORTED /* Initialize the default input/output functions for the PNG file. If you * use your own read or write routines, you can call either png_set_read_fn() * or png_set_write_fn() instead of png_init_io(). If you have defined * PNG_NO_STDIO or otherwise disabled PNG_STDIO_SUPPORTED, you must use a * function of your own because "FILE *" isn't necessarily available. */ void PNGAPI png_init_io(png_structrp png_ptr, png_FILE_p fp) { png_debug(1, "in png_init_io"); if (png_ptr == NULL) return; png_ptr->io_ptr = (png_voidp)fp; } # endif # ifdef PNG_SAVE_INT_32_SUPPORTED /* PNG signed integers are saved in 32-bit 2's complement format. ANSI C-90 * defines a cast of a signed integer to an unsigned integer either to preserve * the value, if it is positive, or to calculate: * * (UNSIGNED_MAX+1) + integer * * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the * negative integral value is added the result will be an unsigned value * correspnding to the 2's complement representation. */ void PNGAPI png_save_int_32(png_bytep buf, png_int_32 i) { png_save_uint_32(buf, (png_uint_32)i); } # endif # ifdef PNG_TIME_RFC1123_SUPPORTED /* Convert the supplied time into an RFC 1123 string suitable for use in * a "Creation Time" or other text-based time string. */ int PNGAPI png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) { static PNG_CONST char short_months[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; if (out == NULL) return 0; if (ptime->year > 9999 /* RFC1123 limitation */ || ptime->month == 0 || ptime->month > 12 || ptime->day == 0 || ptime->day > 31 || ptime->hour > 23 || ptime->minute > 59 || ptime->second > 60) return 0; { size_t pos = 0; char number_buf[5]; /* enough for a four-digit year */ # define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string)) # define APPEND_NUMBER(format, value)\ APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value))) # define APPEND(ch) if (pos < 28) out[pos++] = (ch) APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day); APPEND(' '); APPEND_STRING(short_months[(ptime->month - 1)]); APPEND(' '); APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year); APPEND(' '); APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour); APPEND(':'); APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute); APPEND(':'); APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second); APPEND_STRING(" +0000"); /* This reliably terminates the buffer */ PNG_UNUSED (pos) # undef APPEND # undef APPEND_NUMBER # undef APPEND_STRING } return 1; } # if PNG_LIBPNG_VER < 10700 /* To do: remove the following from libpng-1.7 */ /* Original API that uses a private buffer in png_struct. * Deprecated because it causes png_struct to carry a spurious temporary * buffer (png_struct::time_buffer), better to have the caller pass this in. */ png_const_charp PNGAPI png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) { if (png_ptr != NULL) { /* The only failure above if png_ptr != NULL is from an invalid ptime */ if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0) png_warning(png_ptr, "Ignoring invalid time value"); else return png_ptr->time_buffer; } return NULL; } # endif /* LIBPNG_VER < 10700 */ # endif /* TIME_RFC1123 */ #endif /* READ || WRITE */ png_const_charp PNGAPI png_get_copyright(png_const_structrp png_ptr) { PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ #ifdef PNG_STRING_COPYRIGHT return PNG_STRING_COPYRIGHT #else # ifdef __STDC__ return PNG_STRING_NEWLINE \ "libpng version 1.6.34 - September 29, 2017" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson" \ PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ PNG_STRING_NEWLINE; # else return "libpng version 1.6.34 - September 29, 2017\ Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson\ Copyright (c) 1996-1997 Andreas Dilger\ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; # endif #endif } /* The following return the library version as a short string in the * format 1.0.0 through 99.99.99zz. To get the version of *.h files * used with your application, print out PNG_LIBPNG_VER_STRING, which * is defined in png.h. * Note: now there is no difference between png_get_libpng_ver() and * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard, * it is guaranteed that png.c uses the correct version of png.h. */ png_const_charp PNGAPI png_get_libpng_ver(png_const_structrp png_ptr) { /* Version of *.c files used when building libpng */ return png_get_header_ver(png_ptr); } png_const_charp PNGAPI png_get_header_ver(png_const_structrp png_ptr) { /* Version of *.h files used when building libpng */ PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ return PNG_LIBPNG_VER_STRING; } png_const_charp PNGAPI png_get_header_version(png_const_structrp png_ptr) { /* Returns longer string containing both version and date */ PNG_UNUSED(png_ptr) /* Silence compiler warning about unused png_ptr */ #ifdef __STDC__ return PNG_HEADER_VERSION_STRING # ifndef PNG_READ_SUPPORTED " (NO READ SUPPORT)" # endif PNG_STRING_NEWLINE; #else return PNG_HEADER_VERSION_STRING; #endif } #ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED /* NOTE: this routine is not used internally! */ /* Build a grayscale palette. Palette is assumed to be 1 << bit_depth * large of png_color. This lets grayscale images be treated as * paletted. Most useful for gamma correction and simplification * of code. This API is not used internally. */ void PNGAPI png_build_grayscale_palette(int bit_depth, png_colorp palette) { int num_palette; int color_inc; int i; int v; png_debug(1, "in png_do_build_grayscale_palette"); if (palette == NULL) return; switch (bit_depth) { case 1: num_palette = 2; color_inc = 0xff; break; case 2: num_palette = 4; color_inc = 0x55; break; case 4: num_palette = 16; color_inc = 0x11; break; case 8: num_palette = 256; color_inc = 1; break; default: num_palette = 0; color_inc = 0; break; } for (i = 0, v = 0; i < num_palette; i++, v += color_inc) { palette[i].red = (png_byte)(v & 0xff); palette[i].green = (png_byte)(v & 0xff); palette[i].blue = (png_byte)(v & 0xff); } } #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED int PNGAPI png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) { /* Check chunk_name and return "keep" value if it's on the list, else 0 */ png_const_bytep p, p_end; if (png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list == 0) return PNG_HANDLE_CHUNK_AS_DEFAULT; p_end = png_ptr->chunk_list; p = p_end + png_ptr->num_chunk_list*5; /* beyond end */ /* The code is the fifth byte after each four byte string. Historically this * code was always searched from the end of the list, this is no longer * necessary because the 'set' routine handles duplicate entries correcty. */ do /* num_chunk_list > 0, so at least one */ { p -= 5; if (memcmp(chunk_name, p, 4) == 0) return p[4]; } while (p > p_end); /* This means that known chunks should be processed and unknown chunks should * be handled according to the value of png_ptr->unknown_default; this can be * confusing because, as a result, there are two levels of defaulting for * unknown chunks. */ return PNG_HANDLE_CHUNK_AS_DEFAULT; } #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) int /* PRIVATE */ png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) { png_byte chunk_string[5]; PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name); return png_handle_as_unknown(png_ptr, chunk_string); } #endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ #endif /* SET_UNKNOWN_CHUNKS */ #ifdef PNG_READ_SUPPORTED /* This function, added to libpng-1.0.6g, is untested. */ int PNGAPI png_reset_zstream(png_structrp png_ptr) { if (png_ptr == NULL) return Z_STREAM_ERROR; /* WARNING: this resets the window bits to the maximum! */ return (inflateReset(&png_ptr->zstream)); } #endif /* READ */ /* This function was added to libpng-1.0.7 */ png_uint_32 PNGAPI png_access_version_number(void) { /* Version of *.c files used when building libpng */ return((png_uint_32)PNG_LIBPNG_VER); } #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) /* Ensure that png_ptr->zstream.msg holds some appropriate error message string. * If it doesn't 'ret' is used to set it to something appropriate, even in cases * like Z_OK or Z_STREAM_END where the error code is apparently a success code. */ void /* PRIVATE */ png_zstream_error(png_structrp png_ptr, int ret) { /* Translate 'ret' into an appropriate error string, priority is given to the * one in zstream if set. This always returns a string, even in cases like * Z_OK or Z_STREAM_END where the error code is a success code. */ if (png_ptr->zstream.msg == NULL) switch (ret) { default: case Z_OK: png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return code"); break; case Z_STREAM_END: /* Normal exit */ png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected end of LZ stream"); break; case Z_NEED_DICT: /* This means the deflate stream did not have a dictionary; this * indicates a bogus PNG. */ png_ptr->zstream.msg = PNGZ_MSG_CAST("missing LZ dictionary"); break; case Z_ERRNO: /* gz APIs only: should not happen */ png_ptr->zstream.msg = PNGZ_MSG_CAST("zlib IO error"); break; case Z_STREAM_ERROR: /* internal libpng error */ png_ptr->zstream.msg = PNGZ_MSG_CAST("bad parameters to zlib"); break; case Z_DATA_ERROR: png_ptr->zstream.msg = PNGZ_MSG_CAST("damaged LZ stream"); break; case Z_MEM_ERROR: png_ptr->zstream.msg = PNGZ_MSG_CAST("insufficient memory"); break; case Z_BUF_ERROR: /* End of input or output; not a problem if the caller is doing * incremental read or write. */ png_ptr->zstream.msg = PNGZ_MSG_CAST("truncated"); break; case Z_VERSION_ERROR: png_ptr->zstream.msg = PNGZ_MSG_CAST("unsupported zlib version"); break; case PNG_UNEXPECTED_ZLIB_RETURN: /* Compile errors here mean that zlib now uses the value co-opted in * pngpriv.h for PNG_UNEXPECTED_ZLIB_RETURN; update the switch above * and change pngpriv.h. Note that this message is "... return", * whereas the default/Z_OK one is "... return code". */ png_ptr->zstream.msg = PNGZ_MSG_CAST("unexpected zlib return"); break; } } /* png_convert_size: a PNGAPI but no longer in png.h, so deleted * at libpng 1.5.5! */ /* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ #ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */ static int png_colorspace_check_gamma(png_const_structrp png_ptr, png_colorspacerp colorspace, png_fixed_point gAMA, int from) /* This is called to check a new gamma value against an existing one. The * routine returns false if the new gamma value should not be written. * * 'from' says where the new gamma value comes from: * * 0: the new gamma value is the libpng estimate for an ICC profile * 1: the new gamma value comes from a gAMA chunk * 2: the new gamma value comes from an sRGB chunk */ { png_fixed_point gtest; if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && (png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) == 0 || png_gamma_significant(gtest) != 0)) { /* Either this is an sRGB image, in which case the calculated gamma * approximation should match, or this is an image with a profile and the * value libpng calculates for the gamma of the profile does not match the * value recorded in the file. The former, sRGB, case is an error, the * latter is just a warning. */ if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2) { png_chunk_report(png_ptr, "gamma value does not match sRGB", PNG_CHUNK_ERROR); /* Do not overwrite an sRGB value */ return from == 2; } else /* sRGB tag not involved */ { png_chunk_report(png_ptr, "gamma value does not match libpng estimate", PNG_CHUNK_WARNING); return from == 1; } } return 1; } void /* PRIVATE */ png_colorspace_set_gamma(png_const_structrp png_ptr, png_colorspacerp colorspace, png_fixed_point gAMA) { /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't * occur. Since the fixed point representation is asymetrical it is * possible for 1/gamma to overflow the limit of 21474 and this means the * gamma value must be at least 5/100000 and hence at most 20000.0. For * safety the limits here are a little narrower. The values are 0.00016 to * 6250.0, which are truly ridiculous gamma values (and will produce * displays that are all black or all white.) * * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk * handling code, which only required the value to be >0. */ png_const_charp errmsg; if (gAMA < 16 || gAMA > 625000000) errmsg = "gamma value out of range"; # ifdef PNG_READ_gAMA_SUPPORTED /* Allow the application to set the gamma value more than once */ else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0) errmsg = "duplicate"; # endif /* Do nothing if the colorspace is already invalid */ else if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) return; else { if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, 1/*from gAMA*/) != 0) { /* Store this gamma value. */ colorspace->gamma = gAMA; colorspace->flags |= (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA); } /* At present if the check_gamma test fails the gamma of the colorspace is * not updated however the colorspace is not invalidated. This * corresponds to the case where the existing gamma comes from an sRGB * chunk or profile. An error message has already been output. */ return; } /* Error exit - errmsg has been set. */ colorspace->flags |= PNG_COLORSPACE_INVALID; png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR); } void /* PRIVATE */ png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr) { if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) { /* Everything is invalid */ info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB| PNG_INFO_iCCP); # ifdef PNG_COLORSPACE_SUPPORTED /* Clean up the iCCP profile now if it won't be used. */ png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/); # else PNG_UNUSED(png_ptr) # endif } else { # ifdef PNG_COLORSPACE_SUPPORTED /* Leave the INFO_iCCP flag set if the pngset.c code has already set * it; this allows a PNG to contain a profile which matches sRGB and * yet still have that profile retrievable by the application. */ if ((info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) != 0) info_ptr->valid |= PNG_INFO_sRGB; else info_ptr->valid &= ~PNG_INFO_sRGB; if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) info_ptr->valid |= PNG_INFO_cHRM; else info_ptr->valid &= ~PNG_INFO_cHRM; # endif if ((info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0) info_ptr->valid |= PNG_INFO_gAMA; else info_ptr->valid &= ~PNG_INFO_gAMA; } } #ifdef PNG_READ_SUPPORTED void /* PRIVATE */ png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) { if (info_ptr == NULL) /* reduce code size; check here not in the caller */ return; info_ptr->colorspace = png_ptr->colorspace; png_colorspace_sync_info(png_ptr, info_ptr); } #endif #endif /* GAMMA */ #ifdef PNG_COLORSPACE_SUPPORTED /* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for * cHRM, as opposed to using chromaticities. These internal APIs return * non-zero on a parameter error. The X, Y and Z values are required to be * positive and less than 1.0. */ static int png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) { png_int_32 d, dwhite, whiteX, whiteY; d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z; if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d) == 0) return 1; if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d) == 0) return 1; dwhite = d; whiteX = XYZ->red_X; whiteY = XYZ->red_Y; d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z; if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d) == 0) return 1; if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d) == 0) return 1; dwhite += d; whiteX += XYZ->green_X; whiteY += XYZ->green_Y; d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z; if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d) == 0) return 1; if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d) == 0) return 1; dwhite += d; whiteX += XYZ->blue_X; whiteY += XYZ->blue_Y; /* The reference white is simply the sum of the end-point (X,Y,Z) vectors, * thus: */ if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0) return 1; if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0) return 1; return 0; } static int png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) { png_fixed_point red_inverse, green_inverse, blue_scale; png_fixed_point left, right, denominator; /* Check xy and, implicitly, z. Note that wide gamut color spaces typically * have end points with 0 tristimulus values (these are impossible end * points, but they are used to cover the possible colors). We check * xy->whitey against 5, not 0, to avoid a possible integer overflow. */ if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1; if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1; if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1; if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1; if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1; if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1; if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1; if (xy->whitey < 5 || xy->whitey > PNG_FP_1-xy->whitex) return 1; /* The reverse calculation is more difficult because the original tristimulus * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 * derived values were recorded in the cHRM chunk; * (red,green,blue,white)x(x,y). This loses one degree of freedom and * therefore an arbitrary ninth value has to be introduced to undo the * original transformations. * * Think of the original end-points as points in (X,Y,Z) space. The * chromaticity values (c) have the property: * * C * c = --------- * X + Y + Z * * For each c (x,y,z) from the corresponding original C (X,Y,Z). Thus the * three chromaticity values (x,y,z) for each end-point obey the * relationship: * * x + y + z = 1 * * This describes the plane in (X,Y,Z) space that intersects each axis at the * value 1.0; call this the chromaticity plane. Thus the chromaticity * calculation has scaled each end-point so that it is on the x+y+z=1 plane * and chromaticity is the intersection of the vector from the origin to the * (X,Y,Z) value with the chromaticity plane. * * To fully invert the chromaticity calculation we would need the three * end-point scale factors, (red-scale, green-scale, blue-scale), but these * were not recorded. Instead we calculated the reference white (X,Y,Z) and * recorded the chromaticity of this. The reference white (X,Y,Z) would have * given all three of the scale factors since: * * color-C = color-c * color-scale * white-C = red-C + green-C + blue-C * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale * * But cHRM records only white-x and white-y, so we have lost the white scale * factor: * * white-C = white-c*white-scale * * To handle this the inverse transformation makes an arbitrary assumption * about white-scale: * * Assume: white-Y = 1.0 * Hence: white-scale = 1/white-y * Or: red-Y + green-Y + blue-Y = 1.0 * * Notice the last statement of the assumption gives an equation in three of * the nine values we want to calculate. 8 more equations come from the * above routine as summarised at the top above (the chromaticity * calculation): * * Given: color-x = color-X / (color-X + color-Y + color-Z) * Hence: (color-x - 1)*color-X + color.x*color-Y + color.x*color-Z = 0 * * This is 9 simultaneous equations in the 9 variables "color-C" and can be * solved by Cramer's rule. Cramer's rule requires calculating 10 9x9 matrix * determinants, however this is not as bad as it seems because only 28 of * the total of 90 terms in the various matrices are non-zero. Nevertheless * Cramer's rule is notoriously numerically unstable because the determinant * calculation involves the difference of large, but similar, numbers. It is * difficult to be sure that the calculation is stable for real world values * and it is certain that it becomes unstable where the end points are close * together. * * So this code uses the perhaps slightly less optimal but more * understandable and totally obvious approach of calculating color-scale. * * This algorithm depends on the precision in white-scale and that is * (1/white-y), so we can immediately see that as white-y approaches 0 the * accuracy inherent in the cHRM chunk drops off substantially. * * libpng arithmetic: a simple inversion of the above equations * ------------------------------------------------------------ * * white_scale = 1/white-y * white-X = white-x * white-scale * white-Y = 1.0 * white-Z = (1 - white-x - white-y) * white_scale * * white-C = red-C + green-C + blue-C * = red-c*red-scale + green-c*green-scale + blue-c*blue-scale * * This gives us three equations in (red-scale,green-scale,blue-scale) where * all the coefficients are now known: * * red-x*red-scale + green-x*green-scale + blue-x*blue-scale * = white-x/white-y * red-y*red-scale + green-y*green-scale + blue-y*blue-scale = 1 * red-z*red-scale + green-z*green-scale + blue-z*blue-scale * = (1 - white-x - white-y)/white-y * * In the last equation color-z is (1 - color-x - color-y) so we can add all * three equations together to get an alternative third: * * red-scale + green-scale + blue-scale = 1/white-y = white-scale * * So now we have a Cramer's rule solution where the determinants are just * 3x3 - far more tractible. Unfortunately 3x3 determinants still involve * multiplication of three coefficients so we can't guarantee to avoid * overflow in the libpng fixed point representation. Using Cramer's rule in * floating point is probably a good choice here, but it's not an option for * fixed point. Instead proceed to simplify the first two equations by * eliminating what is likely to be the largest value, blue-scale: * * blue-scale = white-scale - red-scale - green-scale * * Hence: * * (red-x - blue-x)*red-scale + (green-x - blue-x)*green-scale = * (white-x - blue-x)*white-scale * * (red-y - blue-y)*red-scale + (green-y - blue-y)*green-scale = * 1 - blue-y*white-scale * * And now we can trivially solve for (red-scale,green-scale): * * green-scale = * (white-x - blue-x)*white-scale - (red-x - blue-x)*red-scale * ----------------------------------------------------------- * green-x - blue-x * * red-scale = * 1 - blue-y*white-scale - (green-y - blue-y) * green-scale * --------------------------------------------------------- * red-y - blue-y * * Hence: * * red-scale = * ( (green-x - blue-x) * (white-y - blue-y) - * (green-y - blue-y) * (white-x - blue-x) ) / white-y * ------------------------------------------------------------------------- * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) * * green-scale = * ( (red-y - blue-y) * (white-x - blue-x) - * (red-x - blue-x) * (white-y - blue-y) ) / white-y * ------------------------------------------------------------------------- * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) * * Accuracy: * The input values have 5 decimal digits of accuracy. The values are all in * the range 0 < value < 1, so simple products are in the same range but may * need up to 10 decimal digits to preserve the original precision and avoid * underflow. Because we are using a 32-bit signed representation we cannot * match this; the best is a little over 9 decimal digits, less than 10. * * The approach used here is to preserve the maximum precision within the * signed representation. Because the red-scale calculation above uses the * difference between two products of values that must be in the range -1..+1 * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The * factor is irrelevant in the calculation because it is applied to both * numerator and denominator. * * Note that the values of the differences of the products of the * chromaticities in the above equations tend to be small, for example for * the sRGB chromaticities they are: * * red numerator: -0.04751 * green numerator: -0.08788 * denominator: -0.2241 (without white-y multiplication) * * The resultant Y coefficients from the chromaticities of some widely used * color space definitions are (to 15 decimal places): * * sRGB * 0.212639005871510 0.715168678767756 0.072192315360734 * Kodak ProPhoto * 0.288071128229293 0.711843217810102 0.000085653960605 * Adobe RGB * 0.297344975250536 0.627363566255466 0.075291458493998 * Adobe Wide Gamut RGB * 0.258728243040113 0.724682314948566 0.016589442011321 */ /* By the argument, above overflow should be impossible here. The return * value of 2 indicates an internal error to the caller. */ if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7) == 0) return 2; if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7) == 0) return 2; denominator = left - right; /* Now find the red numerator. */ if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) return 2; if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7) == 0) return 2; /* Overflow is possible here and it indicates an extreme set of PNG cHRM * chunk values. This calculation actually returns the reciprocal of the * scale value because this allows us to delay the multiplication of white-y * into the denominator, which tends to produce a small number. */ if (png_muldiv(&red_inverse, xy->whitey, denominator, left-right) == 0 || red_inverse <= xy->whitey /* r+g+b scales = white scale */) return 1; /* Similarly for green_inverse: */ if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7) == 0) return 2; if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7) == 0) return 2; if (png_muldiv(&green_inverse, xy->whitey, denominator, left-right) == 0 || green_inverse <= xy->whitey) return 1; /* And the blue scale, the checks above guarantee this can't overflow but it * can still produce 0 for extreme cHRM values. */ blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) - png_reciprocal(green_inverse); if (blue_scale <= 0) return 1; /* And fill in the png_XYZ: */ if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0) return 1; if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0) return 1; if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, red_inverse) == 0) return 1; if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0) return 1; if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0) return 1; if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, green_inverse) == 0) return 1; if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0) return 1; if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0) return 1; if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, PNG_FP_1) == 0) return 1; return 0; /*success*/ } static int png_XYZ_normalize(png_XYZ *XYZ) { png_int_32 Y; if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 || XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 || XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0) return 1; /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore * relying on addition of two positive values producing a negative one is not * safe. */ Y = XYZ->red_Y; if (0x7fffffff - Y < XYZ->green_X) return 1; Y += XYZ->green_Y; if (0x7fffffff - Y < XYZ->blue_X) return 1; Y += XYZ->blue_Y; if (Y != PNG_FP_1) { if (png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y) == 0) return 1; if (png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y) == 0) return 1; if (png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y) == 0) return 1; if (png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y) == 0) return 1; if (png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y) == 0) return 1; if (png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y) == 0) return 1; if (png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y) == 0) return 1; if (png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y) == 0) return 1; if (png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y) == 0) return 1; } return 0; } static int png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta) { /* Allow an error of +/-0.01 (absolute value) on each chromaticity */ if (PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) || PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) || PNG_OUT_OF_RANGE(xy1->redx, xy2->redx, delta) || PNG_OUT_OF_RANGE(xy1->redy, xy2->redy, delta) || PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) || PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) || PNG_OUT_OF_RANGE(xy1->bluex, xy2->bluex, delta) || PNG_OUT_OF_RANGE(xy1->bluey, xy2->bluey, delta)) return 0; return 1; } /* Added in libpng-1.6.0, a different check for the validity of a set of cHRM * chunk chromaticities. Earlier checks used to simply look for the overflow * condition (where the determinant of the matrix to solve for XYZ ends up zero * because the chromaticity values are not all distinct.) Despite this it is * theoretically possible to produce chromaticities that are apparently valid * but that rapidly degrade to invalid, potentially crashing, sets because of * arithmetic inaccuracies when calculations are performed on them. The new * check is to round-trip xy -> XYZ -> xy and then check that the result is * within a small percentage of the original. */ static int png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy) { int result; png_xy xy_test; /* As a side-effect this routine also returns the XYZ endpoints. */ result = png_XYZ_from_xy(XYZ, xy); if (result != 0) return result; result = png_xy_from_XYZ(&xy_test, XYZ); if (result != 0) return result; if (png_colorspace_endpoints_match(xy, &xy_test, 5/*actually, the math is pretty accurate*/) != 0) return 0; /* Too much slip */ return 1; } /* This is the check going the other way. The XYZ is modified to normalize it * (another side-effect) and the xy chromaticities are returned. */ static int png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ) { int result; png_XYZ XYZtemp; result = png_XYZ_normalize(XYZ); if (result != 0) return result; result = png_xy_from_XYZ(xy, XYZ); if (result != 0) return result; XYZtemp = *XYZ; return png_colorspace_check_xy(&XYZtemp, xy); } /* Used to check for an endpoint match against sRGB */ static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ { /* color x y */ /* red */ 64000, 33000, /* green */ 30000, 60000, /* blue */ 15000, 6000, /* white */ 31270, 32900 }; static int png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ, int preferred) { if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) return 0; /* The consistency check is performed on the chromaticities; this factors out * variations because of the normalization (or not) of the end point Y * values. */ if (preferred < 2 && (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { /* The end points must be reasonably close to any we already have. The * following allows an error of up to +/-.001 */ if (png_colorspace_endpoints_match(xy, &colorspace->end_points_xy, 100) == 0) { colorspace->flags |= PNG_COLORSPACE_INVALID; png_benign_error(png_ptr, "inconsistent chromaticities"); return 0; /* failed */ } /* Only overwrite with preferred values */ if (preferred == 0) return 1; /* ok, but no change */ } colorspace->end_points_xy = *xy; colorspace->end_points_XYZ = *XYZ; colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS; /* The end points are normally quoted to two decimal digits, so allow +/-0.01 * on this test. */ if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000) != 0) colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB; else colorspace->flags &= PNG_COLORSPACE_CANCEL( PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); return 2; /* ok and changed */ } int /* PRIVATE */ png_colorspace_set_chromaticities(png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, int preferred) { /* We must check the end points to ensure they are reasonable - in the past * color management systems have crashed as a result of getting bogus * colorant values, while this isn't the fault of libpng it is the * responsibility of libpng because PNG carries the bomb and libpng is in a * position to protect against it. */ png_XYZ XYZ; switch (png_colorspace_check_xy(&XYZ, xy)) { case 0: /* success */ return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ, preferred); case 1: /* We can't invert the chromaticities so we can't produce value XYZ * values. Likely as not a color management system will fail too. */ colorspace->flags |= PNG_COLORSPACE_INVALID; png_benign_error(png_ptr, "invalid chromaticities"); break; default: /* libpng is broken; this should be a warning but if it happens we * want error reports so for the moment it is an error. */ colorspace->flags |= PNG_COLORSPACE_INVALID; png_error(png_ptr, "internal error checking chromaticities"); } return 0; /* failed */ } int /* PRIVATE */ png_colorspace_set_endpoints(png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred) { png_XYZ XYZ = *XYZ_in; png_xy xy; switch (png_colorspace_check_XYZ(&xy, &XYZ)) { case 0: return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ, preferred); case 1: /* End points are invalid. */ colorspace->flags |= PNG_COLORSPACE_INVALID; png_benign_error(png_ptr, "invalid end points"); break; default: colorspace->flags |= PNG_COLORSPACE_INVALID; png_error(png_ptr, "internal error checking chromaticities"); } return 0; /* failed */ } #if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED) /* Error message generation */ static char png_icc_tag_char(png_uint_32 byte) { byte &= 0xff; if (byte >= 32 && byte <= 126) return (char)byte; else return '?'; } static void png_icc_tag_name(char *name, png_uint_32 tag) { name[0] = '\''; name[1] = png_icc_tag_char(tag >> 24); name[2] = png_icc_tag_char(tag >> 16); name[3] = png_icc_tag_char(tag >> 8); name[4] = png_icc_tag_char(tag ); name[5] = '\''; } static int is_ICC_signature_char(png_alloc_size_t it) { return it == 32 || (it >= 48 && it <= 57) || (it >= 65 && it <= 90) || (it >= 97 && it <= 122); } static int is_ICC_signature(png_alloc_size_t it) { return is_ICC_signature_char(it >> 24) /* checks all the top bits */ && is_ICC_signature_char((it >> 16) & 0xff) && is_ICC_signature_char((it >> 8) & 0xff) && is_ICC_signature_char(it & 0xff); } static int png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_alloc_size_t value, png_const_charp reason) { size_t pos; char message[196]; /* see below for calculation */ if (colorspace != NULL) colorspace->flags |= PNG_COLORSPACE_INVALID; pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */ pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */ pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */ if (is_ICC_signature(value) != 0) { /* So 'value' is at most 4 bytes and the following cast is safe */ png_icc_tag_name(message+pos, (png_uint_32)value); pos += 6; /* total +8; less than the else clause */ message[pos++] = ':'; message[pos++] = ' '; } # ifdef PNG_WARNINGS_SUPPORTED else { char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/ pos = png_safecat(message, (sizeof message), pos, png_format_number(number, number+(sizeof number), PNG_NUMBER_FORMAT_x, value)); pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/ } # endif /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ pos = png_safecat(message, (sizeof message), pos, reason); PNG_UNUSED(pos) /* This is recoverable, but make it unconditionally an app_error on write to * avoid writing invalid ICC profiles into PNG files (i.e., we handle them * on read, with a warning, but on write unless the app turns off * application errors the PNG won't be written.) */ png_chunk_report(png_ptr, message, (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR); return 0; } #endif /* sRGB || iCCP */ #ifdef PNG_sRGB_SUPPORTED int /* PRIVATE */ png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, int intent) { /* sRGB sets known gamma, end points and (from the chunk) intent. */ /* IMPORTANT: these are not necessarily the values found in an ICC profile * because ICC profiles store values adapted to a D50 environment; it is * expected that the ICC profile mediaWhitePointTag will be D50; see the * checks and code elsewhere to understand this better. * * These XYZ values, which are accurate to 5dp, produce rgb to gray * coefficients of (6968,23435,2366), which are reduced (because they add up * to 32769 not 32768) to (6968,23434,2366). These are the values that * libpng has traditionally used (and are the best values given the 15bit * algorithm used by the rgb to gray code.) */ static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */ { /* color X Y Z */ /* red */ 41239, 21264, 1933, /* green */ 35758, 71517, 11919, /* blue */ 18048, 7219, 95053 }; /* Do nothing if the colorspace is already invalidated. */ if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) return 0; /* Check the intent, then check for existing settings. It is valid for the * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must * be consistent with the correct values. If, however, this function is * called below because an iCCP chunk matches sRGB then it is quite * conceivable that an older app recorded incorrect gAMA and cHRM because of * an incorrect calculation based on the values in the profile - this does * *not* invalidate the profile (though it still produces an error, which can * be ignored.) */ if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST) return png_icc_profile_error(png_ptr, colorspace, "sRGB", (png_alloc_size_t)intent, "invalid sRGB rendering intent"); if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 && colorspace->rendering_intent != intent) return png_icc_profile_error(png_ptr, colorspace, "sRGB", (png_alloc_size_t)intent, "inconsistent rendering intents"); if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0) { png_benign_error(png_ptr, "duplicate sRGB information ignored"); return 0; } /* If the standard sRGB cHRM chunk does not match the one from the PNG file * warn but overwrite the value with the correct one. */ if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 && !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy, 100)) png_chunk_report(png_ptr, "cHRM chunk does not match sRGB", PNG_CHUNK_ERROR); /* This check is just done for the error reporting - the routine always * returns true when the 'from' argument corresponds to sRGB (2). */ (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE, 2/*from sRGB*/); /* intent: bugs in GCC force 'int' to be used as the parameter type. */ colorspace->rendering_intent = (png_uint_16)intent; colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT; /* endpoints */ colorspace->end_points_xy = sRGB_xy; colorspace->end_points_XYZ = sRGB_XYZ; colorspace->flags |= (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); /* gamma */ colorspace->gamma = PNG_GAMMA_sRGB_INVERSE; colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA; /* Finally record that we have an sRGB profile */ colorspace->flags |= (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB); return 1; /* set */ } #endif /* sRGB */ #ifdef PNG_iCCP_SUPPORTED /* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value * is XYZ(0.9642,1.0,0.8249), which scales to: * * (63189.8112, 65536, 54060.6464) */ static const png_byte D50_nCIEXYZ[12] = { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d }; static int /* bool */ icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length) { if (profile_length < 132) return png_icc_profile_error(png_ptr, colorspace, name, profile_length, "too short"); return 1; } #ifdef PNG_READ_iCCP_SUPPORTED int /* PRIVATE */ png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length) { if (!icc_check_length(png_ptr, colorspace, name, profile_length)) return 0; /* This needs to be here because the 'normal' check is in * png_decompress_chunk, yet this happens after the attempt to * png_malloc_base the required data. We only need this on read; on write * the caller supplies the profile buffer so libpng doesn't allocate it. See * the call to icc_check_length below (the write case). */ # ifdef PNG_SET_USER_LIMITS_SUPPORTED else if (png_ptr->user_chunk_malloc_max > 0 && png_ptr->user_chunk_malloc_max < profile_length) return png_icc_profile_error(png_ptr, colorspace, name, profile_length, "exceeds application limits"); # elif PNG_USER_CHUNK_MALLOC_MAX > 0 else if (PNG_USER_CHUNK_MALLOC_MAX < profile_length) return png_icc_profile_error(png_ptr, colorspace, name, profile_length, "exceeds libpng limits"); # else /* !SET_USER_LIMITS */ /* This will get compiled out on all 32-bit and better systems. */ else if (PNG_SIZE_MAX < profile_length) return png_icc_profile_error(png_ptr, colorspace, name, profile_length, "exceeds system limits"); # endif /* !SET_USER_LIMITS */ return 1; } #endif /* READ_iCCP */ int /* PRIVATE */ png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length, png_const_bytep profile/* first 132 bytes only */, int color_type) { png_uint_32 temp; /* Length check; this cannot be ignored in this code because profile_length * is used later to check the tag table, so even if the profile seems over * long profile_length from the caller must be correct. The caller can fix * this up on read or write by just passing in the profile header length. */ temp = png_get_uint_32(profile); if (temp != profile_length) return png_icc_profile_error(png_ptr, colorspace, name, temp, "length does not match profile"); temp = (png_uint_32) (*(profile+8)); if (temp > 3 && (profile_length & 3)) return png_icc_profile_error(png_ptr, colorspace, name, profile_length, "invalid length"); temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */ if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */ profile_length < 132+12*temp) /* truncated tag table */ return png_icc_profile_error(png_ptr, colorspace, name, temp, "tag count too large"); /* The 'intent' must be valid or we can't store it, ICC limits the intent to * 16 bits. */ temp = png_get_uint_32(profile+64); if (temp >= 0xffff) /* The ICC limit */ return png_icc_profile_error(png_ptr, colorspace, name, temp, "invalid rendering intent"); /* This is just a warning because the profile may be valid in future * versions. */ if (temp >= PNG_sRGB_INTENT_LAST) (void)png_icc_profile_error(png_ptr, NULL, name, temp, "intent outside defined range"); /* At this point the tag table can't be checked because it hasn't necessarily * been loaded; however, various header fields can be checked. These checks * are for values permitted by the PNG spec in an ICC profile; the PNG spec * restricts the profiles that can be passed in an iCCP chunk (they must be * appropriate to processing PNG data!) */ /* Data checks (could be skipped). These checks must be independent of the * version number; however, the version number doesn't accomodate changes in * the header fields (just the known tags and the interpretation of the * data.) */ temp = png_get_uint_32(profile+36); /* signature 'ascp' */ if (temp != 0x61637370) return png_icc_profile_error(png_ptr, colorspace, name, temp, "invalid signature"); /* Currently the PCS illuminant/adopted white point (the computational * white point) are required to be D50, * however the profile contains a record of the illuminant so perhaps ICC * expects to be able to change this in the future (despite the rationale in * the introduction for using a fixed PCS adopted white.) Consequently the * following is just a warning. */ if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0) (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/, "PCS illuminant is not D50"); /* The PNG spec requires this: * "If the iCCP chunk is present, the image samples conform to the colour * space represented by the embedded ICC profile as defined by the * International Color Consortium [ICC]. The colour space of the ICC profile * shall be an RGB colour space for colour images (PNG colour types 2, 3, and * 6), or a greyscale colour space for greyscale images (PNG colour types 0 * and 4)." * * This checking code ensures the embedded profile (on either read or write) * conforms to the specification requirements. Notice that an ICC 'gray' * color-space profile contains the information to transform the monochrome * data to XYZ or L*a*b (according to which PCS the profile uses) and this * should be used in preference to the standard libpng K channel replication * into R, G and B channels. * * Previously it was suggested that an RGB profile on grayscale data could be * handled. However it it is clear that using an RGB profile in this context * must be an error - there is no specification of what it means. Thus it is * almost certainly more correct to ignore the profile. */ temp = png_get_uint_32(profile+16); /* data colour space field */ switch (temp) { case 0x52474220: /* 'RGB ' */ if ((color_type & PNG_COLOR_MASK_COLOR) == 0) return png_icc_profile_error(png_ptr, colorspace, name, temp, "RGB color space not permitted on grayscale PNG"); break; case 0x47524159: /* 'GRAY' */ if ((color_type & PNG_COLOR_MASK_COLOR) != 0) return png_icc_profile_error(png_ptr, colorspace, name, temp, "Gray color space not permitted on RGB PNG"); break; default: return png_icc_profile_error(png_ptr, colorspace, name, temp, "invalid ICC profile color space"); } /* It is up to the application to check that the profile class matches the * application requirements; the spec provides no guidance, but it's pretty * weird if the profile is not scanner ('scnr'), monitor ('mntr'), printer * ('prtr') or 'spac' (for generic color spaces). Issue a warning in these * cases. Issue an error for device link or abstract profiles - these don't * contain the records necessary to transform the color-space to anything * other than the target device (and not even that for an abstract profile). * Profiles of these classes may not be embedded in images. */ temp = png_get_uint_32(profile+12); /* profile/device class */ switch (temp) { case 0x73636e72: /* 'scnr' */ case 0x6d6e7472: /* 'mntr' */ case 0x70727472: /* 'prtr' */ case 0x73706163: /* 'spac' */ /* All supported */ break; case 0x61627374: /* 'abst' */ /* May not be embedded in an image */ return png_icc_profile_error(png_ptr, colorspace, name, temp, "invalid embedded Abstract ICC profile"); case 0x6c696e6b: /* 'link' */ /* DeviceLink profiles cannot be interpreted in a non-device specific * fashion, if an app uses the AToB0Tag in the profile the results are * undefined unless the result is sent to the intended device, * therefore a DeviceLink profile should not be found embedded in a * PNG. */ return png_icc_profile_error(png_ptr, colorspace, name, temp, "unexpected DeviceLink ICC profile class"); case 0x6e6d636c: /* 'nmcl' */ /* A NamedColor profile is also device specific, however it doesn't * contain an AToB0 tag that is open to misinterpretation. Almost * certainly it will fail the tests below. */ (void)png_icc_profile_error(png_ptr, NULL, name, temp, "unexpected NamedColor ICC profile class"); break; default: /* To allow for future enhancements to the profile accept unrecognized * profile classes with a warning, these then hit the test below on the * tag content to ensure they are backward compatible with one of the * understood profiles. */ (void)png_icc_profile_error(png_ptr, NULL, name, temp, "unrecognized ICC profile class"); break; } /* For any profile other than a device link one the PCS must be encoded * either in XYZ or Lab. */ temp = png_get_uint_32(profile+20); switch (temp) { case 0x58595a20: /* 'XYZ ' */ case 0x4c616220: /* 'Lab ' */ break; default: return png_icc_profile_error(png_ptr, colorspace, name, temp, "unexpected ICC PCS encoding"); } return 1; } int /* PRIVATE */ png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length, png_const_bytep profile /* header plus whole tag table */) { png_uint_32 tag_count = png_get_uint_32(profile+128); png_uint_32 itag; png_const_bytep tag = profile+132; /* The first tag */ /* First scan all the tags in the table and add bits to the icc_info value * (temporarily in 'tags'). */ for (itag=0; itag < tag_count; ++itag, tag += 12) { png_uint_32 tag_id = png_get_uint_32(tag+0); png_uint_32 tag_start = png_get_uint_32(tag+4); /* must be aligned */ png_uint_32 tag_length = png_get_uint_32(tag+8);/* not padded */ /* The ICC specification does not exclude zero length tags, therefore the * start might actually be anywhere if there is no data, but this would be * a clear abuse of the intent of the standard so the start is checked for * being in range. All defined tag types have an 8 byte header - a 4 byte * type signature then 0. */ /* This is a hard error; potentially it can cause read outside the * profile. */ if (tag_start > profile_length || tag_length > profile_length - tag_start) return png_icc_profile_error(png_ptr, colorspace, name, tag_id, "ICC profile tag outside profile"); if ((tag_start & 3) != 0) { /* CNHP730S.icc shipped with Microsoft Windows 64 violates this; it is * only a warning here because libpng does not care about the * alignment. */ (void)png_icc_profile_error(png_ptr, NULL, name, tag_id, "ICC profile tag start not a multiple of 4"); } } return 1; /* success, maybe with warnings */ } #ifdef PNG_sRGB_SUPPORTED #if PNG_sRGB_PROFILE_CHECKS >= 0 /* Information about the known ICC sRGB profiles */ static const struct { png_uint_32 adler, crc, length; png_uint_32 md5[4]; png_byte have_md5; png_byte is_broken; png_uint_16 intent; # define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0) # define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\ { adler, crc, length, md5, broke, intent }, } png_sRGB_checks[] = { /* This data comes from contrib/tools/checksum-icc run on downloads of * all four ICC sRGB profiles from www.color.org. */ /* adler32, crc32, MD5[4], intent, date, length, file-name */ PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9, PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0, "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc") /* ICC sRGB v2 perceptual no black-compensation: */ PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21, PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0, "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc") PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae, PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0, "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc") /* ICC sRGB v4 perceptual */ PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812, PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0, "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc") /* The following profiles have no known MD5 checksum. If there is a match * on the (empty) MD5 the other fields are used to attempt a match and * a warning is produced. The first two of these profiles have a 'cprt' tag * which suggests that they were also made by Hewlett Packard. */ PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce, PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0, "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc") /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not * match the D50 PCS illuminant in the header (it is in fact the D65 values, * so the white point is recorded as the un-adapted value.) The profiles * below only differ in one byte - the intent - and are basically the same as * the previous profile except for the mediaWhitePointTag error and a missing * chromaticAdaptationTag. */ PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552, PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/, "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual") PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d, PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/, "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative") }; static int png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, png_const_bytep profile, uLong adler) { /* The quick check is to verify just the MD5 signature and trust the * rest of the data. Because the profile has already been verified for * correctness this is safe. png_colorspace_set_sRGB will check the 'intent' * field too, so if the profile has been edited with an intent not defined * by sRGB (but maybe defined by a later ICC specification) the read of * the profile will fail at that point. */ png_uint_32 length = 0; png_uint_32 intent = 0x10000; /* invalid */ #if PNG_sRGB_PROFILE_CHECKS > 1 uLong crc = 0; /* the value for 0 length data */ #endif unsigned int i; #ifdef PNG_SET_OPTION_SUPPORTED /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */ if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) == PNG_OPTION_ON) return 0; #endif for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i) { if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] && png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] && png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] && png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3]) { /* This may be one of the old HP profiles without an MD5, in that * case we can only use the length and Adler32 (note that these * are not used by default if there is an MD5!) */ # if PNG_sRGB_PROFILE_CHECKS == 0 if (png_sRGB_checks[i].have_md5 != 0) return 1+png_sRGB_checks[i].is_broken; # endif /* Profile is unsigned or more checks have been configured in. */ if (length == 0) { length = png_get_uint_32(profile); intent = png_get_uint_32(profile+64); } /* Length *and* intent must match */ if (length == (png_uint_32) png_sRGB_checks[i].length && intent == (png_uint_32) png_sRGB_checks[i].intent) { /* Now calculate the adler32 if not done already. */ if (adler == 0) { adler = adler32(0, NULL, 0); adler = adler32(adler, profile, length); } if (adler == png_sRGB_checks[i].adler) { /* These basic checks suggest that the data has not been * modified, but if the check level is more than 1 perform * our own crc32 checksum on the data. */ # if PNG_sRGB_PROFILE_CHECKS > 1 if (crc == 0) { crc = crc32(0, NULL, 0); crc = crc32(crc, profile, length); } /* So this check must pass for the 'return' below to happen. */ if (crc == png_sRGB_checks[i].crc) # endif { if (png_sRGB_checks[i].is_broken != 0) { /* These profiles are known to have bad data that may cause * problems if they are used, therefore attempt to * discourage their use, skip the 'have_md5' warning below, * which is made irrelevant by this error. */ png_chunk_report(png_ptr, "known incorrect sRGB profile", PNG_CHUNK_ERROR); } /* Warn that this being done; this isn't even an error since * the profile is perfectly valid, but it would be nice if * people used the up-to-date ones. */ else if (png_sRGB_checks[i].have_md5 == 0) { png_chunk_report(png_ptr, "out-of-date sRGB profile with no signature", PNG_CHUNK_WARNING); } return 1+png_sRGB_checks[i].is_broken; } } # if PNG_sRGB_PROFILE_CHECKS > 0 /* The signature matched, but the profile had been changed in some * way. This probably indicates a data error or uninformed hacking. * Fall through to "no match". */ png_chunk_report(png_ptr, "Not recognizing known sRGB profile that has been edited", PNG_CHUNK_WARNING); break; # endif } } } return 0; /* no match */ } void /* PRIVATE */ png_icc_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_bytep profile, uLong adler) { /* Is this profile one of the known ICC sRGB profiles? If it is, just set * the sRGB information. */ if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler) != 0) (void)png_colorspace_set_sRGB(png_ptr, colorspace, (int)/*already checked*/png_get_uint_32(profile+64)); } #endif /* PNG_sRGB_PROFILE_CHECKS >= 0 */ #endif /* sRGB */ int /* PRIVATE */ png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length, png_const_bytep profile, int color_type) { if ((colorspace->flags & PNG_COLORSPACE_INVALID) != 0) return 0; if (icc_check_length(png_ptr, colorspace, name, profile_length) != 0 && png_icc_check_header(png_ptr, colorspace, name, profile_length, profile, color_type) != 0 && png_icc_check_tag_table(png_ptr, colorspace, name, profile_length, profile) != 0) { # if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0 /* If no sRGB support, don't try storing sRGB information */ png_icc_set_sRGB(png_ptr, colorspace, profile, 0); # endif return 1; } /* Failure case */ return 0; } #endif /* iCCP */ #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED void /* PRIVATE */ png_colorspace_set_rgb_coefficients(png_structrp png_ptr) { /* Set the rgb_to_gray coefficients from the colorspace. */ if (png_ptr->rgb_to_gray_coefficients_set == 0 && (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { /* png_set_background has not been called, get the coefficients from the Y * values of the colorspace colorants. */ png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y; png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y; png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y; png_fixed_point total = r+g+b; if (total > 0 && r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && r+g+b <= 32769) { /* We allow 0 coefficients here. r+g+b may be 32769 if two or * all of the coefficients were rounded up. Handle this by * reducing the *largest* coefficient by 1; this matches the * approach used for the default coefficients in pngrtran.c */ int add = 0; if (r+g+b > 32768) add = -1; else if (r+g+b < 32768) add = 1; if (add != 0) { if (g >= r && g >= b) g += add; else if (r >= g && r >= b) r += add; else b += add; } /* Check for an internal error. */ if (r+g+b != 32768) png_error(png_ptr, "internal error handling cHRM coefficients"); else { png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; } } /* This is a png_error at present even though it could be ignored - * it should never happen, but it is important that if it does, the * bug is fixed. */ else png_error(png_ptr, "internal error handling cHRM->XYZ"); } } #endif /* READ_RGB_TO_GRAY */ #endif /* COLORSPACE */ #ifdef __GNUC__ /* This exists solely to work round a warning from GNU C. */ static int /* PRIVATE */ png_gt(size_t a, size_t b) { return a > b; } #else # define png_gt(a,b) ((a) > (b)) #endif void /* PRIVATE */ png_check_IHDR(png_const_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, int filter_type) { int error = 0; /* Check for width and height valid values */ if (width == 0) { png_warning(png_ptr, "Image width is zero in IHDR"); error = 1; } if (width > PNG_UINT_31_MAX) { png_warning(png_ptr, "Invalid image width in IHDR"); error = 1; } if (png_gt(((width + 7) & (~7U)), ((PNG_SIZE_MAX - 48 /* big_row_buf hack */ - 1) /* filter byte */ / 8) /* 8-byte RGBA pixels */ - 1)) /* extra max_pixel_depth pad */ { /* The size of the row must be within the limits of this architecture. * Because the read code can perform arbitrary transformations the * maximum size is checked here. Because the code in png_read_start_row * adds extra space "for safety's sake" in several places a conservative * limit is used here. * * NOTE: it would be far better to check the size that is actually used, * but the effect in the real world is minor and the changes are more * extensive, therefore much more dangerous and much more difficult to * write in a way that avoids compiler warnings. */ png_warning(png_ptr, "Image width is too large for this architecture"); error = 1; } #ifdef PNG_SET_USER_LIMITS_SUPPORTED if (width > png_ptr->user_width_max) #else if (width > PNG_USER_WIDTH_MAX) #endif { png_warning(png_ptr, "Image width exceeds user limit in IHDR"); error = 1; } if (height == 0) { png_warning(png_ptr, "Image height is zero in IHDR"); error = 1; } if (height > PNG_UINT_31_MAX) { png_warning(png_ptr, "Invalid image height in IHDR"); error = 1; } #ifdef PNG_SET_USER_LIMITS_SUPPORTED if (height > png_ptr->user_height_max) #else if (height > PNG_USER_HEIGHT_MAX) #endif { png_warning(png_ptr, "Image height exceeds user limit in IHDR"); error = 1; } /* Check other values */ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && bit_depth != 8 && bit_depth != 16) { png_warning(png_ptr, "Invalid bit depth in IHDR"); error = 1; } if (color_type < 0 || color_type == 1 || color_type == 5 || color_type > 6) { png_warning(png_ptr, "Invalid color type in IHDR"); error = 1; } if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) || ((color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8)) { png_warning(png_ptr, "Invalid color type/bit depth combination in IHDR"); error = 1; } if (interlace_type >= PNG_INTERLACE_LAST) { png_warning(png_ptr, "Unknown interlace method in IHDR"); error = 1; } if (compression_type != PNG_COMPRESSION_TYPE_BASE) { png_warning(png_ptr, "Unknown compression method in IHDR"); error = 1; } #ifdef PNG_MNG_FEATURES_SUPPORTED /* Accept filter_method 64 (intrapixel differencing) only if * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and * 2. Libpng did not read a PNG signature (this filter_method is only * used in PNG datastreams that are embedded in MNG datastreams) and * 3. The application called png_permit_mng_features with a mask that * included PNG_FLAG_MNG_FILTER_64 and * 4. The filter_method is 64 and * 5. The color_type is RGB or RGBA */ if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && png_ptr->mng_features_permitted != 0) png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); if (filter_type != PNG_FILTER_TYPE_BASE) { if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA))) { png_warning(png_ptr, "Unknown filter method in IHDR"); error = 1; } if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0) { png_warning(png_ptr, "Invalid filter method in IHDR"); error = 1; } } #else if (filter_type != PNG_FILTER_TYPE_BASE) { png_warning(png_ptr, "Unknown filter method in IHDR"); error = 1; } #endif if (error == 1) png_error(png_ptr, "Invalid IHDR data"); } #if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) /* ASCII to fp functions */ /* Check an ASCII formated floating point value, see the more detailed * comments in pngpriv.h */ /* The following is used internally to preserve the sticky flags */ #define png_fp_add(state, flags) ((state) |= (flags)) #define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY)) int /* PRIVATE */ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, png_size_tp whereami) { int state = *statep; png_size_t i = *whereami; while (i < size) { int type; /* First find the type of the next character */ switch (string[i]) { case 43: type = PNG_FP_SAW_SIGN; break; case 45: type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break; case 46: type = PNG_FP_SAW_DOT; break; case 48: type = PNG_FP_SAW_DIGIT; break; case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break; case 69: case 101: type = PNG_FP_SAW_E; break; default: goto PNG_FP_End; } /* Now deal with this type according to the current * state, the type is arranged to not overlap the * bits of the PNG_FP_STATE. */ switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) { case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: if ((state & PNG_FP_SAW_ANY) != 0) goto PNG_FP_End; /* not a part of the number */ png_fp_add(state, type); break; case PNG_FP_INTEGER + PNG_FP_SAW_DOT: /* Ok as trailer, ok as lead of fraction. */ if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */ goto PNG_FP_End; else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */ png_fp_add(state, type); else png_fp_set(state, PNG_FP_FRACTION | type); break; case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */ png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); png_fp_add(state, type | PNG_FP_WAS_VALID); break; case PNG_FP_INTEGER + PNG_FP_SAW_E: if ((state & PNG_FP_SAW_DIGIT) == 0) goto PNG_FP_End; png_fp_set(state, PNG_FP_EXPONENT); break; /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN: goto PNG_FP_End; ** no sign in fraction */ /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT: goto PNG_FP_End; ** Because SAW_DOT is always set */ case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT: png_fp_add(state, type | PNG_FP_WAS_VALID); break; case PNG_FP_FRACTION + PNG_FP_SAW_E: /* This is correct because the trailing '.' on an * integer is handled above - so we can only get here * with the sequence ".E" (with no preceding digits). */ if ((state & PNG_FP_SAW_DIGIT) == 0) goto PNG_FP_End; png_fp_set(state, PNG_FP_EXPONENT); break; case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: if ((state & PNG_FP_SAW_ANY) != 0) goto PNG_FP_End; /* not a part of the number */ png_fp_add(state, PNG_FP_SAW_SIGN); break; /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT: goto PNG_FP_End; */ case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT: png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID); break; /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E: goto PNG_FP_End; */ default: goto PNG_FP_End; /* I.e. break 2 */ } /* The character seems ok, continue. */ ++i; } PNG_FP_End: /* Here at the end, update the state and return the correct * return code. */ *statep = state; *whereami = i; return (state & PNG_FP_SAW_DIGIT) != 0; } /* The same but for a complete string. */ int png_check_fp_string(png_const_charp string, png_size_t size) { int state=0; png_size_t char_index=0; if (png_check_fp_number(string, size, &state, &char_index) != 0 && (char_index == size || string[char_index] == 0)) return state /* must be non-zero - see above */; return 0; /* i.e. fail */ } #endif /* pCAL || sCAL */ #ifdef PNG_sCAL_SUPPORTED # ifdef PNG_FLOATING_POINT_SUPPORTED /* Utility used below - a simple accurate power of ten from an integral * exponent. */ static double png_pow10(int power) { int recip = 0; double d = 1; /* Handle negative exponent with a reciprocal at the end because * 10 is exact whereas .1 is inexact in base 2 */ if (power < 0) { if (power < DBL_MIN_10_EXP) return 0; recip = 1; power = -power; } if (power > 0) { /* Decompose power bitwise. */ double mult = 10; do { if (power & 1) d *= mult; mult *= mult; power >>= 1; } while (power > 0); if (recip != 0) d = 1/d; } /* else power is 0 and d is 1 */ return d; } /* Function to format a floating point value in ASCII with a given * precision. */ #if GCC_STRICT_OVERFLOW #pragma GCC diagnostic push /* The problem arises below with exp_b10, which can never overflow because it * comes, originally, from frexp and is therefore limited to a range which is * typically +/-710 (log2(DBL_MAX)/log2(DBL_MIN)). */ #pragma GCC diagnostic warning "-Wstrict-overflow=2" #endif /* GCC_STRICT_OVERFLOW */ void /* PRIVATE */ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, double fp, unsigned int precision) { /* We use standard functions from math.h, but not printf because * that would require stdio. The caller must supply a buffer of * sufficient size or we will png_error. The tests on size and * the space in ascii[] consumed are indicated below. */ if (precision < 1) precision = DBL_DIG; /* Enforce the limit of the implementation precision too. */ if (precision > DBL_DIG+1) precision = DBL_DIG+1; /* Basic sanity checks */ if (size >= precision+5) /* See the requirements below. */ { if (fp < 0) { fp = -fp; *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */ --size; } if (fp >= DBL_MIN && fp <= DBL_MAX) { int exp_b10; /* A base 10 exponent */ double base; /* 10^exp_b10 */ /* First extract a base 10 exponent of the number, * the calculation below rounds down when converting * from base 2 to base 10 (multiply by log10(2) - * 0.3010, but 77/256 is 0.3008, so exp_b10 needs to * be increased. Note that the arithmetic shift * performs a floor() unlike C arithmetic - using a * C multiply would break the following for negative * exponents. */ (void)frexp(fp, &exp_b10); /* exponent to base 2 */ exp_b10 = (exp_b10 * 77) >> 8; /* <= exponent to base 10 */ /* Avoid underflow here. */ base = png_pow10(exp_b10); /* May underflow */ while (base < DBL_MIN || base < fp) { /* And this may overflow. */ double test = png_pow10(exp_b10+1); if (test <= DBL_MAX) { ++exp_b10; base = test; } else break; } /* Normalize fp and correct exp_b10, after this fp is in the * range [.1,1) and exp_b10 is both the exponent and the digit * *before* which the decimal point should be inserted * (starting with 0 for the first digit). Note that this * works even if 10^exp_b10 is out of range because of the * test on DBL_MAX above. */ fp /= base; while (fp >= 1) { fp /= 10; ++exp_b10; } /* Because of the code above fp may, at this point, be * less than .1, this is ok because the code below can * handle the leading zeros this generates, so no attempt * is made to correct that here. */ { unsigned int czero, clead, cdigits; char exponent[10]; /* Allow up to two leading zeros - this will not lengthen * the number compared to using E-n. */ if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */ { czero = 0U-exp_b10; /* PLUS 2 digits: TOTAL 3 */ exp_b10 = 0; /* Dot added below before first output. */ } else czero = 0; /* No zeros to add */ /* Generate the digit list, stripping trailing zeros and * inserting a '.' before a digit if the exponent is 0. */ clead = czero; /* Count of leading zeros */ cdigits = 0; /* Count of digits in list. */ do { double d; fp *= 10; /* Use modf here, not floor and subtract, so that * the separation is done in one step. At the end * of the loop don't break the number into parts so * that the final digit is rounded. */ if (cdigits+czero+1 < precision+clead) fp = modf(fp, &d); else { d = floor(fp + .5); if (d > 9) { /* Rounding up to 10, handle that here. */ if (czero > 0) { --czero; d = 1; if (cdigits == 0) --clead; } else { while (cdigits > 0 && d > 9) { int ch = *--ascii; if (exp_b10 != (-1)) ++exp_b10; else if (ch == 46) { ch = *--ascii; ++size; /* Advance exp_b10 to '1', so that the * decimal point happens after the * previous digit. */ exp_b10 = 1; } --cdigits; d = ch - 47; /* I.e. 1+(ch-48) */ } /* Did we reach the beginning? If so adjust the * exponent but take into account the leading * decimal point. */ if (d > 9) /* cdigits == 0 */ { if (exp_b10 == (-1)) { /* Leading decimal point (plus zeros?), if * we lose the decimal point here it must * be reentered below. */ int ch = *--ascii; if (ch == 46) { ++size; exp_b10 = 1; } /* Else lost a leading zero, so 'exp_b10' is * still ok at (-1) */ } else ++exp_b10; /* In all cases we output a '1' */ d = 1; } } } fp = 0; /* Guarantees termination below. */ } if (d == 0) { ++czero; if (cdigits == 0) ++clead; } else { /* Included embedded zeros in the digit count. */ cdigits += czero - clead; clead = 0; while (czero > 0) { /* exp_b10 == (-1) means we just output the decimal * place - after the DP don't adjust 'exp_b10' any * more! */ if (exp_b10 != (-1)) { if (exp_b10 == 0) { *ascii++ = 46; --size; } /* PLUS 1: TOTAL 4 */ --exp_b10; } *ascii++ = 48; --czero; } if (exp_b10 != (-1)) { if (exp_b10 == 0) { *ascii++ = 46; --size; /* counted above */ } --exp_b10; } *ascii++ = (char)(48 + (int)d); ++cdigits; } } while (cdigits+czero < precision+clead && fp > DBL_MIN); /* The total output count (max) is now 4+precision */ /* Check for an exponent, if we don't need one we are * done and just need to terminate the string. At * this point exp_b10==(-1) is effectively a flag - it got * to '-1' because of the decrement after outputting * the decimal point above (the exponent required is * *not* -1!) */ if (exp_b10 >= (-1) && exp_b10 <= 2) { /* The following only happens if we didn't output the * leading zeros above for negative exponent, so this * doesn't add to the digit requirement. Note that the * two zeros here can only be output if the two leading * zeros were *not* output, so this doesn't increase * the output count. */ while (exp_b10-- > 0) *ascii++ = 48; *ascii = 0; /* Total buffer requirement (including the '\0') is * 5+precision - see check at the start. */ return; } /* Here if an exponent is required, adjust size for * the digits we output but did not count. The total * digit output here so far is at most 1+precision - no * decimal point and no leading or trailing zeros have * been output. */ size -= cdigits; *ascii++ = 69; --size; /* 'E': PLUS 1 TOTAL 2+precision */ /* The following use of an unsigned temporary avoids ambiguities in * the signed arithmetic on exp_b10 and permits GCC at least to do * better optimization. */ { unsigned int uexp_b10; if (exp_b10 < 0) { *ascii++ = 45; --size; /* '-': PLUS 1 TOTAL 3+precision */ uexp_b10 = 0U-exp_b10; } else uexp_b10 = 0U+exp_b10; cdigits = 0; while (uexp_b10 > 0) { exponent[cdigits++] = (char)(48 + uexp_b10 % 10); uexp_b10 /= 10; } } /* Need another size check here for the exponent digits, so * this need not be considered above. */ if (size > cdigits) { while (cdigits > 0) *ascii++ = exponent[--cdigits]; *ascii = 0; return; } } } else if (!(fp >= DBL_MIN)) { *ascii++ = 48; /* '0' */ *ascii = 0; return; } else { *ascii++ = 105; /* 'i' */ *ascii++ = 110; /* 'n' */ *ascii++ = 102; /* 'f' */ *ascii = 0; return; } } /* Here on buffer too small. */ png_error(png_ptr, "ASCII conversion buffer too small"); } #if GCC_STRICT_OVERFLOW #pragma GCC diagnostic pop #endif /* GCC_STRICT_OVERFLOW */ # endif /* FLOATING_POINT */ # ifdef PNG_FIXED_POINT_SUPPORTED /* Function to format a fixed point value in ASCII. */ void /* PRIVATE */ png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, png_size_t size, png_fixed_point fp) { /* Require space for 10 decimal digits, a decimal point, a minus sign and a * trailing \0, 13 characters: */ if (size > 12) { png_uint_32 num; /* Avoid overflow here on the minimum integer. */ if (fp < 0) { *ascii++ = 45; num = (png_uint_32)(-fp); } else num = (png_uint_32)fp; if (num <= 0x80000000) /* else overflowed */ { unsigned int ndigits = 0, first = 16 /* flag value */; char digits[10]; while (num) { /* Split the low digit off num: */ unsigned int tmp = num/10; num -= tmp*10; digits[ndigits++] = (char)(48 + num); /* Record the first non-zero digit, note that this is a number * starting at 1, it's not actually the array index. */ if (first == 16 && num > 0) first = ndigits; num = tmp; } if (ndigits > 0) { while (ndigits > 5) *ascii++ = digits[--ndigits]; /* The remaining digits are fractional digits, ndigits is '5' or * smaller at this point. It is certainly not zero. Check for a * non-zero fractional digit: */ if (first <= 5) { unsigned int i; *ascii++ = 46; /* decimal point */ /* ndigits may be <5 for small numbers, output leading zeros * then ndigits digits to first: */ i = 5; while (ndigits < i) { *ascii++ = 48; --i; } while (ndigits >= first) *ascii++ = digits[--ndigits]; /* Don't output the trailing zeros! */ } } else *ascii++ = 48; /* And null terminate the string: */ *ascii = 0; return; } } /* Here on buffer too small. */ png_error(png_ptr, "ASCII conversion buffer too small"); } # endif /* FIXED_POINT */ #endif /* SCAL */ #if defined(PNG_FLOATING_POINT_SUPPORTED) && \ !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ (defined(PNG_sCAL_SUPPORTED) && \ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) png_fixed_point png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) { double r = floor(100000 * fp + .5); if (r > 2147483647. || r < -2147483648.) png_fixed_error(png_ptr, text); # ifndef PNG_ERROR_TEXT_SUPPORTED PNG_UNUSED(text) # endif return (png_fixed_point)r; } #endif #if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\ defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) /* muldiv functions */ /* This API takes signed arguments and rounds the result to the nearest * integer (or, for a fixed point number - the standard argument - to * the nearest .00001). Overflow and divide by zero are signalled in * the result, a boolean - true on success, false on overflow. */ #if GCC_STRICT_OVERFLOW /* from above */ /* It is not obvious which comparison below gets optimized in such a way that * signed overflow would change the result; looking through the code does not * reveal any tests which have the form GCC complains about, so presumably the * optimizer is moving an add or subtract into the 'if' somewhere. */ #pragma GCC diagnostic push #pragma GCC diagnostic warning "-Wstrict-overflow=2" #endif /* GCC_STRICT_OVERFLOW */ int png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, png_int_32 divisor) { /* Return a * times / divisor, rounded. */ if (divisor != 0) { if (a == 0 || times == 0) { *res = 0; return 1; } else { #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED double r = a; r *= times; r /= divisor; r = floor(r+.5); /* A png_fixed_point is a 32-bit integer. */ if (r <= 2147483647. && r >= -2147483648.) { *res = (png_fixed_point)r; return 1; } #else int negative = 0; png_uint_32 A, T, D; png_uint_32 s16, s32, s00; if (a < 0) negative = 1, A = -a; else A = a; if (times < 0) negative = !negative, T = -times; else T = times; if (divisor < 0) negative = !negative, D = -divisor; else D = divisor; /* Following can't overflow because the arguments only * have 31 bits each, however the result may be 32 bits. */ s16 = (A >> 16) * (T & 0xffff) + (A & 0xffff) * (T >> 16); /* Can't overflow because the a*times bit is only 30 * bits at most. */ s32 = (A >> 16) * (T >> 16) + (s16 >> 16); s00 = (A & 0xffff) * (T & 0xffff); s16 = (s16 & 0xffff) << 16; s00 += s16; if (s00 < s16) ++s32; /* carry */ if (s32 < D) /* else overflow */ { /* s32.s00 is now the 64-bit product, do a standard * division, we know that s32 < D, so the maximum * required shift is 31. */ int bitshift = 32; png_fixed_point result = 0; /* NOTE: signed */ while (--bitshift >= 0) { png_uint_32 d32, d00; if (bitshift > 0) d32 = D >> (32-bitshift), d00 = D << bitshift; else d32 = 0, d00 = D; if (s32 > d32) { if (s00 < d00) --s32; /* carry */ s32 -= d32, s00 -= d00, result += 1<= d00) s32 = 0, s00 -= d00, result += 1<= (D >> 1)) ++result; if (negative != 0) result = -result; /* Check for overflow. */ if ((negative != 0 && result <= 0) || (negative == 0 && result >= 0)) { *res = result; return 1; } } #endif } } return 0; } #if GCC_STRICT_OVERFLOW #pragma GCC diagnostic pop #endif /* GCC_STRICT_OVERFLOW */ #endif /* READ_GAMMA || INCH_CONVERSIONS */ #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) /* The following is for when the caller doesn't much care about the * result. */ png_fixed_point png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times, png_int_32 divisor) { png_fixed_point result; if (png_muldiv(&result, a, times, divisor) != 0) return result; png_warning(png_ptr, "fixed point overflow ignored"); return 0; } #endif #ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */ /* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ png_fixed_point png_reciprocal(png_fixed_point a) { #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED double r = floor(1E10/a+.5); if (r <= 2147483647. && r >= -2147483648.) return (png_fixed_point)r; #else png_fixed_point res; if (png_muldiv(&res, 100000, 100000, a) != 0) return res; #endif return 0; /* error/overflow */ } /* This is the shared test on whether a gamma value is 'significant' - whether * it is worth doing gamma correction. */ int /* PRIVATE */ png_gamma_significant(png_fixed_point gamma_val) { return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; } #endif #ifdef PNG_READ_GAMMA_SUPPORTED #ifdef PNG_16BIT_SUPPORTED /* A local convenience routine. */ static png_fixed_point png_product2(png_fixed_point a, png_fixed_point b) { /* The required result is 1/a * 1/b; the following preserves accuracy. */ #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED double r = a * 1E-5; r *= b; r = floor(r+.5); if (r <= 2147483647. && r >= -2147483648.) return (png_fixed_point)r; #else png_fixed_point res; if (png_muldiv(&res, a, b, 100000) != 0) return res; #endif return 0; /* overflow */ } #endif /* 16BIT */ /* The inverse of the above. */ png_fixed_point png_reciprocal2(png_fixed_point a, png_fixed_point b) { /* The required result is 1/a * 1/b; the following preserves accuracy. */ #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED if (a != 0 && b != 0) { double r = 1E15/a; r /= b; r = floor(r+.5); if (r <= 2147483647. && r >= -2147483648.) return (png_fixed_point)r; } #else /* This may overflow because the range of png_fixed_point isn't symmetric, * but this API is only used for the product of file and screen gamma so it * doesn't matter that the smallest number it can produce is 1/21474, not * 1/100000 */ png_fixed_point res = png_product2(a, b); if (res != 0) return png_reciprocal(res); #endif return 0; /* overflow */ } #endif /* READ_GAMMA */ #ifdef PNG_READ_GAMMA_SUPPORTED /* gamma table code */ #ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Fixed point gamma. * * The code to calculate the tables used below can be found in the shell script * contrib/tools/intgamma.sh * * To calculate gamma this code implements fast log() and exp() calls using only * fixed point arithmetic. This code has sufficient precision for either 8-bit * or 16-bit sample values. * * The tables used here were calculated using simple 'bc' programs, but C double * precision floating point arithmetic would work fine. * * 8-bit log table * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to * 255, so it's the base 2 logarithm of a normalized 8-bit floating point * mantissa. The numbers are 32-bit fractions. */ static const png_uint_32 png_8bit_l2[128] = { 4270715492U, 4222494797U, 4174646467U, 4127164793U, 4080044201U, 4033279239U, 3986864580U, 3940795015U, 3895065449U, 3849670902U, 3804606499U, 3759867474U, 3715449162U, 3671346997U, 3627556511U, 3584073329U, 3540893168U, 3498011834U, 3455425220U, 3413129301U, 3371120137U, 3329393864U, 3287946700U, 3246774933U, 3205874930U, 3165243125U, 3124876025U, 3084770202U, 3044922296U, 3005329011U, 2965987113U, 2926893432U, 2888044853U, 2849438323U, 2811070844U, 2772939474U, 2735041326U, 2697373562U, 2659933400U, 2622718104U, 2585724991U, 2548951424U, 2512394810U, 2476052606U, 2439922311U, 2404001468U, 2368287663U, 2332778523U, 2297471715U, 2262364947U, 2227455964U, 2192742551U, 2158222529U, 2123893754U, 2089754119U, 2055801552U, 2022034013U, 1988449497U, 1955046031U, 1921821672U, 1888774511U, 1855902668U, 1823204291U, 1790677560U, 1758320682U, 1726131893U, 1694109454U, 1662251657U, 1630556815U, 1599023271U, 1567649391U, 1536433567U, 1505374214U, 1474469770U, 1443718700U, 1413119487U, 1382670639U, 1352370686U, 1322218179U, 1292211689U, 1262349810U, 1232631153U, 1203054352U, 1173618059U, 1144320946U, 1115161701U, 1086139034U, 1057251672U, 1028498358U, 999877854U, 971388940U, 943030410U, 914801076U, 886699767U, 858725327U, 830876614U, 803152505U, 775551890U, 748073672U, 720716771U, 693480120U, 666362667U, 639363374U, 612481215U, 585715177U, 559064263U, 532527486U, 506103872U, 479792461U, 453592303U, 427502463U, 401522014U, 375650043U, 349885648U, 324227938U, 298676034U, 273229066U, 247886176U, 222646516U, 197509248U, 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, 24347096U, 0U #if 0 /* The following are the values for 16-bit tables - these work fine for the * 8-bit conversions but produce very slightly larger errors in the 16-bit * log (about 1.2 as opposed to 0.7 absolute error in the final value). To * use these all the shifts below must be adjusted appropriately. */ 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054, 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803, 50170, 49542, 48918, 48298, 47682, 47070, 46462, 45858, 45257, 44661, 44068, 43479, 42894, 42312, 41733, 41159, 40587, 40020, 39455, 38894, 38336, 37782, 37230, 36682, 36137, 35595, 35057, 34521, 33988, 33459, 32932, 32408, 31887, 31369, 30854, 30341, 29832, 29325, 28820, 28319, 27820, 27324, 26830, 26339, 25850, 25364, 24880, 24399, 23920, 23444, 22970, 22499, 22029, 21562, 21098, 20636, 20175, 19718, 19262, 18808, 18357, 17908, 17461, 17016, 16573, 16132, 15694, 15257, 14822, 14390, 13959, 13530, 13103, 12678, 12255, 11834, 11415, 10997, 10582, 10168, 9756, 9346, 8937, 8531, 8126, 7723, 7321, 6921, 6523, 6127, 5732, 5339, 4947, 4557, 4169, 3782, 3397, 3014, 2632, 2251, 1872, 1495, 1119, 744, 372 #endif }; static png_int_32 png_log8bit(unsigned int x) { unsigned int lg2 = 0; /* Each time 'x' is multiplied by 2, 1 must be subtracted off the final log, * because the log is actually negate that means adding 1. The final * returned value thus has the range 0 (for 255 input) to 7.994 (for 1 * input), return -1 for the overflow (log 0) case, - so the result is * always at most 19 bits. */ if ((x &= 0xff) == 0) return -1; if ((x & 0xf0) == 0) lg2 = 4, x <<= 4; if ((x & 0xc0) == 0) lg2 += 2, x <<= 2; if ((x & 0x80) == 0) lg2 += 1, x <<= 1; /* result is at most 19 bits, so this cast is safe: */ return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16)); } /* The above gives exact (to 16 binary places) log2 values for 8-bit images, * for 16-bit images we use the most significant 8 bits of the 16-bit value to * get an approximation then multiply the approximation by a correction factor * determined by the remaining up to 8 bits. This requires an additional step * in the 16-bit case. * * We want log2(value/65535), we have log2(v'/255), where: * * value = v' * 256 + v'' * = v' * f * * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128 * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less * than 258. The final factor also needs to correct for the fact that our 8-bit * value is scaled by 255, whereas the 16-bit values must be scaled by 65535. * * This gives a final formula using a calculated value 'x' which is value/v' and * scaling by 65536 to match the above table: * * log2(x/257) * 65536 * * Since these numbers are so close to '1' we can use simple linear * interpolation between the two end values 256/257 (result -368.61) and 258/257 * (result 367.179). The values used below are scaled by a further 64 to give * 16-bit precision in the interpolation: * * Start (256): -23591 * Zero (257): 0 * End (258): 23499 */ #ifdef PNG_16BIT_SUPPORTED static png_int_32 png_log16bit(png_uint_32 x) { unsigned int lg2 = 0; /* As above, but now the input has 16 bits. */ if ((x &= 0xffff) == 0) return -1; if ((x & 0xff00) == 0) lg2 = 8, x <<= 8; if ((x & 0xf000) == 0) lg2 += 4, x <<= 4; if ((x & 0xc000) == 0) lg2 += 2, x <<= 2; if ((x & 0x8000) == 0) lg2 += 1, x <<= 1; /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional * value. */ lg2 <<= 28; lg2 += (png_8bit_l2[(x>>8)-128]+8) >> 4; /* Now we need to interpolate the factor, this requires a division by the top * 8 bits. Do this with maximum precision. */ x = ((x << 16) + (x >> 9)) / (x >> 8); /* Since we divided by the top 8 bits of 'x' there will be a '1' at 1<<24, * the value at 1<<16 (ignoring this) will be 0 or 1; this gives us exactly * 16 bits to interpolate to get the low bits of the result. Round the * answer. Note that the end point values are scaled by 64 to retain overall * precision and that 'lg2' is current scaled by an extra 12 bits, so adjust * the overall scaling by 6-12. Round at every step. */ x -= 1U << 24; if (x <= 65536U) /* <= '257' */ lg2 += ((23591U * (65536U-x)) + (1U << (16+6-12-1))) >> (16+6-12); else lg2 -= ((23499U * (x-65536U)) + (1U << (16+6-12-1))) >> (16+6-12); /* Safe, because the result can't have more than 20 bits: */ return (png_int_32)((lg2 + 2048) >> 12); } #endif /* 16BIT */ /* The 'exp()' case must invert the above, taking a 20-bit fixed point * logarithmic value and returning a 16 or 8-bit number as appropriate. In * each case only the low 16 bits are relevant - the fraction - since the * integer bits (the top 4) simply determine a shift. * * The worst case is the 16-bit distinction between 65535 and 65534. This * requires perhaps spurious accuracy in the decoding of the logarithm to * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance * of getting this accuracy in practice. * * To deal with this the following exp() function works out the exponent of the * fractional part of the logarithm by using an accurate 32-bit value from the * top four fractional bits then multiplying in the remaining bits. */ static const png_uint_32 png_32bit_exp[16] = { /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, 2553802834U, 2445529972U, 2341847524U, 2242560872U }; /* Adjustment table; provided to explain the numbers in the code below. */ #if 0 for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} 11 44937.64284865548751208448 10 45180.98734845585101160448 9 45303.31936980687359311872 8 45364.65110595323018870784 7 45395.35850361789624614912 6 45410.72259715102037508096 5 45418.40724413220722311168 4 45422.25021786898173001728 3 45424.17186732298419044352 2 45425.13273269940811464704 1 45425.61317555035558641664 0 45425.85339951654943850496 #endif static png_uint_32 png_exp(png_fixed_point x) { if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ { /* Obtain a 4-bit approximation */ png_uint_32 e = png_32bit_exp[(x >> 12) & 0x0f]; /* Incorporate the low 12 bits - these decrease the returned value by * multiplying by a number less than 1 if the bit is set. The multiplier * is determined by the above table and the shift. Notice that the values * converge on 45426 and this is used to allow linear interpolation of the * low bits. */ if (x & 0x800) e -= (((e >> 16) * 44938U) + 16U) >> 5; if (x & 0x400) e -= (((e >> 16) * 45181U) + 32U) >> 6; if (x & 0x200) e -= (((e >> 16) * 45303U) + 64U) >> 7; if (x & 0x100) e -= (((e >> 16) * 45365U) + 128U) >> 8; if (x & 0x080) e -= (((e >> 16) * 45395U) + 256U) >> 9; if (x & 0x040) e -= (((e >> 16) * 45410U) + 512U) >> 10; /* And handle the low 6 bits in a single block. */ e -= (((e >> 16) * 355U * (x & 0x3fU)) + 256U) >> 9; /* Handle the upper bits of x. */ e >>= x >> 16; return e; } /* Check for overflow */ if (x <= 0) return png_32bit_exp[0]; /* Else underflow */ return 0; } static png_byte png_exp8bit(png_fixed_point lg2) { /* Get a 32-bit value: */ png_uint_32 x = png_exp(lg2); /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the * second, rounding, step can't overflow because of the first, subtraction, * step. */ x -= x >> 8; return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff); } #ifdef PNG_16BIT_SUPPORTED static png_uint_16 png_exp16bit(png_fixed_point lg2) { /* Get a 32-bit value: */ png_uint_32 x = png_exp(lg2); /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */ x -= x >> 16; return (png_uint_16)((x + 32767U) >> 16); } #endif /* 16BIT */ #endif /* FLOATING_ARITHMETIC */ png_byte png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) { if (value > 0 && value < 255) { # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly * convert this to a floating point value. This includes values that * would overflow if 'value' were to be converted to 'int'. * * Apparently GCC, however, does an intermediate conversion to (int) * on some (ARM) but not all (x86) platforms, possibly because of * hardware FP limitations. (E.g. if the hardware conversion always * assumes the integer register contains a signed value.) This results * in ANSI-C undefined behavior for large values. * * Other implementations on the same machine might actually be ANSI-C90 * conformant and therefore compile spurious extra code for the large * values. * * We can be reasonably sure that an unsigned to float conversion * won't be faster than an int to float one. Therefore this code * assumes responsibility for the undefined behavior, which it knows * can't happen because of the check above. * * Note the argument to this routine is an (unsigned int) because, on * 16-bit platforms, it is assigned a value which might be out of * range for an (int); that would result in undefined behavior in the * caller if the *argument* ('value') were to be declared (int). */ double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5); return (png_byte)r; # else png_int_32 lg2 = png_log8bit(value); png_fixed_point res; if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) return png_exp8bit(res); /* Overflow. */ value = 0; # endif } return (png_byte)(value & 0xff); } #ifdef PNG_16BIT_SUPPORTED png_uint_16 png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) { if (value > 0 && value < 65535) { # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* The same (unsigned int)->(double) constraints apply here as above, * however in this case the (unsigned int) to (int) conversion can * overflow on an ANSI-C90 compliant system so the cast needs to ensure * that this is not possible. */ double r = floor(65535*pow((png_int_32)value/65535., gamma_val*.00001)+.5); return (png_uint_16)r; # else png_int_32 lg2 = png_log16bit(value); png_fixed_point res; if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) return png_exp16bit(res); /* Overflow. */ value = 0; # endif } return (png_uint_16)value; } #endif /* 16BIT */ /* This does the right thing based on the bit_depth field of the * png_struct, interpreting values as 8-bit or 16-bit. While the result * is nominally a 16-bit value if bit depth is 8 then the result is * 8-bit (as are the arguments.) */ png_uint_16 /* PRIVATE */ png_gamma_correct(png_structrp png_ptr, unsigned int value, png_fixed_point gamma_val) { if (png_ptr->bit_depth == 8) return png_gamma_8bit_correct(value, gamma_val); #ifdef PNG_16BIT_SUPPORTED else return png_gamma_16bit_correct(value, gamma_val); #else /* should not reach this */ return 0; #endif /* 16BIT */ } #ifdef PNG_16BIT_SUPPORTED /* Internal function to build a single 16-bit table - the table consists of * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount * to shift the input values right (or 16-number_of_signifiant_bits). * * The caller is responsible for ensuring that the table gets cleaned up on * png_error (i.e. if one of the mallocs below fails) - i.e. the *table argument * should be somewhere that will be cleaned. */ static void png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) { /* Various values derived from 'shift': */ PNG_CONST unsigned int num = 1U << (8U - shift); #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* CSE the division and work round wacky GCC warnings (see the comments * in png_gamma_8bit_correct for where these come from.) */ PNG_CONST double fmax = 1./(((png_int_32)1 << (16U - shift))-1); #endif PNG_CONST unsigned int max = (1U << (16U - shift))-1U; PNG_CONST unsigned int max_by_2 = 1U << (15U-shift); unsigned int i; png_uint_16pp table = *ptable = (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); for (i = 0; i < num; i++) { png_uint_16p sub_table = table[i] = (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16))); /* The 'threshold' test is repeated here because it can arise for one of * the 16-bit tables even if the others don't hit it. */ if (png_gamma_significant(gamma_val) != 0) { /* The old code would overflow at the end and this would cause the * 'pow' function to return a result >1, resulting in an * arithmetic error. This code follows the spec exactly; ig is * the recovered input sample, it always has 8-16 bits. * * We want input * 65535/max, rounded, the arithmetic fits in 32 * bits (unsigned) so long as max <= 32767. */ unsigned int j; for (j = 0; j < 256; j++) { png_uint_32 ig = (j << (8-shift)) + i; # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Inline the 'max' scaling operation: */ /* See png_gamma_8bit_correct for why the cast to (int) is * required here. */ double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5); sub_table[j] = (png_uint_16)d; # else if (shift != 0) ig = (ig * 65535U + max_by_2)/max; sub_table[j] = png_gamma_16bit_correct(ig, gamma_val); # endif } } else { /* We must still build a table, but do it the fast way. */ unsigned int j; for (j = 0; j < 256; j++) { png_uint_32 ig = (j << (8-shift)) + i; if (shift != 0) ig = (ig * 65535U + max_by_2)/max; sub_table[j] = (png_uint_16)ig; } } } } /* NOTE: this function expects the *inverse* of the overall gamma transformation * required. */ static void png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) { PNG_CONST unsigned int num = 1U << (8U - shift); PNG_CONST unsigned int max = (1U << (16U - shift))-1U; unsigned int i; png_uint_32 last; png_uint_16pp table = *ptable = (png_uint_16pp)png_calloc(png_ptr, num * (sizeof (png_uint_16p))); /* 'num' is the number of tables and also the number of low bits of low * bits of the input 16-bit value used to select a table. Each table is * itself indexed by the high 8 bits of the value. */ for (i = 0; i < num; i++) table[i] = (png_uint_16p)png_malloc(png_ptr, 256 * (sizeof (png_uint_16))); /* 'gamma_val' is set to the reciprocal of the value calculated above, so * pow(out,g) is an *input* value. 'last' is the last input value set. * * In the loop 'i' is used to find output values. Since the output is * 8-bit there are only 256 possible values. The tables are set up to * select the closest possible output value for each input by finding * the input value at the boundary between each pair of output values * and filling the table up to that boundary with the lower output * value. * * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit * values the code below uses a 16-bit value in i; the values start at * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last * entries are filled with 255). Start i at 128 and fill all 'last' * table entries <= 'max' */ last = 0; for (i = 0; i < 255; ++i) /* 8-bit output value */ { /* Find the corresponding maximum input value */ png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */ /* Find the boundary value in 16 bits: */ png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val); /* Adjust (round) to (16-shift) bits: */ bound = (bound * max + 32768U)/65535U + 1U; while (last < bound) { table[last & (0xffU >> shift)][last >> (8U - shift)] = out; last++; } } /* And fill in the final entries. */ while (last < (num << 8)) { table[last & (0xff >> shift)][last >> (8U - shift)] = 65535U; last++; } } #endif /* 16BIT */ /* Build a single 8-bit table: same as the 16-bit case but much simpler (and * typically much faster). Note that libpng currently does no sBIT processing * (apparently contrary to the spec) so a 256-entry table is always generated. */ static void png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, PNG_CONST png_fixed_point gamma_val) { unsigned int i; png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256); if (png_gamma_significant(gamma_val) != 0) for (i=0; i<256; i++) table[i] = png_gamma_8bit_correct(i, gamma_val); else for (i=0; i<256; ++i) table[i] = (png_byte)(i & 0xff); } /* Used from png_read_destroy and below to release the memory used by the gamma * tables. */ void /* PRIVATE */ png_destroy_gamma_table(png_structrp png_ptr) { png_free(png_ptr, png_ptr->gamma_table); png_ptr->gamma_table = NULL; #ifdef PNG_16BIT_SUPPORTED if (png_ptr->gamma_16_table != NULL) { int i; int istop = (1 << (8 - png_ptr->gamma_shift)); for (i = 0; i < istop; i++) { png_free(png_ptr, png_ptr->gamma_16_table[i]); } png_free(png_ptr, png_ptr->gamma_16_table); png_ptr->gamma_16_table = NULL; } #endif /* 16BIT */ #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) png_free(png_ptr, png_ptr->gamma_from_1); png_ptr->gamma_from_1 = NULL; png_free(png_ptr, png_ptr->gamma_to_1); png_ptr->gamma_to_1 = NULL; #ifdef PNG_16BIT_SUPPORTED if (png_ptr->gamma_16_from_1 != NULL) { int i; int istop = (1 << (8 - png_ptr->gamma_shift)); for (i = 0; i < istop; i++) { png_free(png_ptr, png_ptr->gamma_16_from_1[i]); } png_free(png_ptr, png_ptr->gamma_16_from_1); png_ptr->gamma_16_from_1 = NULL; } if (png_ptr->gamma_16_to_1 != NULL) { int i; int istop = (1 << (8 - png_ptr->gamma_shift)); for (i = 0; i < istop; i++) { png_free(png_ptr, png_ptr->gamma_16_to_1[i]); } png_free(png_ptr, png_ptr->gamma_16_to_1); png_ptr->gamma_16_to_1 = NULL; } #endif /* 16BIT */ #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } /* We build the 8- or 16-bit gamma tables here. Note that for 16-bit * tables, we don't make a full table if we are reducing to 8-bit in * the future. Note also how the gamma_16 tables are segmented so that * we don't need to allocate > 64K chunks for a full 16-bit table. */ void /* PRIVATE */ png_build_gamma_table(png_structrp png_ptr, int bit_depth) { png_debug(1, "in png_build_gamma_table"); /* Remove any existing table; this copes with multiple calls to * png_read_update_info. The warning is because building the gamma tables * multiple times is a performance hit - it's harmless but the ability to * call png_read_update_info() multiple times is new in 1.5.6 so it seems * sensible to warn if the app introduces such a hit. */ if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL) { png_warning(png_ptr, "gamma table being rebuilt"); png_destroy_gamma_table(png_ptr); } if (bit_depth <= 8) { png_build_8bit_table(png_ptr, &png_ptr->gamma_table, png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma) : PNG_FP_1); #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) { png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, png_reciprocal(png_ptr->colorspace.gamma)); png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); } #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } #ifdef PNG_16BIT_SUPPORTED else { png_byte shift, sig_bit; if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) { sig_bit = png_ptr->sig_bit.red; if (png_ptr->sig_bit.green > sig_bit) sig_bit = png_ptr->sig_bit.green; if (png_ptr->sig_bit.blue > sig_bit) sig_bit = png_ptr->sig_bit.blue; } else sig_bit = png_ptr->sig_bit.gray; /* 16-bit gamma code uses this equation: * * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] * * Where 'iv' is the input color value and 'ov' is the output value - * pow(iv, gamma). * * Thus the gamma table consists of up to 256 256-entry tables. The table * is selected by the (8-gamma_shift) most significant of the low 8 bits * of the color value then indexed by the upper 8 bits: * * table[low bits][high 8 bits] * * So the table 'n' corresponds to all those 'iv' of: * * ..<(n+1 << gamma_shift)-1> * */ if (sig_bit > 0 && sig_bit < 16U) /* shift == insignificant bits */ shift = (png_byte)((16U - sig_bit) & 0xff); else shift = 0; /* keep all 16 bits */ if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) { /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively * the significant bits in the *input* when the output will * eventually be 8 bits. By default it is 11. */ if (shift < (16U - PNG_MAX_GAMMA_8)) shift = (16U - PNG_MAX_GAMMA_8); } if (shift > 8U) shift = 8U; /* Guarantees at least one table! */ png_ptr->gamma_shift = shift; /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now * PNG_COMPOSE). This effectively smashed the background calculation for * 16-bit output because the 8-bit table assumes the result will be * reduced to 8 bits. */ if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma, png_ptr->screen_gamma) : PNG_FP_1); else png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift, png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma) : PNG_FP_1); #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) { png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, png_reciprocal(png_ptr->colorspace.gamma)); /* Notice that the '16 from 1' table should be full precision, however * the lookup on this table still uses gamma_shift, so it can't be. * TODO: fix this. */ png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); } #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } #endif /* 16BIT */ } #endif /* READ_GAMMA */ /* HARDWARE OR SOFTWARE OPTION SUPPORT */ #ifdef PNG_SET_OPTION_SUPPORTED int PNGAPI png_set_option(png_structrp png_ptr, int option, int onoff) { if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && (option & 1) == 0) { png_uint_32 mask = 3U << option; png_uint_32 setting = (2U + (onoff != 0)) << option; png_uint_32 current = png_ptr->options; png_ptr->options = (png_uint_32)(((current & ~mask) | setting) & 0xff); return (int)(current & mask) >> option; } return PNG_OPTION_INVALID; } #endif /* sRGB support */ #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) /* sRGB conversion tables; these are machine generated with the code in * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the * specification (see the article at https://en.wikipedia.org/wiki/SRGB) * is used, not the gamma=1/2.2 approximation use elsewhere in libpng. * The sRGB to linear table is exact (to the nearest 16-bit linear fraction). * The inverse (linear to sRGB) table has accuracies as follows: * * For all possible (255*65535+1) input values: * * error: -0.515566 - 0.625971, 79441 (0.475369%) of readings inexact * * For the input values corresponding to the 65536 16-bit values: * * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact * * In all cases the inexact readings are only off by one. */ #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* The convert-to-sRGB table is only currently required for read. */ const png_uint_16 png_sRGB_table[256] = { 0,20,40,60,80,99,119,139, 159,179,199,219,241,264,288,313, 340,367,396,427,458,491,526,562, 599,637,677,718,761,805,851,898, 947,997,1048,1101,1156,1212,1270,1330, 1391,1453,1517,1583,1651,1720,1790,1863, 1937,2013,2090,2170,2250,2333,2418,2504, 2592,2681,2773,2866,2961,3058,3157,3258, 3360,3464,3570,3678,3788,3900,4014,4129, 4247,4366,4488,4611,4736,4864,4993,5124, 5257,5392,5530,5669,5810,5953,6099,6246, 6395,6547,6700,6856,7014,7174,7335,7500, 7666,7834,8004,8177,8352,8528,8708,8889, 9072,9258,9445,9635,9828,10022,10219,10417, 10619,10822,11028,11235,11446,11658,11873,12090, 12309,12530,12754,12980,13209,13440,13673,13909, 14146,14387,14629,14874,15122,15371,15623,15878, 16135,16394,16656,16920,17187,17456,17727,18001, 18277,18556,18837,19121,19407,19696,19987,20281, 20577,20876,21177,21481,21787,22096,22407,22721, 23038,23357,23678,24002,24329,24658,24990,25325, 25662,26001,26344,26688,27036,27386,27739,28094, 28452,28813,29176,29542,29911,30282,30656,31033, 31412,31794,32179,32567,32957,33350,33745,34143, 34544,34948,35355,35764,36176,36591,37008,37429, 37852,38278,38706,39138,39572,40009,40449,40891, 41337,41785,42236,42690,43147,43606,44069,44534, 45002,45473,45947,46423,46903,47385,47871,48359, 48850,49344,49841,50341,50844,51349,51858,52369, 52884,53401,53921,54445,54971,55500,56032,56567, 57105,57646,58190,58737,59287,59840,60396,60955, 61517,62082,62650,63221,63795,64372,64952,65535 }; #endif /* SIMPLIFIED_READ */ /* The base/delta tables are required for both read and write (but currently * only the simplified versions.) */ const png_uint_16 png_sRGB_base[512] = { 128,1782,3383,4644,5675,6564,7357,8074, 8732,9346,9921,10463,10977,11466,11935,12384, 12816,13233,13634,14024,14402,14769,15125,15473, 15812,16142,16466,16781,17090,17393,17690,17981, 18266,18546,18822,19093,19359,19621,19879,20133, 20383,20630,20873,21113,21349,21583,21813,22041, 22265,22487,22707,22923,23138,23350,23559,23767, 23972,24175,24376,24575,24772,24967,25160,25352, 25542,25730,25916,26101,26284,26465,26645,26823, 27000,27176,27350,27523,27695,27865,28034,28201, 28368,28533,28697,28860,29021,29182,29341,29500, 29657,29813,29969,30123,30276,30429,30580,30730, 30880,31028,31176,31323,31469,31614,31758,31902, 32045,32186,32327,32468,32607,32746,32884,33021, 33158,33294,33429,33564,33697,33831,33963,34095, 34226,34357,34486,34616,34744,34873,35000,35127, 35253,35379,35504,35629,35753,35876,35999,36122, 36244,36365,36486,36606,36726,36845,36964,37083, 37201,37318,37435,37551,37668,37783,37898,38013, 38127,38241,38354,38467,38580,38692,38803,38915, 39026,39136,39246,39356,39465,39574,39682,39790, 39898,40005,40112,40219,40325,40431,40537,40642, 40747,40851,40955,41059,41163,41266,41369,41471, 41573,41675,41777,41878,41979,42079,42179,42279, 42379,42478,42577,42676,42775,42873,42971,43068, 43165,43262,43359,43456,43552,43648,43743,43839, 43934,44028,44123,44217,44311,44405,44499,44592, 44685,44778,44870,44962,45054,45146,45238,45329, 45420,45511,45601,45692,45782,45872,45961,46051, 46140,46229,46318,46406,46494,46583,46670,46758, 46846,46933,47020,47107,47193,47280,47366,47452, 47538,47623,47709,47794,47879,47964,48048,48133, 48217,48301,48385,48468,48552,48635,48718,48801, 48884,48966,49048,49131,49213,49294,49376,49458, 49539,49620,49701,49782,49862,49943,50023,50103, 50183,50263,50342,50422,50501,50580,50659,50738, 50816,50895,50973,51051,51129,51207,51285,51362, 51439,51517,51594,51671,51747,51824,51900,51977, 52053,52129,52205,52280,52356,52432,52507,52582, 52657,52732,52807,52881,52956,53030,53104,53178, 53252,53326,53400,53473,53546,53620,53693,53766, 53839,53911,53984,54056,54129,54201,54273,54345, 54417,54489,54560,54632,54703,54774,54845,54916, 54987,55058,55129,55199,55269,55340,55410,55480, 55550,55620,55689,55759,55828,55898,55967,56036, 56105,56174,56243,56311,56380,56448,56517,56585, 56653,56721,56789,56857,56924,56992,57059,57127, 57194,57261,57328,57395,57462,57529,57595,57662, 57728,57795,57861,57927,57993,58059,58125,58191, 58256,58322,58387,58453,58518,58583,58648,58713, 58778,58843,58908,58972,59037,59101,59165,59230, 59294,59358,59422,59486,59549,59613,59677,59740, 59804,59867,59930,59993,60056,60119,60182,60245, 60308,60370,60433,60495,60558,60620,60682,60744, 60806,60868,60930,60992,61054,61115,61177,61238, 61300,61361,61422,61483,61544,61605,61666,61727, 61788,61848,61909,61969,62030,62090,62150,62211, 62271,62331,62391,62450,62510,62570,62630,62689, 62749,62808,62867,62927,62986,63045,63104,63163, 63222,63281,63340,63398,63457,63515,63574,63632, 63691,63749,63807,63865,63923,63981,64039,64097, 64155,64212,64270,64328,64385,64443,64500,64557, 64614,64672,64729,64786,64843,64900,64956,65013, 65070,65126,65183,65239,65296,65352,65409,65465 }; const png_byte png_sRGB_delta[512] = { 207,201,158,129,113,100,90,82,77,72,68,64,61,59,56,54, 52,50,49,47,46,45,43,42,41,40,39,39,38,37,36,36, 35,34,34,33,33,32,32,31,31,30,30,30,29,29,28,28, 28,27,27,27,27,26,26,26,25,25,25,25,24,24,24,24, 23,23,23,23,23,22,22,22,22,22,22,21,21,21,21,21, 21,20,20,20,20,20,20,20,20,19,19,19,19,19,19,19, 19,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17, 17,17,17,17,17,17,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,15,15,15,15,15,15,15,15,15,15,15,15, 15,15,15,15,14,14,14,14,14,14,14,14,14,14,14,14, 14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13, 13,13,13,13,13,13,13,13,13,13,13,13,13,13,12,12, 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,11, 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, 11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, 10,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; #endif /* SIMPLIFIED READ/WRITE sRGB support */ /* SIMPLIFIED READ/WRITE SUPPORT */ #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) static int png_image_free_function(png_voidp argument) { png_imagep image = png_voidcast(png_imagep, argument); png_controlp cp = image->opaque; png_control c; /* Double check that we have a png_ptr - it should be impossible to get here * without one. */ if (cp->png_ptr == NULL) return 0; /* First free any data held in the control structure. */ # ifdef PNG_STDIO_SUPPORTED if (cp->owned_file != 0) { FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr); cp->owned_file = 0; /* Ignore errors here. */ if (fp != NULL) { cp->png_ptr->io_ptr = NULL; (void)fclose(fp); } } # endif /* Copy the control structure so that the original, allocated, version can be * safely freed. Notice that a png_error here stops the remainder of the * cleanup, but this is probably fine because that would indicate bad memory * problems anyway. */ c = *cp; image->opaque = &c; png_free(c.png_ptr, cp); /* Then the structures, calling the correct API. */ if (c.for_write != 0) { # ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED png_destroy_write_struct(&c.png_ptr, &c.info_ptr); # else png_error(c.png_ptr, "simplified write not supported"); # endif } else { # ifdef PNG_SIMPLIFIED_READ_SUPPORTED png_destroy_read_struct(&c.png_ptr, &c.info_ptr, NULL); # else png_error(c.png_ptr, "simplified read not supported"); # endif } /* Success. */ return 1; } void PNGAPI png_image_free(png_imagep image) { /* Safely call the real function, but only if doing so is safe at this point * (if not inside an error handling context). Otherwise assume * png_safe_execute will call this API after the return. */ if (image != NULL && image->opaque != NULL && image->opaque->error_buf == NULL) { /* Ignore errors here: */ (void)png_safe_execute(image, png_image_free_function, image); image->opaque = NULL; } } int /* PRIVATE */ png_image_error(png_imagep image, png_const_charp error_message) { /* Utility to log an error. */ png_safecat(image->message, (sizeof image->message), 0, error_message); image->warning_or_error |= PNG_IMAGE_ERROR; png_image_free(image); return 0; } #endif /* SIMPLIFIED READ/WRITE */ #endif /* READ || WRITE */ stella-5.1.1/src/libpng/png.h000066400000000000000000004314251324334165500160200ustar00rootroot00000000000000 /* png.h - header file for PNG reference library * * libpng version 1.6.34, September 29, 2017 * * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license (See LICENSE, below) * * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger * libpng versions 0.97, January 1998, through 1.6.34, September 29, 2017: * Glenn Randers-Pehrson. * See also "Contributing Authors", below. */ /* * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE: * * If you modify libpng you may insert additional notices immediately following * this sentence. * * This code is released under the libpng license. * * libpng versions 1.0.7, July 1, 2000 through 1.6.34, September 29, 2017 are * Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are * derived from libpng-1.0.6, and are distributed according to the same * disclaimer and license as libpng-1.0.6 with the following individuals * added to the list of Contributing Authors: * * Simon-Pierre Cadieux * Eric S. Raymond * Mans Rullgard * Cosmin Truta * Gilles Vollant * James Yu * Mandar Sahastrabuddhe * Google Inc. * Vadim Barkov * * and with the following additions to the disclaimer: * * There is no warranty against interference with your enjoyment of the * library or against infringement. There is no warranty that our * efforts or the library will fulfill any of your particular purposes * or needs. This library is provided with all faults, and the entire * risk of satisfactory quality, performance, accuracy, and effort is with * the user. * * Some files in the "contrib" directory and some configure-generated * files that are distributed with libpng have other copyright owners and * are released under other open source licenses. * * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from * libpng-0.96, and are distributed according to the same disclaimer and * license as libpng-0.96, with the following individuals added to the list * of Contributing Authors: * * Tom Lane * Glenn Randers-Pehrson * Willem van Schaik * * libpng versions 0.89, June 1996, through 0.96, May 1997, are * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, * and are distributed according to the same disclaimer and license as * libpng-0.88, with the following individuals added to the list of * Contributing Authors: * * John Bowler * Kevin Bracey * Sam Bushell * Magnus Holmgren * Greg Roelofs * Tom Tanner * * Some files in the "scripts" directory have other copyright owners * but are released under this license. * * libpng versions 0.5, May 1995, through 0.88, January 1996, are * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. * * For the purposes of this copyright and license, "Contributing Authors" * is defined as the following set of individuals: * * Andreas Dilger * Dave Martindale * Guy Eric Schalnat * Paul Schmidt * Tim Wegner * * The PNG Reference Library is supplied "AS IS". The Contributing Authors * and Group 42, Inc. disclaim all warranties, expressed or implied, * including, without limitation, the warranties of merchantability and of * fitness for any purpose. The Contributing Authors and Group 42, Inc. * assume no liability for direct, indirect, incidental, special, exemplary, * or consequential damages, which may result from the use of the PNG * Reference Library, even if advised of the possibility of such damage. * * Permission is hereby granted to use, copy, modify, and distribute this * source code, or portions hereof, for any purpose, without fee, subject * to the following restrictions: * * 1. The origin of this source code must not be misrepresented. * * 2. Altered versions must be plainly marked as such and must not * be misrepresented as being the original source. * * 3. This Copyright notice may not be removed or altered from any * source or altered source distribution. * * The Contributing Authors and Group 42, Inc. specifically permit, without * fee, and encourage the use of this source code as a component to * supporting the PNG file format in commercial products. If you use this * source code in a product, acknowledgment is not required but would be * appreciated. * * END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. * * TRADEMARK: * * The name "libpng" has not been registered by the Copyright owner * as a trademark in any jurisdiction. However, because libpng has * been distributed and maintained world-wide, continually since 1995, * the Copyright owner claims "common-law trademark protection" in any * jurisdiction where common-law trademark is recognized. * * OSI CERTIFICATION: * * Libpng is OSI Certified Open Source Software. OSI Certified Open Source is * a certification mark of the Open Source Initiative. OSI has not addressed * the additional disclaimers inserted at version 1.0.7. * * EXPORT CONTROL: * * The Copyright owner believes that the Export Control Classification * Number (ECCN) for libpng is EAR99, which means not subject to export * controls or International Traffic in Arms Regulations (ITAR) because * it is open source, publicly available software, that does not contain * any encryption software. See the EAR, paragraphs 734.3(b)(3) and * 734.7(b). */ /* * A "png_get_copyright" function is available, for convenient use in "about" * boxes and the like: * * printf("%s", png_get_copyright(NULL)); * * Also, the PNG logo (in PNG format, of course) is supplied in the * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). */ /* * The contributing authors would like to thank all those who helped * with testing, bug fixes, and patience. This wouldn't have been * possible without all of you. * * Thanks to Frank J. T. Wojcik for helping with the documentation. */ /* Note about libpng version numbers: * * Due to various miscommunications, unforeseen code incompatibilities * and occasional factors outside the authors' control, version numbering * on the library has not always been consistent and straightforward. * The following table summarizes matters since version 0.89c, which was * the first widely used release: * * source png.h png.h shared-lib * version string int version * ------- ------ ----- ---------- * 0.89c "1.0 beta 3" 0.89 89 1.0.89 * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90] * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95] * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96] * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97] * 0.97c 0.97 97 2.0.97 * 0.98 0.98 98 2.0.98 * 0.99 0.99 98 2.0.99 * 0.99a-m 0.99 99 2.0.99 * 1.00 1.00 100 2.1.0 [100 should be 10000] * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000] * 1.0.1 png.h string is 10001 2.1.0 * 1.0.1a-e identical to the 10002 from here on, the shared library * 1.0.2 source version) 10002 is 2.V where V is the source code * 1.0.2a-b 10003 version, except as noted. * 1.0.3 10003 * 1.0.3a-d 10004 * 1.0.4 10004 * 1.0.4a-f 10005 * 1.0.5 (+ 2 patches) 10005 * 1.0.5a-d 10006 * 1.0.5e-r 10100 (not source compatible) * 1.0.5s-v 10006 (not binary compatible) * 1.0.6 (+ 3 patches) 10006 (still binary incompatible) * 1.0.6d-f 10007 (still binary incompatible) * 1.0.6g 10007 * 1.0.6h 10007 10.6h (testing xy.z so-numbering) * 1.0.6i 10007 10.6i * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0) * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible) * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) * 1.0.7 1 10007 (still compatible) * ... * 1.0.19 10 10019 10.so.0.19[.0] * ... * 1.2.59 13 10257 12.so.0.59[.0] * ... * 1.5.30 15 10527 15.so.15.30[.0] * ... * 1.6.34 16 10633 16.so.16.34[.0] * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be * used for changes in backward compatibility, as it is intended. The * PNG_LIBPNG_VER macro, which is not used within libpng but is available * for applications, is an unsigned integer of the form xyyzz corresponding * to the source version x.y.z (leading zeros in y and z). Beta versions * were given the previous public release number plus a letter, until * version 1.0.6j; from then on they were given the upcoming public * release number plus "betaNN" or "rcNN". * * Binary incompatibility exists only when applications make direct access * to the info_ptr or png_ptr members through png.h, and the compiled * application is loaded with a different version of the library. * * DLLNUM will change each time there are forward or backward changes * in binary compatibility (e.g., when a new feature is added). * * See libpng.txt or libpng.3 for more information. The PNG specification * is available as a W3C Recommendation and as an ISO Specification, * * * If you just need to read a PNG file and don't want to read the documentation * skip to the end of this file and read the section entitled 'simplified API'. */ /* Version information for png.h - this should match the version in png.c */ #define PNG_LIBPNG_VER_STRING "1.6.34" #define PNG_HEADER_VERSION_STRING " libpng version 1.6.34 - September 29, 2017\n" #define PNG_LIBPNG_VER_SONUM 16 #define PNG_LIBPNG_VER_DLLNUM 16 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 #define PNG_LIBPNG_VER_RELEASE 34 /* This should match the numeric part of the final component of * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ #define PNG_LIBPNG_VER_BUILD 0 /* Release Status */ #define PNG_LIBPNG_BUILD_ALPHA 1 #define PNG_LIBPNG_BUILD_BETA 2 #define PNG_LIBPNG_BUILD_RC 3 #define PNG_LIBPNG_BUILD_STABLE 4 #define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7 /* Release-Specific Flags */ #define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with PNG_LIBPNG_BUILD_STABLE only */ #define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with PNG_LIBPNG_BUILD_SPECIAL */ #define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with PNG_LIBPNG_BUILD_PRIVATE */ #define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE /* Careful here. At one time, Guy wanted to use 082, but that would be octal. * We must not include leading zeros. * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only * version 1.0.0 was mis-numbered 100 instead of 10000). From * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ #define PNG_LIBPNG_VER 10634 /* 1.6.34 */ /* Library configuration: these options cannot be changed after * the library has been built. */ #ifndef PNGLCONF_H /* If pnglibconf.h is missing, you can * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h */ # include "pnglibconf.h" #endif #ifndef PNG_VERSION_INFO_ONLY /* Machine specific configuration. */ # include "pngconf.h" #endif /* * Added at libpng-1.2.8 * * Ref MSDN: Private as priority over Special * VS_FF_PRIVATEBUILD File *was not* built using standard release * procedures. If this value is given, the StringFileInfo block must * contain a PrivateBuild string. * * VS_FF_SPECIALBUILD File *was* built by the original company using * standard release procedures but is a variation of the standard * file of the same version number. If this value is given, the * StringFileInfo block must contain a SpecialBuild string. */ #ifdef PNG_USER_PRIVATEBUILD /* From pnglibconf.h */ # define PNG_LIBPNG_BUILD_TYPE \ (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE) #else # ifdef PNG_LIBPNG_SPECIALBUILD # define PNG_LIBPNG_BUILD_TYPE \ (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL) # else # define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE) # endif #endif #ifndef PNG_VERSION_INFO_ONLY /* Inhibit C++ name-mangling for libpng functions but not for system calls. */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Version information for C files, stored in png.c. This had better match * the version above. */ #define png_libpng_ver png_get_header_ver(NULL) /* This file is arranged in several sections: * * 1. [omitted] * 2. Any configuration options that can be specified by for the application * code when it is built. (Build time configuration is in pnglibconf.h) * 3. Type definitions (base types are defined in pngconf.h), structure * definitions. * 4. Exported library functions. * 5. Simplified API. * 6. Implementation options. * * The library source code has additional files (principally pngpriv.h) that * allow configuration of the library. */ /* Section 1: [omitted] */ /* Section 2: run time configuration * See pnglibconf.h for build time configuration * * Run time configuration allows the application to choose between * implementations of certain arithmetic APIs. The default is set * at build time and recorded in pnglibconf.h, but it is safe to * override these (and only these) settings. Note that this won't * change what the library does, only application code, and the * settings can (and probably should) be made on a per-file basis * by setting the #defines before including png.h * * Use macros to read integers from PNG data or use the exported * functions? * PNG_USE_READ_MACROS: use the macros (see below) Note that * the macros evaluate their argument multiple times. * PNG_NO_USE_READ_MACROS: call the relevant library function. * * Use the alternative algorithm for compositing alpha samples that * does not use division? * PNG_READ_COMPOSITE_NODIV_SUPPORTED: use the 'no division' * algorithm. * PNG_NO_READ_COMPOSITE_NODIV: use the 'division' algorithm. * * How to handle benign errors if PNG_ALLOW_BENIGN_ERRORS is * false? * PNG_ALLOW_BENIGN_ERRORS: map calls to the benign error * APIs to png_warning. * Otherwise the calls are mapped to png_error. */ /* Section 3: type definitions, including structures and compile time * constants. * See pngconf.h for base types that vary by machine/system */ /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ typedef char* png_libpng_version_1_6_34; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * * png_struct is the cache of information used while reading or writing a single * PNG file. One of these is always required, although the simplified API * (below) hides the creation and destruction of it. */ typedef struct png_struct_def png_struct; typedef const png_struct * png_const_structp; typedef png_struct * png_structp; typedef png_struct * * png_structpp; /* png_info contains information read from or to be written to a PNG file. One * or more of these must exist while reading or creating a PNG file. The * information is not used by libpng during read but is used to control what * gets written when a PNG file is created. "png_get_" function calls read * information during read and "png_set_" functions calls write information * when creating a PNG. * been moved into a separate header file that is not accessible to * applications. Read libpng-manual.txt or libpng.3 for more info. */ typedef struct png_info_def png_info; typedef png_info * png_infop; typedef const png_info * png_const_infop; typedef png_info * * png_infopp; /* Types with names ending 'p' are pointer types. The corresponding types with * names ending 'rp' are identical pointer types except that the pointer is * marked 'restrict', which means that it is the only pointer to the object * passed to the function. Applications should not use the 'restrict' types; * it is always valid to pass 'p' to a pointer with a function argument of the * corresponding 'rp' type. Different compilers have different rules with * regard to type matching in the presence of 'restrict'. For backward * compatibility libpng callbacks never have 'restrict' in their parameters and, * consequentially, writing portable application code is extremely difficult if * an attempt is made to use 'restrict'. */ typedef png_struct * PNG_RESTRICT png_structrp; typedef const png_struct * PNG_RESTRICT png_const_structrp; typedef png_info * PNG_RESTRICT png_inforp; typedef const png_info * PNG_RESTRICT png_const_inforp; /* Three color definitions. The order of the red, green, and blue, (and the * exact size) is not important, although the size of the fields need to * be png_byte or png_uint_16 (as defined below). */ typedef struct png_color_struct { png_byte red; png_byte green; png_byte blue; } png_color; typedef png_color * png_colorp; typedef const png_color * png_const_colorp; typedef png_color * * png_colorpp; typedef struct png_color_16_struct { png_byte index; /* used for palette files */ png_uint_16 red; /* for use in red green blue files */ png_uint_16 green; png_uint_16 blue; png_uint_16 gray; /* for use in grayscale files */ } png_color_16; typedef png_color_16 * png_color_16p; typedef const png_color_16 * png_const_color_16p; typedef png_color_16 * * png_color_16pp; typedef struct png_color_8_struct { png_byte red; /* for use in red green blue files */ png_byte green; png_byte blue; png_byte gray; /* for use in grayscale files */ png_byte alpha; /* for alpha channel files */ } png_color_8; typedef png_color_8 * png_color_8p; typedef const png_color_8 * png_const_color_8p; typedef png_color_8 * * png_color_8pp; /* * The following two structures are used for the in-core representation * of sPLT chunks. */ typedef struct png_sPLT_entry_struct { png_uint_16 red; png_uint_16 green; png_uint_16 blue; png_uint_16 alpha; png_uint_16 frequency; } png_sPLT_entry; typedef png_sPLT_entry * png_sPLT_entryp; typedef const png_sPLT_entry * png_const_sPLT_entryp; typedef png_sPLT_entry * * png_sPLT_entrypp; /* When the depth of the sPLT palette is 8 bits, the color and alpha samples * occupy the LSB of their respective members, and the MSB of each member * is zero-filled. The frequency member always occupies the full 16 bits. */ typedef struct png_sPLT_struct { png_charp name; /* palette name */ png_byte depth; /* depth of palette samples */ png_sPLT_entryp entries; /* palette entries */ png_int_32 nentries; /* number of palette entries */ } png_sPLT_t; typedef png_sPLT_t * png_sPLT_tp; typedef const png_sPLT_t * png_const_sPLT_tp; typedef png_sPLT_t * * png_sPLT_tpp; #ifdef PNG_TEXT_SUPPORTED /* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file, * and whether that contents is compressed or not. The "key" field * points to a regular zero-terminated C string. The "text" fields can be a * regular C string, an empty string, or a NULL pointer. * However, the structure returned by png_get_text() will always contain * the "text" field as a regular zero-terminated C string (possibly * empty), never a NULL pointer, so it can be safely used in printf() and * other string-handling functions. Note that the "itxt_length", "lang", and * "lang_key" members of the structure only exist when the library is built * with iTXt chunk support. Prior to libpng-1.4.0 the library was built by * default without iTXt support. Also note that when iTXt *is* supported, * the "lang" and "lang_key" fields contain NULL pointers when the * "compression" field contains * PNG_TEXT_COMPRESSION_NONE or * PNG_TEXT_COMPRESSION_zTXt. Note that the "compression value" is not the * same as what appears in the PNG tEXt/zTXt/iTXt chunk's "compression flag" * which is always 0 or 1, or its "compression method" which is always 0. */ typedef struct png_text_struct { int compression; /* compression value: -1: tEXt, none 0: zTXt, deflate 1: iTXt, none 2: iTXt, deflate */ png_charp key; /* keyword, 1-79 character description of "text" */ png_charp text; /* comment, may be an empty string (ie "") or a NULL pointer */ png_size_t text_length; /* length of the text string */ png_size_t itxt_length; /* length of the itxt string */ png_charp lang; /* language code, 0-79 characters or a NULL pointer */ png_charp lang_key; /* keyword translated UTF-8 string, 0 or more chars or a NULL pointer */ } png_text; typedef png_text * png_textp; typedef const png_text * png_const_textp; typedef png_text * * png_textpp; #endif /* Supported compression types for text in PNG files (tEXt, and zTXt). * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */ #define PNG_TEXT_COMPRESSION_NONE_WR -3 #define PNG_TEXT_COMPRESSION_zTXt_WR -2 #define PNG_TEXT_COMPRESSION_NONE -1 #define PNG_TEXT_COMPRESSION_zTXt 0 #define PNG_ITXT_COMPRESSION_NONE 1 #define PNG_ITXT_COMPRESSION_zTXt 2 #define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */ /* png_time is a way to hold the time in an machine independent way. * Two conversions are provided, both from time_t and struct tm. There * is no portable way to convert to either of these structures, as far * as I know. If you know of a portable way, send it to me. As a side * note - PNG has always been Year 2000 compliant! */ typedef struct png_time_struct { png_uint_16 year; /* full year, as in, 1995 */ png_byte month; /* month of year, 1 - 12 */ png_byte day; /* day of month, 1 - 31 */ png_byte hour; /* hour of day, 0 - 23 */ png_byte minute; /* minute of hour, 0 - 59 */ png_byte second; /* second of minute, 0 - 60 (for leap seconds) */ } png_time; typedef png_time * png_timep; typedef const png_time * png_const_timep; typedef png_time * * png_timepp; #if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) ||\ defined(PNG_USER_CHUNKS_SUPPORTED) /* png_unknown_chunk is a structure to hold queued chunks for which there is * no specific support. The idea is that we can use this to queue * up private chunks for output even though the library doesn't actually * know about their semantics. * * The data in the structure is set by libpng on read and used on write. */ typedef struct png_unknown_chunk_t { png_byte name[5]; /* Textual chunk name with '\0' terminator */ png_byte *data; /* Data, should not be modified on read! */ png_size_t size; /* On write 'location' must be set using the flag values listed below. * Notice that on read it is set by libpng however the values stored have * more bits set than are listed below. Always treat the value as a * bitmask. On write set only one bit - setting multiple bits may cause the * chunk to be written in multiple places. */ png_byte location; /* mode of operation at read time */ } png_unknown_chunk; typedef png_unknown_chunk * png_unknown_chunkp; typedef const png_unknown_chunk * png_const_unknown_chunkp; typedef png_unknown_chunk * * png_unknown_chunkpp; #endif /* Flag values for the unknown chunk location byte. */ #define PNG_HAVE_IHDR 0x01 #define PNG_HAVE_PLTE 0x02 #define PNG_AFTER_IDAT 0x08 /* Maximum positive integer used in PNG is (2^31)-1 */ #define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) #define PNG_UINT_32_MAX ((png_uint_32)(-1)) #define PNG_SIZE_MAX ((png_size_t)(-1)) /* These are constants for fixed point values encoded in the * PNG specification manner (x100000) */ #define PNG_FP_1 100000 #define PNG_FP_HALF 50000 #define PNG_FP_MAX ((png_fixed_point)0x7fffffffL) #define PNG_FP_MIN (-PNG_FP_MAX) /* These describe the color_type field in png_info. */ /* color type masks */ #define PNG_COLOR_MASK_PALETTE 1 #define PNG_COLOR_MASK_COLOR 2 #define PNG_COLOR_MASK_ALPHA 4 /* color types. Note that not all combinations are legal */ #define PNG_COLOR_TYPE_GRAY 0 #define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE) #define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR) #define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA) #define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA) /* aliases */ #define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA #define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA /* This is for compression type. PNG 1.0-1.2 only define the single type. */ #define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ #define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE /* This is for filter type. PNG 1.0-1.2 only define the single type. */ #define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ #define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ #define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE /* These are for the interlacing type. These values should NOT be changed. */ #define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ #define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ #define PNG_INTERLACE_LAST 2 /* Not a valid value */ /* These are for the oFFs chunk. These values should NOT be changed. */ #define PNG_OFFSET_PIXEL 0 /* Offset in pixels */ #define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */ #define PNG_OFFSET_LAST 2 /* Not a valid value */ /* These are for the pCAL chunk. These values should NOT be changed. */ #define PNG_EQUATION_LINEAR 0 /* Linear transformation */ #define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */ #define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */ #define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */ #define PNG_EQUATION_LAST 4 /* Not a valid value */ /* These are for the sCAL chunk. These values should NOT be changed. */ #define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */ #define PNG_SCALE_METER 1 /* meters per pixel */ #define PNG_SCALE_RADIAN 2 /* radians per pixel */ #define PNG_SCALE_LAST 3 /* Not a valid value */ /* These are for the pHYs chunk. These values should NOT be changed. */ #define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */ #define PNG_RESOLUTION_METER 1 /* pixels/meter */ #define PNG_RESOLUTION_LAST 2 /* Not a valid value */ /* These are for the sRGB chunk. These values should NOT be changed. */ #define PNG_sRGB_INTENT_PERCEPTUAL 0 #define PNG_sRGB_INTENT_RELATIVE 1 #define PNG_sRGB_INTENT_SATURATION 2 #define PNG_sRGB_INTENT_ABSOLUTE 3 #define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */ /* This is for text chunks */ #define PNG_KEYWORD_MAX_LENGTH 79 /* Maximum number of entries in PLTE/sPLT/tRNS arrays */ #define PNG_MAX_PALETTE_LENGTH 256 /* These determine if an ancillary chunk's data has been successfully read * from the PNG header, or if the application has filled in the corresponding * data in the info_struct to be written into the output file. The values * of the PNG_INFO_ defines should NOT be changed. */ #define PNG_INFO_gAMA 0x0001U #define PNG_INFO_sBIT 0x0002U #define PNG_INFO_cHRM 0x0004U #define PNG_INFO_PLTE 0x0008U #define PNG_INFO_tRNS 0x0010U #define PNG_INFO_bKGD 0x0020U #define PNG_INFO_hIST 0x0040U #define PNG_INFO_pHYs 0x0080U #define PNG_INFO_oFFs 0x0100U #define PNG_INFO_tIME 0x0200U #define PNG_INFO_pCAL 0x0400U #define PNG_INFO_sRGB 0x0800U /* GR-P, 0.96a */ #define PNG_INFO_iCCP 0x1000U /* ESR, 1.0.6 */ #define PNG_INFO_sPLT 0x2000U /* ESR, 1.0.6 */ #define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */ #define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */ #define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */ /* This is used for the transformation routines, as some of them * change these values for the row. It also should enable using * the routines for other purposes. */ typedef struct png_row_info_struct { png_uint_32 width; /* width of row */ png_size_t rowbytes; /* number of bytes in row */ png_byte color_type; /* color type of row */ png_byte bit_depth; /* bit depth of row */ png_byte channels; /* number of channels (1, 2, 3, or 4) */ png_byte pixel_depth; /* bits per pixel (depth * channels) */ } png_row_info; typedef png_row_info * png_row_infop; typedef png_row_info * * png_row_infopp; /* These are the function types for the I/O functions and for the functions * that allow the user to override the default I/O functions with his or her * own. The png_error_ptr type should match that of user-supplied warning * and error functions, while the png_rw_ptr type should match that of the * user read/write data functions. Note that the 'write' function must not * modify the buffer it is passed. The 'read' function, on the other hand, is * expected to return the read data in the buffer. */ typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, int)); typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, int)); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); /* The following callback receives png_uint_32 row_number, int pass for the * png_bytep data of the row. When transforming an interlaced image the * row number is the row number within the sub-image of the interlace pass, so * the value will increase to the height of the sub-image (not the full image) * then reset to 0 for the next pass. * * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to * find the output pixel (x,y) given an interlaced sub-image pixel * (row,col,pass). (See below for these macros.) */ typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, png_uint_32, int)); #endif #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, png_bytep)); #endif #ifdef PNG_USER_CHUNKS_SUPPORTED typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, png_unknown_chunkp)); #endif #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED /* not used anywhere */ /* typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); */ #endif #ifdef PNG_SETJMP_SUPPORTED /* This must match the function definition in , and the application * must include this before png.h to obtain the definition of jmp_buf. The * function is required to be PNG_NORETURN, but this is not checked. If the * function does return the application will crash via an abort() or similar * system level call. * * If you get a warning here while building the library you may need to make * changes to ensure that pnglibconf.h records the calling convention used by * your compiler. This may be very difficult - try using a different compiler * to build the library! */ PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); #endif /* Transform masks for the high-level interface */ #define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */ #define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */ #define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */ #define PNG_TRANSFORM_PACKING 0x0004 /* read and write */ #define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */ #define PNG_TRANSFORM_EXPAND 0x0010 /* read only */ #define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */ #define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */ #define PNG_TRANSFORM_BGR 0x0080 /* read and write */ #define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */ #define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */ #define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */ #define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* write only */ /* Added to libpng-1.2.34 */ #define PNG_TRANSFORM_STRIP_FILLER_BEFORE PNG_TRANSFORM_STRIP_FILLER #define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ /* Added to libpng-1.4.0 */ #define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ /* Added to libpng-1.5.4 */ #define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ #if INT_MAX >= 0x8000 /* else this might break */ #define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ #endif /* Flags for MNG supported features */ #define PNG_FLAG_MNG_EMPTY_PLTE 0x01 #define PNG_FLAG_MNG_FILTER_64 0x04 #define PNG_ALL_MNG_FEATURES 0x05 /* NOTE: prior to 1.5 these functions had no 'API' style declaration, * this allowed the zlib default functions to be used on Windows * platforms. In 1.5 the zlib default malloc (which just calls malloc and * ignores the first argument) should be completely compatible with the * following. */ typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, png_alloc_size_t)); typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); /* Section 4: exported functions * Here are the function definitions most commonly used. This is not * the place to find out how to use libpng. See libpng-manual.txt for the * full explanation, see example.c for the summary. This just provides * a simple one line description of the use of each function. * * The PNG_EXPORT() and PNG_EXPORTA() macros used below are defined in * pngconf.h and in the *.dfn files in the scripts directory. * * PNG_EXPORT(ordinal, type, name, (args)); * * ordinal: ordinal that is used while building * *.def files. The ordinal value is only * relevant when preprocessing png.h with * the *.dfn files for building symbol table * entries, and are removed by pngconf.h. * type: return type of the function * name: function name * args: function arguments, with types * * When we wish to append attributes to a function prototype we use * the PNG_EXPORTA() macro instead. * * PNG_EXPORTA(ordinal, type, name, (args), attributes); * * ordinal, type, name, and args: same as in PNG_EXPORT(). * attributes: function attributes */ /* Returns the version number of the library */ PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); /* Tell lib we have already handled the first magic bytes. * Handling more than 8 bytes from the beginning of the file is an error. */ PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes)); /* Check sig[start] through sig[start + num_to_check - 1] to see if it's a * PNG file. Returns zero if the supplied bytes match the 8-byte PNG * signature, and non-zero otherwise. Having num_to_check == 0 or * start > 7 will always fail (ie return non-zero). */ PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, png_size_t start, png_size_t num_to_check)); /* Simple signature checking function. This is the same as calling * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). */ #define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n)) /* Allocate and initialize png_ptr struct for reading, and any other memory. */ PNG_EXPORTA(4, png_structp, png_create_read_struct, (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn), PNG_ALLOCATED); /* Allocate and initialize png_ptr struct for writing, and any other memory */ PNG_EXPORTA(5, png_structp, png_create_write_struct, (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn), PNG_ALLOCATED); PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, (png_const_structrp png_ptr)); PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, png_size_t size)); /* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp * match up. */ #ifdef PNG_SETJMP_SUPPORTED /* This function returns the jmp_buf built in to *png_ptr. It must be * supplied with an appropriate 'longjmp' function to use on that jmp_buf * unless the default error function is overridden in which case NULL is * acceptable. The size of the jmp_buf is checked against the actual size * allocated by the library - the call will return NULL on a mismatch * indicating an ABI mismatch. */ PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); # define png_jmpbuf(png_ptr) \ (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) #else # define png_jmpbuf(png_ptr) \ (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP) #endif /* This function should be used by libpng applications in place of * longjmp(png_ptr->jmpbuf, val). If longjmp_fn() has been set, it * will use it; otherwise it will call PNG_ABORT(). This function was * added in libpng-1.5.0. */ PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), PNG_NORETURN); #ifdef PNG_READ_SUPPORTED /* Reset the compression stream */ PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); #endif /* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ #ifdef PNG_USER_MEM_SUPPORTED PNG_EXPORTA(11, png_structp, png_create_read_struct_2, (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), PNG_ALLOCATED); PNG_EXPORTA(12, png_structp, png_create_write_struct_2, (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), PNG_ALLOCATED); #endif /* Write the PNG file signature. */ PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); /* Write a PNG chunk - size, type, (optional) data, CRC. */ PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep chunk_name, png_const_bytep data, png_size_t length)); /* Write the start of a PNG chunk - length and chunk name. */ PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, png_const_bytep chunk_name, png_uint_32 length)); /* Write the data of a PNG chunk started with png_write_chunk_start(). */ PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, png_const_bytep data, png_size_t length)); /* Finish a chunk started with png_write_chunk_start() (includes CRC). */ PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); /* Allocate and initialize the info structure */ PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), PNG_ALLOCATED); /* DEPRECATED: this function allowed init structures to be created using the * default allocation method (typically malloc). Use is deprecated in 1.6.0 and * the API will be removed in the future. */ PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, png_size_t png_info_struct_size), PNG_DEPRECATED); /* Writes all the PNG information before the image. */ PNG_EXPORT(20, void, png_write_info_before_PLTE, (png_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(21, void, png_write_info, (png_structrp png_ptr, png_const_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the information before the actual image data. */ PNG_EXPORT(22, void, png_read_info, (png_structrp png_ptr, png_inforp info_ptr)); #endif #ifdef PNG_TIME_RFC1123_SUPPORTED /* Convert to a US string format: there is no localization support in this * routine. The original implementation used a 29 character buffer in * png_struct, this will be removed in future versions. */ #if PNG_LIBPNG_VER < 10700 /* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, png_const_timep ptime),PNG_DEPRECATED); #endif PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], png_const_timep ptime)); #endif #ifdef PNG_CONVERT_tIME_SUPPORTED /* Convert from a struct tm to png_time */ PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, const struct tm * ttime)); /* Convert from time_t to png_time. Uses gmtime() */ PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); #endif /* CONVERT_tIME */ #ifdef PNG_READ_EXPAND_SUPPORTED /* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED /* Expand to 16-bit channels, forces conversion of palette to RGB and expansion * of a tRNS chunk if present. */ PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Use blue, green, red order for pixels. */ PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand the grayscale to 24-bit RGB if necessary. */ PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Reduce RGB to grayscale. */ #define PNG_ERROR_ACTION_NONE 1 #define PNG_ERROR_ACTION_WARN 2 #define PNG_ERROR_ACTION_ERROR 3 #define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, int error_action, double red, double green)) PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, int error_action, png_fixed_point red, png_fixed_point green)) PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp png_ptr)); #endif #ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, png_colorp palette)); #endif #ifdef PNG_READ_ALPHA_MODE_SUPPORTED /* How the alpha channel is interpreted - this affects how the color channels * of a PNG file are returned to the calling application when an alpha channel, * or a tRNS chunk in a palette file, is present. * * This has no effect on the way pixels are written into a PNG output * datastream. The color samples in a PNG datastream are never premultiplied * with the alpha samples. * * The default is to return data according to the PNG specification: the alpha * channel is a linear measure of the contribution of the pixel to the * corresponding composited pixel, and the color channels are unassociated * (not premultiplied). The gamma encoded color channels must be scaled * according to the contribution and to do this it is necessary to undo * the encoding, scale the color values, perform the composition and reencode * the values. This is the 'PNG' mode. * * The alternative is to 'associate' the alpha with the color information by * storing color channel values that have been scaled by the alpha. * image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes * (the latter being the two common names for associated alpha color channels). * * For the 'OPTIMIZED' mode, a pixel is treated as opaque only if the alpha * value is equal to the maximum value. * * The final choice is to gamma encode the alpha channel as well. This is * broken because, in practice, no implementation that uses this choice * correctly undoes the encoding before handling alpha composition. Use this * choice only if other serious errors in the software or hardware you use * mandate it; the typical serious error is for dark halos to appear around * opaque areas of the composited PNG image because of arithmetic overflow. * * The API function png_set_alpha_mode specifies which of these choices to use * with an enumerated 'mode' value and the gamma of the required output: */ #define PNG_ALPHA_PNG 0 /* according to the PNG standard */ #define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ #define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ #define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ #define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ #define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, double output_gamma)) PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, int mode, png_fixed_point output_gamma)) #endif #if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* The output_gamma value is a screen gamma in libpng terminology: it expresses * how to decode the output values, not how they are encoded. */ #define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ #define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ #define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ #define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ #endif /* The following are examples of calls to png_set_alpha_mode to achieve the * required overall gamma correction and, where necessary, alpha * premultiplication. * * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); * This is the default libpng handling of the alpha channel - it is not * pre-multiplied into the color components. In addition the call states * that the output is for a sRGB system and causes all PNG files without gAMA * chunks to be assumed to be encoded using sRGB. * * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); * In this case the output is assumed to be something like an sRGB conformant * display preceeded by a power-law lookup table of power 1.45. This is how * early Mac systems behaved. * * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); * This is the classic Jim Blinn approach and will work in academic * environments where everything is done by the book. It has the shortcoming * of assuming that input PNG data with no gamma information is linear - this * is unlikely to be correct unless the PNG files where generated locally. * Most of the time the output precision will be so low as to show * significant banding in dark areas of the image. * * png_set_expand_16(pp); * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); * This is a somewhat more realistic Jim Blinn inspired approach. PNG files * are assumed to have the sRGB encoding if not marked with a gamma value and * the output is always 16 bits per component. This permits accurate scaling * and processing of the data. If you know that your input PNG files were * generated locally you might need to replace PNG_DEFAULT_sRGB with the * correct value for your system. * * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); * If you just need to composite the PNG image onto an existing background * and if you control the code that does this you can use the optimization * setting. In this case you just copy completely opaque pixels to the * output. For pixels that are not completely transparent (you just skip * those) you do the composition math using png_composite or png_composite_16 * below then encode the resultant 8-bit or 16-bit values to match the output * encoding. * * Other cases * If neither the PNG nor the standard linear encoding work for you because * of the software or hardware you use then you have a big problem. The PNG * case will probably result in halos around the image. The linear encoding * will probably result in a washed out, too bright, image (it's actually too * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably * substantially reduce the halos. Alternatively try: * * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); * This option will also reduce the halos, but there will be slight dark * halos round the opaque parts of the image where the background is light. * In the OPTIMIZED mode the halos will be light halos where the background * is dark. Take your pick - the halos are unavoidable unless you can get * your hardware/software fixed! (The OPTIMIZED approach is slightly * faster.) * * When the default gamma of PNG files doesn't match the output gamma. * If you have PNG files with no gamma information png_set_alpha_mode allows * you to provide a default gamma, but it also sets the ouput gamma to the * matching value. If you know your PNG files have a gamma that doesn't * match the output you can take advantage of the fact that * png_set_alpha_mode always sets the output gamma but only sets the PNG * default if it is not already set: * * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); * The first call sets both the default and the output gamma values, the * second call overrides the output gamma without changing the default. This * is easier than achieving the same effect with png_set_gamma. You must use * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will * fire if more than one call to png_set_alpha_mode and png_set_background is * made in the same read operation, however multiple calls with PNG_ALPHA_PNG * are ignored. */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) /* Add a filler byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */ PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler, int flags)); /* The values of the PNG_FILLER_ defines should NOT be changed */ # define PNG_FILLER_BEFORE 0 # define PNG_FILLER_AFTER 1 /* Add an alpha byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */ PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, png_uint_32 filler, int flags)); #endif /* READ_FILLER || WRITE_FILLER */ #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Swap bytes in 16-bit depth files. */ PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr)); #endif #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) /* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ defined(PNG_WRITE_PACKSWAP_SUPPORTED) /* Swap packing order of pixels in bytes. */ PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) /* Converts files to legal bit depths. */ PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p true_bits)); #endif #if defined(PNG_READ_INTERLACING_SUPPORTED) || \ defined(PNG_WRITE_INTERLACING_SUPPORTED) /* Have the code handle the interlacing. Returns the number of passes. * MUST be called before png_read_update_info or png_start_read_image, * otherwise it will not have the desired effect. Note that it is still * necessary to call png_read_row or png_read_rows png_get_image_height * times for each pass. */ PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) /* Invert monochrome files */ PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED /* Handle alpha and tRNS by replacing with a background color. Prior to * libpng-1.5.4 this API must not be called before the PNG file header has been * read. Doing so will result in unexpected behavior and possible warnings or * errors if the PNG file contains a bKGD chunk. */ PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma)) PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, png_fixed_point background_gamma)) #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED # define PNG_BACKGROUND_GAMMA_UNKNOWN 0 # define PNG_BACKGROUND_GAMMA_SCREEN 1 # define PNG_BACKGROUND_GAMMA_FILE 2 # define PNG_BACKGROUND_GAMMA_UNIQUE 3 #endif #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale a 16-bit depth file down to 8-bit, accurately. */ PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED #define PNG_READ_16_TO_8_SUPPORTED /* Name prior to 1.5.4 */ /* Strip the second byte of information from a 16-bit depth file. */ PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED /* Turn on quantizing, and reduce the palette to the number of colors * available. */ PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, png_colorp palette, int num_palette, int maximum_colors, png_const_uint_16p histogram, int full_quantize)); #endif #ifdef PNG_READ_GAMMA_SUPPORTED /* The threshold on gamma processing is configurable but hard-wired into the * library. The following is the floating point variant. */ #define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) /* Handle gamma correction. Screen_gamma=(display_exponent). * NOTE: this API simply sets the screen and file gamma values. It will * therefore override the value for gamma in a PNG file if it is called after * the file header has been read - use with care - call before reading the PNG * file for best results! * * These routines accept the same gamma values as png_set_alpha_mode (described * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either * API (floating point or fixed.) Notice, however, that the 'file_gamma' value * is the inverse of a 'screen gamma' value. */ PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, double screen_gamma, double override_file_gamma)) PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) #endif #ifdef PNG_WRITE_FLUSH_SUPPORTED /* Set how many lines between output flushes - 0 for no flushing */ PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); /* Flush the current PNG output buffer */ PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); #endif /* Optional update palette with requested transformations */ PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); /* Optional call to update the users info structure */ PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, png_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. */ PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read a row of data. */ PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, png_bytep display_row)); #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the whole image into memory at once. */ PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); #endif /* Write a row of image data */ PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, png_const_bytep row)); /* Write a few rows of image data: (*row) is not written; however, the type * is declared as writeable to maintain compatibility with previous versions * of libpng and to allow the 'display_row' array from read_rows to be passed * unchanged to write_rows. */ PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, png_uint_32 num_rows)); /* Write the image data */ PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); /* Write the end of the PNG file. */ PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, png_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. */ PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); #endif /* Free any memory associated with the png_info_struct */ PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, png_infopp info_ptr_ptr)); /* Free any memory associated with the png_struct and the png_info_structs */ PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); /* Free any memory associated with the png_struct and the png_info_structs */ PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); /* Set the libpng method of handling chunk CRC errors */ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, int ancil_action)); /* Values for png_set_crc_action() say how to handle CRC errors in * ancillary and critical chunks, and whether to use the data contained * therein. Note that it is impossible to "discard" data in a critical * chunk. For versions prior to 0.90, the action was always error/quit, * whereas in version 0.90 and later, the action for CRC errors in ancillary * chunks is warn/discard. These values should NOT be changed. * * value action:critical action:ancillary */ #define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */ #define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */ #define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */ #define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */ #define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ #define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ #ifdef PNG_WRITE_SUPPORTED /* These functions give the user control over the scan-line filtering in * libpng and the compression methods used by zlib. These functions are * mainly useful for testing, as the defaults should work with most users. * Those users who are tight on memory or want faster performance at the * expense of compression can modify them. See the compression library * header file (zlib.h) for an explination of the compression functions. */ /* Set the filtering method(s) used by libpng. Currently, the only valid * value for "method" is 0. */ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, int filters)); #endif /* WRITE */ /* Flags for png_set_filter() to say which filters to use. The flags * are chosen so that they don't conflict with real filter types * below, in case they are supplied instead of the #defined constants. * These values should NOT be changed. */ #define PNG_NO_FILTERS 0x00 #define PNG_FILTER_NONE 0x08 #define PNG_FILTER_SUB 0x10 #define PNG_FILTER_UP 0x20 #define PNG_FILTER_AVG 0x40 #define PNG_FILTER_PAETH 0x80 #define PNG_FAST_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP) #define PNG_ALL_FILTERS (PNG_FAST_FILTERS | PNG_FILTER_AVG | PNG_FILTER_PAETH) /* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. * These defines should NOT be changed. */ #define PNG_FILTER_VALUE_NONE 0 #define PNG_FILTER_VALUE_SUB 1 #define PNG_FILTER_VALUE_UP 2 #define PNG_FILTER_VALUE_AVG 3 #define PNG_FILTER_VALUE_PAETH 4 #define PNG_FILTER_VALUE_LAST 5 #ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, int heuristic_method, int num_weights, png_const_doublep filter_weights, png_const_doublep filter_costs)) PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, (png_structrp png_ptr, int heuristic_method, int num_weights, png_const_fixed_point_p filter_weights, png_const_fixed_point_p filter_costs)) #endif /* WRITE_WEIGHTED_FILTER */ /* The following are no longer used and will be removed from libpng-1.7: */ #define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ #define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ #define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ #define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ /* Set the library compression level. Currently, valid values range from * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 * (0 - no compression, 9 - "maximal" compression). Note that tests have * shown that zlib compression levels 3-6 usually perform as well as level 9 * for PNG images, and do considerably fewer caclulations. In the future, * these values may not correspond directly to the zlib compression levels. */ #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, int level)); PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, int mem_level)); PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, int strategy)); /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a * smaller value of window_bits if it can do so safely. */ PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, int window_bits)); PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, int method)); #endif /* WRITE_CUSTOMIZE_COMPRESSION */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED /* Also set zlib parameters for compressing non-IDAT chunks */ PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, int level)); PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, int mem_level)); PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, int strategy)); /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a * smaller value of window_bits if it can do so safely. */ PNG_EXPORT(225, void, png_set_text_compression_window_bits, (png_structrp png_ptr, int window_bits)); PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, int method)); #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ #endif /* WRITE */ /* These next functions are called for input/output, memory, and error * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, * and call standard C I/O routines such as fread(), fwrite(), and * fprintf(). These functions can be made to use other I/O routines * at run time for those applications that need to handle I/O in a * different manner by calling png_set_???_fn(). See libpng-manual.txt for * more information. */ #ifdef PNG_STDIO_SUPPORTED /* Initialize the input/output for the PNG file to the default functions. */ PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp)); #endif /* Replace the (error and abort), and warning functions with user * supplied functions. If no messages are to be printed you must still * write and use replacement functions. The replacement error_fn should * still do a longjmp to the last setjmp location if you are using this * method of error handling. If error_fn or warning_fn is NULL, the * default function will be used. */ PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); /* Return the user pointer associated with the error functions */ PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr)); /* Replace the default data output functions with a user supplied one(s). * If buffered output is not used, then output_flush_fn can be set to NULL. * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time * output_flush_fn will be ignored (and thus can be NULL). * It is probably a mistake to use NULL for output_flush_fn if * write_data_fn is not also NULL unless you have built libpng with * PNG_WRITE_FLUSH_SUPPORTED undefined, because in this case libpng's * default flush function, which uses the standard *FILE structure, will * be used. */ PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); /* Replace the default data input function with a user supplied one. */ PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn)); /* Return the user pointer associated with the I/O functions */ PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, png_read_status_ptr read_row_fn)); PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr, png_write_status_ptr write_row_fn)); #ifdef PNG_USER_MEM_SUPPORTED /* Replace the default memory allocation functions with user supplied one(s). */ PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); /* Return the user pointer associated with the memory functions */ PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); #endif #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, png_user_transform_ptr read_user_transform_fn)); #endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn)); #endif #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr, png_voidp user_transform_ptr, int user_transform_depth, int user_transform_channels)); /* Return the user pointer associated with the user transform functions */ PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, (png_const_structrp png_ptr)); #endif #ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED /* Return information about the row currently being processed. Note that these * APIs do not fail but will return unexpected results if called outside a user * transform callback. Also note that when transforming an interlaced image the * row number is the row number within the sub-image of the interlace pass, so * the value will increase to the height of the sub-image (not the full image) * then reset to 0 for the next pass. * * Use PNG_ROW_FROM_PASS_ROW(row, pass) and PNG_COL_FROM_PASS_COL(col, pass) to * find the output pixel (x,y) given an interlaced sub-image pixel * (row,col,pass). (See below for these macros.) */ PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); #endif #ifdef PNG_READ_USER_CHUNKS_SUPPORTED /* This callback is called only for *unknown* chunks. If * PNG_HANDLE_AS_UNKNOWN_SUPPORTED is set then it is possible to set known * chunks to be treated as unknown, however in this case the callback must do * any processing required by the chunk (e.g. by calling the appropriate * png_set_ APIs.) * * There is no write support - on write, by default, all the chunks in the * 'unknown' list are written in the specified position. * * The integer return from the callback function is interpreted thus: * * negative: An error occurred; png_chunk_error will be called. * zero: The chunk was not handled, the chunk will be saved. A critical * chunk will cause an error at this point unless it is to be saved. * positive: The chunk was handled, libpng will ignore/discard it. * * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about * how this behavior will change in libpng 1.7 */ PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); #endif #ifdef PNG_USER_CHUNKS_SUPPORTED PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr)); #endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED /* Sets the function callbacks for the push reader, and a pointer to a * user-defined structure available to the callback functions. */ PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr, png_voidp progressive_ptr, png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); /* Returns the user pointer associated with the push read functions */ PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, (png_const_structrp png_ptr)); /* Function to be called when data becomes available */ PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size)); /* A function which may be called *only* within png_process_data to stop the * processing of any more data. The function returns the number of bytes * remaining, excluding any that libpng has cached internally. A subsequent * call to png_process_data must supply these bytes again. If the argument * 'save' is set to true the routine will first save all the pending data and * will always return 0. */ PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save)); /* A function which may be called *only* outside (after) a call to * png_process_data. It returns the number of bytes of data to skip in the * input. Normally it will return 0, but if it returns a non-zero value the * application must skip than number of bytes of input data and pass the * following data to the next call to png_process_data. */ PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); /* Function that combines rows. 'new_row' is a flag that should come from * the callback and be non-NULL if anything needs to be done; the library * stores its own version of the new data internally and ignores the passed * in value. */ PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, png_bytep old_row, png_const_bytep new_row)); #endif /* PROGRESSIVE_READ */ PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, png_alloc_size_t size), PNG_ALLOCATED); /* Added at libpng version 1.4.0 */ PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, png_alloc_size_t size), PNG_ALLOCATED); /* Added at libpng version 1.2.4 */ PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, png_alloc_size_t size), PNG_ALLOCATED); /* Frees a pointer allocated by png_malloc() */ PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); /* Free data that was allocated internally */ PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 free_me, int num)); /* Reassign responsibility for freeing existing data, whether allocated * by libpng or by the application; this works on the png_info structure passed * in, it does not change the state for other png_info structures. * * It is unlikely that this function works correctly as of 1.6.0 and using it * may result either in memory leaks or double free of allocated data. */ PNG_EXPORT(99, void, png_data_freer, (png_const_structrp png_ptr, png_inforp info_ptr, int freer, png_uint_32 mask)); /* Assignments for png_data_freer */ #define PNG_DESTROY_WILL_FREE_DATA 1 #define PNG_SET_WILL_FREE_DATA 1 #define PNG_USER_WILL_FREE_DATA 2 /* Flags for png_ptr->free_me and info_ptr->free_me */ #define PNG_FREE_HIST 0x0008U #define PNG_FREE_ICCP 0x0010U #define PNG_FREE_SPLT 0x0020U #define PNG_FREE_ROWS 0x0040U #define PNG_FREE_PCAL 0x0080U #define PNG_FREE_SCAL 0x0100U #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED # define PNG_FREE_UNKN 0x0200U #endif /* PNG_FREE_LIST 0x0400U removed in 1.6.0 because it is ignored */ #define PNG_FREE_PLTE 0x1000U #define PNG_FREE_TRNS 0x2000U #define PNG_FREE_TEXT 0x4000U #define PNG_FREE_EXIF 0x8000U /* Added at libpng-1.6.31 */ #define PNG_FREE_ALL 0xffffU #define PNG_FREE_MUL 0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ #ifdef PNG_USER_MEM_SUPPORTED PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, png_voidp ptr), PNG_DEPRECATED); #endif #ifdef PNG_ERROR_TEXT_SUPPORTED /* Fatal error in PNG image of libpng - can't continue */ PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN); /* The same, but the chunk name is prepended to the error string. */ PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN); #else /* Fatal error in PNG image of libpng - can't continue */ PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); # define png_error(s1,s2) png_err(s1) # define png_chunk_error(s1,s2) png_err(s1) #endif #ifdef PNG_WARNINGS_SUPPORTED /* Non-fatal error in libpng. Can continue, but may have a problem. */ PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, png_const_charp warning_message)); /* Non-fatal error in libpng, chunk name is prepended to message. */ PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, png_const_charp warning_message)); #else # define png_warning(s1,s2) ((void)(s1)) # define png_chunk_warning(s1,s2) ((void)(s1)) #endif #ifdef PNG_BENIGN_ERRORS_SUPPORTED /* Benign error in libpng. Can continue, but may have a problem. * User can choose whether to handle as a fatal error or as a warning. */ PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, png_const_charp warning_message)); #ifdef PNG_READ_SUPPORTED /* Same, chunk name is prepended to message (only during read) */ PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, png_const_charp warning_message)); #endif PNG_EXPORT(109, void, png_set_benign_errors, (png_structrp png_ptr, int allowed)); #else # ifdef PNG_ALLOW_BENIGN_ERRORS # define png_benign_error png_warning # define png_chunk_benign_error png_chunk_warning # else # define png_benign_error png_error # define png_chunk_benign_error png_chunk_error # endif #endif /* The png_set_ functions are for storing values in the png_info_struct. * Similarly, the png_get_ calls are used to read values from the * png_info_struct, either storing the parameters in the passed variables, or * setting pointers into the png_info_struct where the data is stored. The * png_get_ functions return a non-zero value if the data was available * in info_ptr, or return zero and do not change any of the parameters if the * data was not available. * * These functions should be used instead of directly accessing png_info * to avoid problems with future changes in the size and internal layout of * png_info_struct. */ /* Returns "flag" if chunk data is valid in info_ptr. */ PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 flag)); /* Returns number of bytes needed to hold a transformed row. */ PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr, png_const_inforp info_ptr)); #ifdef PNG_INFO_IMAGE_SUPPORTED /* Returns row_pointers, which is an array of pointers to scanlines that was * returned from png_read_png(). */ PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Set row_pointers, which is an array of pointers to scanlines for use * by png_write_png(). */ PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, png_inforp info_ptr, png_bytepp row_pointers)); #endif /* Returns number of color channels in image. */ PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, png_const_inforp info_ptr)); #ifdef PNG_EASY_ACCESS_SUPPORTED /* Returns image width in pixels. */ PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns image height in pixels. */ PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns image bit_depth. */ PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns image color_type. */ PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns image filter_type. */ PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns image interlace_type. */ PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns image compression_type. */ PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns image resolution in pixels per meter, from pHYs chunk data. */ PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns pixel aspect ratio, computed from pHYs chunk data. */ PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, (png_const_structrp png_ptr, png_const_inforp info_ptr)) PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, (png_const_structrp png_ptr, png_const_inforp info_ptr)) /* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, (png_const_structrp png_ptr, png_const_inforp info_ptr)); #endif /* EASY_ACCESS */ #ifdef PNG_READ_SUPPORTED /* Returns pointer to signature string read from PNG header */ PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, png_const_inforp info_ptr)); #endif #ifdef PNG_bKGD_SUPPORTED PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, png_inforp info_ptr, png_color_16p *background)); #endif #ifdef PNG_bKGD_SUPPORTED PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_color_16p background)); #endif #ifdef PNG_cHRM_SUPPORTED PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, double *red_y, double *green_x, double *green_y, double *blue_x, double *blue_y)) PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, double *green_X, double *green_Y, double *green_Z, double *blue_X, double *blue_Y, double *blue_Z)) PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_white_x, png_fixed_point *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)) PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_red_X, png_fixed_point *int_red_Y, png_fixed_point *int_red_Z, png_fixed_point *int_green_X, png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, png_fixed_point *int_blue_Z)) #endif #ifdef PNG_cHRM_SUPPORTED PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, png_inforp info_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, double green_y, double blue_x, double blue_y)) PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, png_inforp info_ptr, double red_X, double red_Y, double red_Z, double green_X, double green_Y, double green_Z, double blue_X, double blue_Y, double blue_Z)) PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y, png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, png_fixed_point int_blue_y)) PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, png_fixed_point int_red_Z, png_fixed_point int_green_X, png_fixed_point int_green_Y, png_fixed_point int_green_Z, png_fixed_point int_blue_X, png_fixed_point int_blue_Y, png_fixed_point int_blue_Z)) #endif #ifdef PNG_eXIf_SUPPORTED PNG_EXPORT(246, png_uint_32, png_get_eXIf, (png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *exif)); PNG_EXPORT(247, void, png_set_eXIf, (png_const_structrp png_ptr, png_inforp info_ptr, const png_bytep exif)); PNG_EXPORT(248, png_uint_32, png_get_eXIf_1, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *num_exif, png_bytep *exif)); PNG_EXPORT(249, void, png_set_eXIf_1, (png_const_structrp png_ptr, png_inforp info_ptr, const png_uint_32 num_exif, const png_bytep exif)); #endif #ifdef PNG_gAMA_SUPPORTED PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, png_const_inforp info_ptr, double *file_gamma)) PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_file_gamma)) #endif #ifdef PNG_gAMA_SUPPORTED PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)) PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point int_file_gamma)) #endif #ifdef PNG_hIST_SUPPORTED PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, png_inforp info_ptr, png_uint_16p *hist)); PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_uint_16p hist)); #endif PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, int *interlace_method, int *compression_method, int *filter_method)); PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_method, int compression_method, int filter_method)); #ifdef PNG_oFFs_SUPPORTED PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)); #endif #ifdef PNG_oFFs_SUPPORTED PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, int unit_type)); #endif #ifdef PNG_pCAL_SUPPORTED PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, png_charp *units, png_charpp *params)); #endif #ifdef PNG_pCAL_SUPPORTED PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params)); #endif #ifdef PNG_pHYs_SUPPORTED PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); #endif #ifdef PNG_pHYs_SUPPORTED PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); #endif PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, png_inforp info_ptr, png_colorp *palette, int *num_palette)); PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, png_inforp info_ptr, png_const_colorp palette, int num_palette)); #ifdef PNG_sBIT_SUPPORTED PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, png_inforp info_ptr, png_color_8p *sig_bit)); #endif #ifdef PNG_sBIT_SUPPORTED PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_color_8p sig_bit)); #endif #ifdef PNG_sRGB_SUPPORTED PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, png_const_inforp info_ptr, int *file_srgb_intent)); #endif #ifdef PNG_sRGB_SUPPORTED PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)); PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)); #endif #ifdef PNG_iCCP_SUPPORTED PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, png_inforp info_ptr, png_charpp name, int *compression_type, png_bytepp profile, png_uint_32 *proflen)); #endif #ifdef PNG_iCCP_SUPPORTED PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp name, int compression_type, png_const_bytep profile, png_uint_32 proflen)); #endif #ifdef PNG_sPLT_SUPPORTED PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, png_inforp info_ptr, png_sPLT_tpp entries)); #endif #ifdef PNG_sPLT_SUPPORTED PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); #endif #ifdef PNG_TEXT_SUPPORTED /* png_get_text also returns the number of text chunks in *num_text */ PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, png_inforp info_ptr, png_textp *text_ptr, int *num_text)); #endif /* Note while png_set_text() will accept a structure whose text, * language, and translated keywords are NULL pointers, the structure * returned by png_get_text will always contain regular * zero-terminated C strings. They might be empty strings but * they will never be NULL pointers. */ #ifdef PNG_TEXT_SUPPORTED PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_textp text_ptr, int num_text)); #endif #ifdef PNG_tIME_SUPPORTED PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, png_inforp info_ptr, png_timep *mod_time)); #endif #ifdef PNG_tIME_SUPPORTED PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_timep mod_time)); #endif #ifdef PNG_tRNS_SUPPORTED PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)); #endif #ifdef PNG_tRNS_SUPPORTED PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)); #endif #ifdef PNG_sCAL_SUPPORTED PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, double *width, double *height)) #if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ defined(PNG_FLOATING_POINT_SUPPORTED) /* NOTE: this API is currently implemented using floating point arithmetic, * consequently it can only be used on systems with floating point support. * In any case the range of values supported by png_fixed_point is small and it * is highly recommended that png_get_sCAL_s be used instead. */ PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, png_fixed_point *width, png_fixed_point *height)) #endif PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, png_charpp swidth, png_charpp sheight)); PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, png_inforp info_ptr, int unit, double width, double height)) PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_fixed_point width, png_fixed_point height)) PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_const_charp swidth, png_const_charp sheight)); #endif /* sCAL */ #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED /* Provide the default handling for all unknown chunks or, optionally, for * specific unknown chunks. * * NOTE: prior to 1.6.0 the handling specified for particular chunks on read was * ignored and the default was used, the per-chunk setting only had an effect on * write. If you wish to have chunk-specific handling on read in code that must * work on earlier versions you must use a user chunk callback to specify the * desired handling (keep or discard.) * * The 'keep' parameter is a PNG_HANDLE_CHUNK_ value as listed below. The * parameter is interpreted as follows: * * READ: * PNG_HANDLE_CHUNK_AS_DEFAULT: * Known chunks: do normal libpng processing, do not keep the chunk (but * see the comments below about PNG_HANDLE_AS_UNKNOWN_SUPPORTED) * Unknown chunks: for a specific chunk use the global default, when used * as the default discard the chunk data. * PNG_HANDLE_CHUNK_NEVER: * Discard the chunk data. * PNG_HANDLE_CHUNK_IF_SAFE: * Keep the chunk data if the chunk is not critical else raise a chunk * error. * PNG_HANDLE_CHUNK_ALWAYS: * Keep the chunk data. * * If the chunk data is saved it can be retrieved using png_get_unknown_chunks, * below. Notice that specifying "AS_DEFAULT" as a global default is equivalent * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks * it simply resets the behavior to the libpng default. * * INTERACTION WTIH USER CHUNK CALLBACKS: * The per-chunk handling is always used when there is a png_user_chunk_ptr * callback and the callback returns 0; the chunk is then always stored *unless* * it is critical and the per-chunk setting is other than ALWAYS. Notice that * the global default is *not* used in this case. (In effect the per-chunk * value is incremented to at least IF_SAFE.) * * IMPORTANT NOTE: this behavior will change in libpng 1.7 - the global and * per-chunk defaults will be honored. If you want to preserve the current * behavior when your callback returns 0 you must set PNG_HANDLE_CHUNK_IF_SAFE * as the default - if you don't do this libpng 1.6 will issue a warning. * * If you want unhandled unknown chunks to be discarded in libpng 1.6 and * earlier simply return '1' (handled). * * PNG_HANDLE_AS_UNKNOWN_SUPPORTED: * If this is *not* set known chunks will always be handled by libpng and * will never be stored in the unknown chunk list. Known chunks listed to * png_set_keep_unknown_chunks will have no effect. If it is set then known * chunks listed with a keep other than AS_DEFAULT will *never* be processed * by libpng, in addition critical chunks must either be processed by the * callback or saved. * * The IHDR and IEND chunks must not be listed. Because this turns off the * default handling for chunks that would otherwise be recognized the * behavior of libpng transformations may well become incorrect! * * WRITE: * When writing chunks the options only apply to the chunks specified by * png_set_unknown_chunks (below), libpng will *always* write known chunks * required by png_set_ calls and will always write the core critical chunks * (as required for PLTE). * * Each chunk in the png_set_unknown_chunks list is looked up in the * png_set_keep_unknown_chunks list to find the keep setting, this is then * interpreted as follows: * * PNG_HANDLE_CHUNK_AS_DEFAULT: * Write safe-to-copy chunks and write other chunks if the global * default is set to _ALWAYS, otherwise don't write this chunk. * PNG_HANDLE_CHUNK_NEVER: * Do not write the chunk. * PNG_HANDLE_CHUNK_IF_SAFE: * Write the chunk if it is safe-to-copy, otherwise do not write it. * PNG_HANDLE_CHUNK_ALWAYS: * Write the chunk. * * Note that the default behavior is effectively the opposite of the read case - * in read unknown chunks are not stored by default, in write they are written * by default. Also the behavior of PNG_HANDLE_CHUNK_IF_SAFE is very different * - on write the safe-to-copy bit is checked, on read the critical bit is * checked and on read if the chunk is critical an error will be raised. * * num_chunks: * =========== * If num_chunks is positive, then the "keep" parameter specifies the manner * for handling only those chunks appearing in the chunk_list array, * otherwise the chunk list array is ignored. * * If num_chunks is 0 the "keep" parameter specifies the default behavior for * unknown chunks, as described above. * * If num_chunks is negative, then the "keep" parameter specifies the manner * for handling all unknown chunks plus all chunks recognized by libpng * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to * be processed by libpng. */ #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, int keep, png_const_bytep chunk_list, int num_chunks)); #endif /* HANDLE_AS_UNKNOWN */ /* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; * the result is therefore true (non-zero) if special handling is required, * false for the default handling. */ PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, png_const_bytep chunk_name)); #endif /* SET_UNKNOWN_CHUNKS */ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)); /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added * unknowns to the location currently stored in the png_struct. This is * invariably the wrong value on write. To fix this call the following API * for each chunk in the list with the correct location. If you know your * code won't be compiled on earlier versions you can rely on * png_set_unknown_chunks(write-ptr, png_get_unknown_chunks(read-ptr)) doing * the correct thing. */ PNG_EXPORT(175, void, png_set_unknown_chunk_location, (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, png_inforp info_ptr, png_unknown_chunkpp entries)); #endif /* Png_free_data() will turn off the "valid" flag for anything it frees. * If you need to turn it off for a chunk that your application has freed, * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */ PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, png_inforp info_ptr, int mask)); #ifdef PNG_INFO_IMAGE_SUPPORTED /* The "params" pointer is currently not used and is for future expansion. */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params)); #endif #ifdef PNG_WRITE_SUPPORTED PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params)); #endif #endif PNG_EXPORT(180, png_const_charp, png_get_copyright, (png_const_structrp png_ptr)); PNG_EXPORT(181, png_const_charp, png_get_header_ver, (png_const_structrp png_ptr)); PNG_EXPORT(182, png_const_charp, png_get_header_version, (png_const_structrp png_ptr)); PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, (png_const_structrp png_ptr)); #ifdef PNG_MNG_FEATURES_SUPPORTED PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, png_uint_32 mng_features_permitted)); #endif /* For use in png_set_keep_unknown, added to version 1.2.6 */ #define PNG_HANDLE_CHUNK_AS_DEFAULT 0 #define PNG_HANDLE_CHUNK_NEVER 1 #define PNG_HANDLE_CHUNK_IF_SAFE 2 #define PNG_HANDLE_CHUNK_ALWAYS 3 #define PNG_HANDLE_CHUNK_LAST 4 /* Strip the prepended error numbers ("#nnn ") from error and warning * messages before passing them to the error or warning handler. */ #ifdef PNG_ERROR_NUMBERS_SUPPORTED PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, png_uint_32 strip_mode)); #endif /* Added in libpng-1.2.6 */ #ifdef PNG_SET_USER_LIMITS_SUPPORTED PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); PNG_EXPORT(187, png_uint_32, png_get_user_width_max, (png_const_structrp png_ptr)); PNG_EXPORT(188, png_uint_32, png_get_user_height_max, (png_const_structrp png_ptr)); /* Added in libpng-1.4.0 */ PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)); PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, (png_const_structrp png_ptr)); /* Added in libpng-1.4.1 */ PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, png_alloc_size_t user_chunk_cache_max)); PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, (png_const_structrp png_ptr)); #endif #if defined(PNG_INCH_CONVERSIONS_SUPPORTED) PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_FP_EXPORT(196, float, png_get_x_offset_inches, (png_const_structrp png_ptr, png_const_inforp info_ptr)) #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, (png_const_structrp png_ptr, png_const_inforp info_ptr)) #endif PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, png_const_inforp info_ptr)) #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, (png_const_structrp png_ptr, png_const_inforp info_ptr)) #endif # ifdef PNG_pHYs_SUPPORTED PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); # endif /* pHYs */ #endif /* INCH_CONVERSIONS */ /* Added in libpng-1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); /* Removed from libpng 1.6; use png_get_io_chunk_type. */ PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), PNG_DEPRECATED) PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, (png_const_structrp png_ptr)); /* The flags returned by png_get_io_state() are the following: */ # define PNG_IO_NONE 0x0000 /* no I/O at this moment */ # define PNG_IO_READING 0x0001 /* currently reading */ # define PNG_IO_WRITING 0x0002 /* currently writing */ # define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ # define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ # define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ # define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ # define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ # define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ #endif /* IO_STATE */ /* Interlace support. The following macros are always defined so that if * libpng interlace handling is turned off the macros may be used to handle * interlaced images within the application. */ #define PNG_INTERLACE_ADAM7_PASSES 7 /* Two macros to return the first row and first column of the original, * full, image which appears in a given pass. 'pass' is in the range 0 * to 6 and the result is in the range 0 to 7. */ #define PNG_PASS_START_ROW(pass) (((1&~(pass))<<(3-((pass)>>1)))&7) #define PNG_PASS_START_COL(pass) (((1& (pass))<<(3-(((pass)+1)>>1)))&7) /* A macro to return the offset between pixels in the output row for a pair of * pixels in the input - effectively the inverse of the 'COL_SHIFT' macro that * follows. Note that ROW_OFFSET is the offset from one row to the next whereas * COL_OFFSET is from one column to the next, within a row. */ #define PNG_PASS_ROW_OFFSET(pass) ((pass)>2?(8>>(((pass)-1)>>1)):8) #define PNG_PASS_COL_OFFSET(pass) (1<<((7-(pass))>>1)) /* Two macros to help evaluate the number of rows or columns in each * pass. This is expressed as a shift - effectively log2 of the number or * rows or columns in each 8x8 tile of the original image. */ #define PNG_PASS_ROW_SHIFT(pass) ((pass)>2?(8-(pass))>>1:3) #define PNG_PASS_COL_SHIFT(pass) ((pass)>1?(7-(pass))>>1:3) /* Hence two macros to determine the number of rows or columns in a given * pass of an image given its height or width. In fact these macros may * return non-zero even though the sub-image is empty, because the other * dimension may be empty for a small image. */ #define PNG_PASS_ROWS(height, pass) (((height)+(((1<>PNG_PASS_ROW_SHIFT(pass)) #define PNG_PASS_COLS(width, pass) (((width)+(((1<>PNG_PASS_COL_SHIFT(pass)) /* For the reader row callbacks (both progressive and sequential) it is * necessary to find the row in the output image given a row in an interlaced * image, so two more macros: */ #define PNG_ROW_FROM_PASS_ROW(y_in, pass) \ (((y_in)<>(((7-(off))-(pass))<<2)) & 0xF) | \ ((0x01145AF0>>(((7-(off))-(pass))<<2)) & 0xF0)) #define PNG_ROW_IN_INTERLACE_PASS(y, pass) \ ((PNG_PASS_MASK(pass,0) >> ((y)&7)) & 1) #define PNG_COL_IN_INTERLACE_PASS(x, pass) \ ((PNG_PASS_MASK(pass,1) >> ((x)&7)) & 1) #ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED /* With these routines we avoid an integer divide, which will be slower on * most machines. However, it does take more operations than the corresponding * divide method, so it may be slower on a few RISC systems. There are two * shifts (by 8 or 16 bits) and an addition, versus a single integer divide. * * Note that the rounding factors are NOT supposed to be the same! 128 and * 32768 are correct for the NODIV code; 127 and 32767 are correct for the * standard method. * * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ] */ /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ # define png_composite(composite, fg, alpha, bg) \ { \ png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ * (png_uint_16)(alpha) \ + (png_uint_16)(bg)*(png_uint_16)(255 \ - (png_uint_16)(alpha)) + 128); \ (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); \ } # define png_composite_16(composite, fg, alpha, bg) \ { \ png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ * (png_uint_32)(alpha) \ + (png_uint_32)(bg)*(65535 \ - (png_uint_32)(alpha)) + 32768); \ (composite) = (png_uint_16)(0xffff & ((temp + (temp >> 16)) >> 16)); \ } #else /* Standard method using integer division */ # define png_composite(composite, fg, alpha, bg) \ (composite) = \ (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) + \ (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ 127) / 255)) # define png_composite_16(composite, fg, alpha, bg) \ (composite) = \ (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \ (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ 32767) / 65535)) #endif /* READ_COMPOSITE_NODIV */ #ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); #endif PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, png_const_bytep buf)); /* No png_get_int_16 -- may be added if there's a real need for it. */ /* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); #endif #ifdef PNG_SAVE_INT_32_SUPPORTED PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i)); #endif /* Place a 16-bit number into a buffer in PNG byte order. * The parameter is declared unsigned int, not png_uint_16, * just to avoid potential problems on pre-ANSI C compilers. */ #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); /* No png_save_int_16 -- may be added if there's a real need for it. */ #endif #ifdef PNG_USE_READ_MACROS /* Inline macros to do direct reads of bytes from the input buffer. * The png_get_int_32() routine assumes we are using two's complement * format for negative values, which is almost certainly true. */ # define PNG_get_uint_32(buf) \ (((png_uint_32)(*(buf)) << 24) + \ ((png_uint_32)(*((buf) + 1)) << 16) + \ ((png_uint_32)(*((buf) + 2)) << 8) + \ ((png_uint_32)(*((buf) + 3)))) /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the * function) incorrectly returned a value of type png_uint_32. */ # define PNG_get_uint_16(buf) \ ((png_uint_16) \ (((unsigned int)(*(buf)) << 8) + \ ((unsigned int)(*((buf) + 1))))) # define PNG_get_int_32(buf) \ ((png_int_32)((*(buf) & 0x80) \ ? -((png_int_32)(((png_get_uint_32(buf)^0xffffffffU)+1U)&0x7fffffffU)) \ : (png_int_32)png_get_uint_32(buf))) /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, * but defining a macro name prefixed with PNG_PREFIX. */ # ifndef PNG_PREFIX # define png_get_uint_32(buf) PNG_get_uint_32(buf) # define png_get_uint_16(buf) PNG_get_uint_16(buf) # define png_get_int_32(buf) PNG_get_int_32(buf) # endif #else # ifdef PNG_PREFIX /* No macros; revert to the (redefined) function */ # define PNG_get_uint_32 (png_get_uint_32) # define PNG_get_uint_16 (png_get_uint_16) # define PNG_get_int_32 (png_get_int_32) # endif #endif #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED PNG_EXPORT(242, void, png_set_check_for_invalid_index, (png_structrp png_ptr, int allowed)); # ifdef PNG_GET_PALETTE_MAX_SUPPORTED PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, png_const_infop info_ptr)); # endif #endif /* CHECK_FOR_INVALID_INDEX */ /******************************************************************************* * Section 5: SIMPLIFIED API ******************************************************************************* * * Please read the documentation in libpng-manual.txt (TODO: write said * documentation) if you don't understand what follows. * * The simplified API hides the details of both libpng and the PNG file format * itself. It allows PNG files to be read into a very limited number of * in-memory bitmap formats or to be written from the same formats. If these * formats do not accomodate your needs then you can, and should, use the more * sophisticated APIs above - these support a wide variety of in-memory formats * and a wide variety of sophisticated transformations to those formats as well * as a wide variety of APIs to manipulate ancillary information. * * To read a PNG file using the simplified API: * * 1) Declare a 'png_image' structure (see below) on the stack, set the * version field to PNG_IMAGE_VERSION and the 'opaque' pointer to NULL * (this is REQUIRED, your program may crash if you don't do it.) * 2) Call the appropriate png_image_begin_read... function. * 3) Set the png_image 'format' member to the required sample format. * 4) Allocate a buffer for the image and, if required, the color-map. * 5) Call png_image_finish_read to read the image and, if required, the * color-map into your buffers. * * There are no restrictions on the format of the PNG input itself; all valid * color types, bit depths, and interlace methods are acceptable, and the * input image is transformed as necessary to the requested in-memory format * during the png_image_finish_read() step. The only caveat is that if you * request a color-mapped image from a PNG that is full-color or makes * complex use of an alpha channel the transformation is extremely lossy and the * result may look terrible. * * To write a PNG file using the simplified API: * * 1) Declare a 'png_image' structure on the stack and memset() it to all zero. * 2) Initialize the members of the structure that describe the image, setting * the 'format' member to the format of the image samples. * 3) Call the appropriate png_image_write... function with a pointer to the * image and, if necessary, the color-map to write the PNG data. * * png_image is a structure that describes the in-memory format of an image * when it is being read or defines the in-memory format of an image that you * need to write: */ #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) #define PNG_IMAGE_VERSION 1 typedef struct png_control *png_controlp; typedef struct { png_controlp opaque; /* Initialize to NULL, free with png_image_free */ png_uint_32 version; /* Set to PNG_IMAGE_VERSION */ png_uint_32 width; /* Image width in pixels (columns) */ png_uint_32 height; /* Image height in pixels (rows) */ png_uint_32 format; /* Image format as defined below */ png_uint_32 flags; /* A bit mask containing informational flags */ png_uint_32 colormap_entries; /* Number of entries in the color-map */ /* In the event of an error or warning the following field will be set to a * non-zero value and the 'message' field will contain a '\0' terminated * string with the libpng error or warning message. If both warnings and * an error were encountered, only the error is recorded. If there * are multiple warnings, only the first one is recorded. * * The upper 30 bits of this value are reserved, the low two bits contain * a value as follows: */ # define PNG_IMAGE_WARNING 1 # define PNG_IMAGE_ERROR 2 /* * The result is a two-bit code such that a value more than 1 indicates * a failure in the API just called: * * 0 - no warning or error * 1 - warning * 2 - error * 3 - error preceded by warning */ # define PNG_IMAGE_FAILED(png_cntrl) ((((png_cntrl).warning_or_error)&0x03)>1) png_uint_32 warning_or_error; char message[64]; } png_image, *png_imagep; /* The samples of the image have one to four channels whose components have * original values in the range 0 to 1.0: * * 1: A single gray or luminance channel (G). * 2: A gray/luminance channel and an alpha channel (GA). * 3: Three red, green, blue color channels (RGB). * 4: Three color channels and an alpha channel (RGBA). * * The components are encoded in one of two ways: * * a) As a small integer, value 0..255, contained in a single byte. For the * alpha channel the original value is simply value/255. For the color or * luminance channels the value is encoded according to the sRGB specification * and matches the 8-bit format expected by typical display devices. * * The color/gray channels are not scaled (pre-multiplied) by the alpha * channel and are suitable for passing to color management software. * * b) As a value in the range 0..65535, contained in a 2-byte integer. All * channels can be converted to the original value by dividing by 65535; all * channels are linear. Color channels use the RGB encoding (RGB end-points) of * the sRGB specification. This encoding is identified by the * PNG_FORMAT_FLAG_LINEAR flag below. * * When the simplified API needs to convert between sRGB and linear colorspaces, * the actual sRGB transfer curve defined in the sRGB specification (see the * article at https://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 * approximation used elsewhere in libpng. * * When an alpha channel is present it is expected to denote pixel coverage * of the color or luminance channels and is returned as an associated alpha * channel: the color/gray channels are scaled (pre-multiplied) by the alpha * value. * * The samples are either contained directly in the image data, between 1 and 8 * bytes per pixel according to the encoding, or are held in a color-map indexed * by bytes in the image data. In the case of a color-map the color-map entries * are individual samples, encoded as above, and the image data has one byte per * pixel to select the relevant sample from the color-map. */ /* PNG_FORMAT_* * * #defines to be used in png_image::format. Each #define identifies a * particular layout of sample data and, if present, alpha values. There are * separate defines for each of the two component encodings. * * A format is built up using single bit flag values. All combinations are * valid. Formats can be built up from the flag values or you can use one of * the predefined values below. When testing formats always use the FORMAT_FLAG * macros to test for individual features - future versions of the library may * add new flags. * * When reading or writing color-mapped images the format should be set to the * format of the entries in the color-map then png_image_{read,write}_colormap * called to read or write the color-map and set the format correctly for the * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! * * NOTE: libpng can be built with particular features disabled. If you see * compiler errors because the definition of one of the following flags has been * compiled out it is because libpng does not have the required support. It is * possible, however, for the libpng configuration to enable the format on just * read or just write; in that case you may see an error at run time. You can * guard against this by checking for the definition of the appropriate * "_SUPPORTED" macro, one of: * * PNG_SIMPLIFIED_{READ,WRITE}_{BGR,AFIRST}_SUPPORTED */ #define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ #define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ #define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2-byte channels else 1-byte */ #define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ #ifdef PNG_FORMAT_BGR_SUPPORTED # define PNG_FORMAT_FLAG_BGR 0x10U /* BGR colors, else order is RGB */ #endif #ifdef PNG_FORMAT_AFIRST_SUPPORTED # define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ #endif #define PNG_FORMAT_FLAG_ASSOCIATED_ALPHA 0x40U /* alpha channel is associated */ /* Commonly used formats have predefined macros. * * First the single byte (sRGB) formats: */ #define PNG_FORMAT_GRAY 0 #define PNG_FORMAT_GA PNG_FORMAT_FLAG_ALPHA #define PNG_FORMAT_AG (PNG_FORMAT_GA|PNG_FORMAT_FLAG_AFIRST) #define PNG_FORMAT_RGB PNG_FORMAT_FLAG_COLOR #define PNG_FORMAT_BGR (PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_BGR) #define PNG_FORMAT_RGBA (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_ALPHA) #define PNG_FORMAT_ARGB (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_AFIRST) #define PNG_FORMAT_BGRA (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_ALPHA) #define PNG_FORMAT_ABGR (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_AFIRST) /* Then the linear 2-byte formats. When naming these "Y" is used to * indicate a luminance (gray) channel. */ #define PNG_FORMAT_LINEAR_Y PNG_FORMAT_FLAG_LINEAR #define PNG_FORMAT_LINEAR_Y_ALPHA (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_ALPHA) #define PNG_FORMAT_LINEAR_RGB (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR) #define PNG_FORMAT_LINEAR_RGB_ALPHA \ (PNG_FORMAT_FLAG_LINEAR|PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA) /* With color-mapped formats the image data is one byte for each pixel, the byte * is an index into the color-map which is formatted as above. To obtain a * color-mapped format it is sufficient just to add the PNG_FOMAT_FLAG_COLORMAP * to one of the above definitions, or you can use one of the definitions below. */ #define PNG_FORMAT_RGB_COLORMAP (PNG_FORMAT_RGB|PNG_FORMAT_FLAG_COLORMAP) #define PNG_FORMAT_BGR_COLORMAP (PNG_FORMAT_BGR|PNG_FORMAT_FLAG_COLORMAP) #define PNG_FORMAT_RGBA_COLORMAP (PNG_FORMAT_RGBA|PNG_FORMAT_FLAG_COLORMAP) #define PNG_FORMAT_ARGB_COLORMAP (PNG_FORMAT_ARGB|PNG_FORMAT_FLAG_COLORMAP) #define PNG_FORMAT_BGRA_COLORMAP (PNG_FORMAT_BGRA|PNG_FORMAT_FLAG_COLORMAP) #define PNG_FORMAT_ABGR_COLORMAP (PNG_FORMAT_ABGR|PNG_FORMAT_FLAG_COLORMAP) /* PNG_IMAGE macros * * These are convenience macros to derive information from a png_image * structure. The PNG_IMAGE_SAMPLE_ macros return values appropriate to the * actual image sample values - either the entries in the color-map or the * pixels in the image. The PNG_IMAGE_PIXEL_ macros return corresponding values * for the pixels and will always return 1 for color-mapped formats. The * remaining macros return information about the rows in the image and the * complete image. * * NOTE: All the macros that take a png_image::format parameter are compile time * constants if the format parameter is, itself, a constant. Therefore these * macros can be used in array declarations and case labels where required. * Similarly the macros are also pre-processor constants (sizeof is not used) so * they can be used in #if tests. * * First the information about the samples. */ #define PNG_IMAGE_SAMPLE_CHANNELS(fmt)\ (((fmt)&(PNG_FORMAT_FLAG_COLOR|PNG_FORMAT_FLAG_ALPHA))+1) /* Return the total number of channels in a given format: 1..4 */ #define PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)\ ((((fmt) & PNG_FORMAT_FLAG_LINEAR) >> 2)+1) /* Return the size in bytes of a single component of a pixel or color-map * entry (as appropriate) in the image: 1 or 2. */ #define PNG_IMAGE_SAMPLE_SIZE(fmt)\ (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * PNG_IMAGE_SAMPLE_COMPONENT_SIZE(fmt)) /* This is the size of the sample data for one sample. If the image is * color-mapped it is the size of one color-map entry (and image pixels are * one byte in size), otherwise it is the size of one image pixel. */ #define PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(fmt)\ (PNG_IMAGE_SAMPLE_CHANNELS(fmt) * 256) /* The maximum size of the color-map required by the format expressed in a * count of components. This can be used to compile-time allocate a * color-map: * * png_uint_16 colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(linear_fmt)]; * * png_byte colormap[PNG_IMAGE_MAXIMUM_COLORMAP_COMPONENTS(sRGB_fmt)]; * * Alternatively use the PNG_IMAGE_COLORMAP_SIZE macro below to use the * information from one of the png_image_begin_read_ APIs and dynamically * allocate the required memory. */ /* Corresponding information about the pixels */ #define PNG_IMAGE_PIXEL_(test,fmt)\ (((fmt)&PNG_FORMAT_FLAG_COLORMAP)?1:test(fmt)) #define PNG_IMAGE_PIXEL_CHANNELS(fmt)\ PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_CHANNELS,fmt) /* The number of separate channels (components) in a pixel; 1 for a * color-mapped image. */ #define PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)\ PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_COMPONENT_SIZE,fmt) /* The size, in bytes, of each component in a pixel; 1 for a color-mapped * image. */ #define PNG_IMAGE_PIXEL_SIZE(fmt) PNG_IMAGE_PIXEL_(PNG_IMAGE_SAMPLE_SIZE,fmt) /* The size, in bytes, of a complete pixel; 1 for a color-mapped image. */ /* Information about the whole row, or whole image */ #define PNG_IMAGE_ROW_STRIDE(image)\ (PNG_IMAGE_PIXEL_CHANNELS((image).format) * (image).width) /* Return the total number of components in a single row of the image; this * is the minimum 'row stride', the minimum count of components between each * row. For a color-mapped image this is the minimum number of bytes in a * row. * * WARNING: this macro overflows for some images with more than one component * and very large image widths. libpng will refuse to process an image where * this macro would overflow. */ #define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) /* Return the size, in bytes, of an image buffer given a png_image and a row * stride - the number of components to leave space for in each row. * * WARNING: this macro overflows a 32-bit integer for some large PNG images, * libpng will refuse to process an image where such an overflow would occur. */ #define PNG_IMAGE_SIZE(image)\ PNG_IMAGE_BUFFER_SIZE(image, PNG_IMAGE_ROW_STRIDE(image)) /* Return the size, in bytes, of the image in memory given just a png_image; * the row stride is the minimum stride required for the image. */ #define PNG_IMAGE_COLORMAP_SIZE(image)\ (PNG_IMAGE_SAMPLE_SIZE((image).format) * (image).colormap_entries) /* Return the size, in bytes, of the color-map of this image. If the image * format is not a color-map format this will return a size sufficient for * 256 entries in the given format; check PNG_FORMAT_FLAG_COLORMAP if * you don't want to allocate a color-map in this case. */ /* PNG_IMAGE_FLAG_* * * Flags containing additional information about the image are held in the * 'flags' field of png_image. */ #define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 /* This indicates the the RGB values of the in-memory bitmap do not * correspond to the red, green and blue end-points defined by sRGB. */ #define PNG_IMAGE_FLAG_FAST 0x02 /* On write emphasise speed over compression; the resultant PNG file will be * larger but will be produced significantly faster, particular for large * images. Do not use this option for images which will be distributed, only * used it when producing intermediate files that will be read back in * repeatedly. For a typical 24-bit image the option will double the read * speed at the cost of increasing the image size by 25%, however for many * more compressible images the PNG file can be 10 times larger with only a * slight speed gain. */ #define PNG_IMAGE_FLAG_16BIT_sRGB 0x04 /* On read if the image is a 16-bit per component image and there is no gAMA * or sRGB chunk assume that the components are sRGB encoded. Notice that * images output by the simplified API always have gamma information; setting * this flag only affects the interpretation of 16-bit images from an * external source. It is recommended that the application expose this flag * to the user; the user can normally easily recognize the difference between * linear and sRGB encoding. This flag has no effect on write - the data * passed to the write APIs must have the correct encoding (as defined * above.) * * If the flag is not set (the default) input 16-bit per component data is * assumed to be linear. * * NOTE: the flag can only be set after the png_image_begin_read_ call, * because that call initializes the 'flags' field. */ #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* READ APIs * --------- * * The png_image passed to the read APIs must have been initialized by setting * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) */ #ifdef PNG_STDIO_SUPPORTED PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, const char *file_name)); /* The named file is opened for read and the image header is filled in * from the PNG header in the file. */ PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, FILE* file)); /* The PNG header is read from the stdio FILE object. */ #endif /* STDIO */ PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, png_const_voidp memory, png_size_t size)); /* The PNG header is read from the given memory buffer. */ PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, png_const_colorp background, void *buffer, png_int_32 row_stride, void *colormap)); /* Finish reading the image into the supplied buffer and clean up the * png_image structure. * * row_stride is the step, in byte or 2-byte units as appropriate, * between adjacent rows. A positive stride indicates that the top-most row * is first in the buffer - the normal top-down arrangement. A negative * stride indicates that the bottom-most row is first in the buffer. * * background need only be supplied if an alpha channel must be removed from * a png_byte format and the removal is to be done by compositing on a solid * color; otherwise it may be NULL and any composition will be done directly * onto the buffer. The value is an sRGB color to use for the background, * for grayscale output the green channel is used. * * background must be supplied when an alpha channel must be removed from a * single byte color-mapped output format, in other words if: * * 1) The original format from png_image_begin_read_from_* had * PNG_FORMAT_FLAG_ALPHA set. * 2) The format set by the application does not. * 3) The format set by the application has PNG_FORMAT_FLAG_COLORMAP set and * PNG_FORMAT_FLAG_LINEAR *not* set. * * For linear output removing the alpha channel is always done by compositing * on black and background is ignored. * * colormap must be supplied when PNG_FORMAT_FLAG_COLORMAP is set. It must * be at least the size (in bytes) returned by PNG_IMAGE_COLORMAP_SIZE. * image->colormap_entries will be updated to the actual number of entries * written to the colormap; this may be less than the original value. */ PNG_EXPORT(238, void, png_image_free, (png_imagep image)); /* Free any data allocated by libpng in image->opaque, setting the pointer to * NULL. May be called at any time after the structure is initialized. */ #endif /* SIMPLIFIED_READ */ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED /* WRITE APIS * ---------- * For write you must initialize a png_image structure to describe the image to * be written. To do this use memset to set the whole structure to 0 then * initialize fields describing your image. * * version: must be set to PNG_IMAGE_VERSION * opaque: must be initialized to NULL * width: image width in pixels * height: image height in rows * format: the format of the data (image and color-map) you wish to write * flags: set to 0 unless one of the defined flags applies; set * PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images where the RGB * values do not correspond to the colors in sRGB. * colormap_entries: set to the number of entries in the color-map (0 to 256) */ #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, const char *file, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap)); /* Write the image to the named file. */ PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, int convert_to_8_bit, const void *buffer, png_int_32 row_stride, const void *colormap)); /* Write the image to the given (FILE*). */ #endif /* SIMPLIFIED_WRITE_STDIO */ /* With all write APIs if image is in one of the linear formats with 16-bit * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG * gamma encoded according to the sRGB specification, otherwise a 16-bit linear * encoded PNG file is written. * * With color-mapped data formats the colormap parameter point to a color-map * with at least image->colormap_entries encoded in the specified format. If * the format is linear the written PNG color-map will be converted to sRGB * regardless of the convert_to_8_bit flag. * * With all APIs row_stride is handled as in the read APIs - it is the spacing * from one row to the next in component sized units (1 or 2 bytes) and if * negative indicates a bottom-up row layout in the buffer. If row_stride is * zero, libpng will calculate it for you from the image width and number of * channels. * * Note that the write API does not support interlacing, sub-8-bit pixels or * most ancillary chunks. If you need to write text chunks (e.g. for copyright * notices) you need to use one of the other APIs. */ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory, png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8_bit, const void *buffer, png_int_32 row_stride, const void *colormap)); /* Write the image to the given memory buffer. The function both writes the * whole PNG data stream to *memory and updates *memory_bytes with the count * of bytes written. * * 'memory' may be NULL. In this case *memory_bytes is not read however on * success the number of bytes which would have been written will still be * stored in *memory_bytes. On failure *memory_bytes will contain 0. * * If 'memory' is not NULL it must point to memory[*memory_bytes] of * writeable memory. * * If the function returns success memory[*memory_bytes] (if 'memory' is not * NULL) contains the written PNG data. *memory_bytes will always be less * than or equal to the original value. * * If the function returns false and *memory_bytes was not changed an error * occured during write. If *memory_bytes was changed, or is not 0 if * 'memory' was NULL, the write would have succeeded but for the memory * buffer being too small. *memory_bytes contains the required number of * bytes and will be bigger that the original value. */ #define png_image_write_get_memory_size(image, size, convert_to_8_bit, buffer,\ row_stride, colormap)\ png_image_write_to_memory(&(image), 0, &(size), convert_to_8_bit, buffer,\ row_stride, colormap) /* Return the amount of memory in 'size' required to compress this image. * The png_image structure 'image' must be filled in as in the above * function and must not be changed before the actual write call, the buffer * and all other parameters must also be identical to that in the final * write call. The 'size' variable need not be initialized. * * NOTE: the macro returns true/false, if false is returned 'size' will be * set to zero and the write failed and probably will fail if tried again. */ /* You can pre-allocate the buffer by making sure it is of sufficient size * regardless of the amount of compression achieved. The buffer size will * always be bigger than the original image and it will never be filled. The * following macros are provided to assist in allocating the buffer. */ #define PNG_IMAGE_DATA_SIZE(image) (PNG_IMAGE_SIZE(image)+(image).height) /* The number of uncompressed bytes in the PNG byte encoding of the image; * uncompressing the PNG IDAT data will give this number of bytes. * * NOTE: while PNG_IMAGE_SIZE cannot overflow for an image in memory this * macro can because of the extra bytes used in the PNG byte encoding. You * need to avoid this macro if your image size approaches 2^30 in width or * height. The same goes for the remainder of these macros; they all produce * bigger numbers than the actual in-memory image size. */ #ifndef PNG_ZLIB_MAX_SIZE # define PNG_ZLIB_MAX_SIZE(b) ((b)+(((b)+7U)>>3)+(((b)+63U)>>6)+11U) /* An upper bound on the number of compressed bytes given 'b' uncompressed * bytes. This is based on deflateBounds() in zlib; different * implementations of zlib compression may conceivably produce more data so * if your zlib implementation is not zlib itself redefine this macro * appropriately. */ #endif #define PNG_IMAGE_COMPRESSED_SIZE_MAX(image)\ PNG_ZLIB_MAX_SIZE((png_alloc_size_t)PNG_IMAGE_DATA_SIZE(image)) /* An upper bound on the size of the data in the PNG IDAT chunks. */ #define PNG_IMAGE_PNG_SIZE_MAX_(image, image_size)\ ((8U/*sig*/+25U/*IHDR*/+16U/*gAMA*/+44U/*cHRM*/+12U/*IEND*/+\ (((image).format&PNG_FORMAT_FLAG_COLORMAP)?/*colormap: PLTE, tRNS*/\ 12U+3U*(image).colormap_entries/*PLTE data*/+\ (((image).format&PNG_FORMAT_FLAG_ALPHA)?\ 12U/*tRNS*/+(image).colormap_entries:0U):0U)+\ 12U)+(12U*((image_size)/PNG_ZBUF_SIZE))/*IDAT*/+(image_size)) /* A helper for the following macro; if your compiler cannot handle the * following macro use this one with the result of * PNG_IMAGE_COMPRESSED_SIZE_MAX(image) as the second argument (most * compilers should handle this just fine.) */ #define PNG_IMAGE_PNG_SIZE_MAX(image)\ PNG_IMAGE_PNG_SIZE_MAX_(image, PNG_IMAGE_COMPRESSED_SIZE_MAX(image)) /* An upper bound on the total length of the PNG data stream for 'image'. * The result is of type png_alloc_size_t, on 32-bit systems this may * overflow even though PNG_IMAGE_DATA_SIZE does not overflow; the write will * run out of buffer space but return a corrected size which should work. */ #endif /* SIMPLIFIED_WRITE */ /******************************************************************************* * END OF SIMPLIFIED API ******************************************************************************/ #endif /* SIMPLIFIED_{READ|WRITE} */ /******************************************************************************* * Section 6: IMPLEMENTATION OPTIONS ******************************************************************************* * * Support for arbitrary implementation-specific optimizations. The API allows * particular options to be turned on or off. 'Option' is the number of the * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given * by the PNG_OPTION_ defines below. * * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, * are detected at run time, however sometimes it may be impossible * to do this in user mode, in which case it is necessary to discover * the capabilities in an OS specific way. Such capabilities are * listed here when libpng has support for them and must be turned * ON by the application if present. * * SOFTWARE: sometimes software optimizations actually result in performance * decrease on some architectures or systems, or with some sets of * PNG images. 'Software' options allow such optimizations to be * selected at run time. */ #ifdef PNG_SET_OPTION_SUPPORTED #ifdef PNG_ARM_NEON_API_SUPPORTED # define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ #endif #define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ #define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */ #ifdef PNG_MIPS_MSA_API_SUPPORTED # define PNG_MIPS_MSA 6 /* HARDWARE: MIPS Msa SIMD instructions supported */ #endif #define PNG_IGNORE_ADLER32 8 #ifdef PNG_POWERPC_VSX_API_SUPPORTED # define PNG_POWERPC_VSX 10 /* HARDWARE: PowerPC VSX SIMD instructions supported */ #endif #define PNG_OPTION_NEXT 12 /* Next option - numbers must be even */ /* Return values: NOTE: there are four values and 'off' is *not* zero */ #define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ #define PNG_OPTION_INVALID 1 /* Option number out of range */ #define PNG_OPTION_OFF 2 #define PNG_OPTION_ON 3 PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, int onoff)); #endif /* SET_OPTION */ /******************************************************************************* * END OF HARDWARE AND SOFTWARE OPTIONS ******************************************************************************/ /* Maintainer: Put new public prototypes here ^, in libpng.3, in project * defs, and in scripts/symbols.def. */ /* The last ordinal number (this is the *last* one already used; the next * one to use is one more than this.) */ #ifdef PNG_EXPORT_LAST_ORDINAL PNG_EXPORT_LAST_ORDINAL(249); #endif #ifdef __cplusplus } #endif #endif /* PNG_VERSION_INFO_ONLY */ /* Do not put anything past this line */ #endif /* PNG_H */ stella-5.1.1/src/libpng/pngconf.h000066400000000000000000000544751324334165500166740ustar00rootroot00000000000000 /* pngconf.h - machine configurable file for libpng * * libpng version 1.6.34, September 29, 2017 * * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * Any machine specific code is near the front of this file, so if you * are configuring libpng for a machine, you may want to read the section * starting here down to where it starts to typedef png_color, png_text, * and png_info. */ #ifndef PNGCONF_H #define PNGCONF_H #ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ /* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C * compiler for correct compilation. The following header files are required by * the standard. If your compiler doesn't provide these header files, or they * do not match the standard, you will need to provide/improve them. */ #include #include /* Library header files. These header files are all defined by ISOC90; libpng * expects conformant implementations, however, an ISOC90 conformant system need * not provide these header files if the functionality cannot be implemented. * In this case it will be necessary to disable the relevant parts of libpng in * the build of pnglibconf.h. * * Prior to 1.6.0 string.h was included here; the API changes in 1.6.0 to not * include this unnecessary header file. */ #ifdef PNG_STDIO_SUPPORTED /* Required for the definition of FILE: */ # include #endif #ifdef PNG_SETJMP_SUPPORTED /* Required for the definition of jmp_buf and the declaration of longjmp: */ # include #endif #ifdef PNG_CONVERT_tIME_SUPPORTED /* Required for struct tm: */ # include #endif #endif /* PNG_BUILDING_SYMBOL_TABLE */ /* Prior to 1.6.0 it was possible to turn off 'const' in declarations using * PNG_NO_CONST; this is no longer supported except for data declarations which * apparently still cause problems in 2011 on some compilers. */ #define PNG_CONST const /* backward compatibility only */ /* This controls optimization of the reading of 16-bit and 32-bit values * from PNG files. It can be set on a per-app-file basis - it * just changes whether a macro is used when the function is called. * The library builder sets the default; if read functions are not * built into the library the macro implementation is forced on. */ #ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED # define PNG_USE_READ_MACROS #endif #if !defined(PNG_NO_USE_READ_MACROS) && !defined(PNG_USE_READ_MACROS) # if PNG_DEFAULT_READ_MACROS # define PNG_USE_READ_MACROS # endif #endif /* COMPILER SPECIFIC OPTIONS. * * These options are provided so that a variety of difficult compilers * can be used. Some are fixed at build time (e.g. PNG_API_RULE * below) but still have compiler specific implementations, others * may be changed on a per-file basis when compiling against libpng. */ /* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect * against legacy (pre ISOC90) compilers that did not understand function * prototypes. It is not required for modern C compilers. */ #ifndef PNGARG # define PNGARG(arglist) arglist #endif /* Function calling conventions. * ============================= * Normally it is not necessary to specify to the compiler how to call * a function - it just does it - however on x86 systems derived from * Microsoft and Borland C compilers ('IBM PC', 'DOS', 'Windows' systems * and some others) there are multiple ways to call a function and the * default can be changed on the compiler command line. For this reason * libpng specifies the calling convention of every exported function and * every function called via a user supplied function pointer. This is * done in this file by defining the following macros: * * PNGAPI Calling convention for exported functions. * PNGCBAPI Calling convention for user provided (callback) functions. * PNGCAPI Calling convention used by the ANSI-C library (required * for longjmp callbacks and sometimes used internally to * specify the calling convention for zlib). * * These macros should never be overridden. If it is necessary to * change calling convention in a private build this can be done * by setting PNG_API_RULE (which defaults to 0) to one of the values * below to select the correct 'API' variants. * * PNG_API_RULE=0 Use PNGCAPI - the 'C' calling convention - throughout. * This is correct in every known environment. * PNG_API_RULE=1 Use the operating system convention for PNGAPI and * the 'C' calling convention (from PNGCAPI) for * callbacks (PNGCBAPI). This is no longer required * in any known environment - if it has to be used * please post an explanation of the problem to the * libpng mailing list. * * These cases only differ if the operating system does not use the C * calling convention, at present this just means the above cases * (x86 DOS/Windows sytems) and, even then, this does not apply to * Cygwin running on those systems. * * Note that the value must be defined in pnglibconf.h so that what * the application uses to call the library matches the conventions * set when building the library. */ /* Symbol export * ============= * When building a shared library it is almost always necessary to tell * the compiler which symbols to export. The png.h macro 'PNG_EXPORT' * is used to mark the symbols. On some systems these symbols can be * extracted at link time and need no special processing by the compiler, * on other systems the symbols are flagged by the compiler and just * the declaration requires a special tag applied (unfortunately) in a * compiler dependent way. Some systems can do either. * * A small number of older systems also require a symbol from a DLL to * be flagged to the program that calls it. This is a problem because * we do not know in the header file included by application code that * the symbol will come from a shared library, as opposed to a statically * linked one. For this reason the application must tell us by setting * the magic flag PNG_USE_DLL to turn on the special processing before * it includes png.h. * * Four additional macros are used to make this happen: * * PNG_IMPEXP The magic (if any) to cause a symbol to be exported from * the build or imported if PNG_USE_DLL is set - compiler * and system specific. * * PNG_EXPORT_TYPE(type) A macro that pre or appends PNG_IMPEXP to * 'type', compiler specific. * * PNG_DLL_EXPORT Set to the magic to use during a libpng build to * make a symbol exported from the DLL. Not used in the * public header files; see pngpriv.h for how it is used * in the libpng build. * * PNG_DLL_IMPORT Set to the magic to force the libpng symbols to come * from a DLL - used to define PNG_IMPEXP when * PNG_USE_DLL is set. */ /* System specific discovery. * ========================== * This code is used at build time to find PNG_IMPEXP, the API settings * and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL * import processing is possible. On Windows systems it also sets * compiler-specific macros to the values required to change the calling * conventions of the various functions. */ #if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or * MinGW on any architecture currently supported by Windows. Also includes * Watcom builds but these need special treatment because they are not * compatible with GCC or Visual C because of different calling conventions. */ # if PNG_API_RULE == 2 /* If this line results in an error, either because __watcall is not * understood or because of a redefine just below you cannot use *this* * build of the library with the compiler you are using. *This* build was * build using Watcom and applications must also be built using Watcom! */ # define PNGCAPI __watcall # endif # if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) # define PNGCAPI __cdecl # if PNG_API_RULE == 1 /* If this line results in an error __stdcall is not understood and * PNG_API_RULE should not have been set to '1'. */ # define PNGAPI __stdcall # endif # else /* An older compiler, or one not detected (erroneously) above, * if necessary override on the command line to get the correct * variants for the compiler. */ # ifndef PNGCAPI # define PNGCAPI _cdecl # endif # if PNG_API_RULE == 1 && !defined(PNGAPI) # define PNGAPI _stdcall # endif # endif /* compiler/api */ /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ # if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) # error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" # endif # if (defined(_MSC_VER) && _MSC_VER < 800) ||\ (defined(__BORLANDC__) && __BORLANDC__ < 0x500) /* older Borland and MSC * compilers used '__export' and required this to be after * the type. */ # ifndef PNG_EXPORT_TYPE # define PNG_EXPORT_TYPE(type) type PNG_IMPEXP # endif # define PNG_DLL_EXPORT __export # else /* newer compiler */ # define PNG_DLL_EXPORT __declspec(dllexport) # ifndef PNG_DLL_IMPORT # define PNG_DLL_IMPORT __declspec(dllimport) # endif # endif /* compiler */ #else /* !Windows */ # if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) # define PNGAPI _System # else /* !Windows/x86 && !OS/2 */ /* Use the defaults, or define PNG*API on the command line (but * this will have to be done for every compile!) */ # endif /* other system, !OS/2 */ #endif /* !Windows/x86 */ /* Now do all the defaulting . */ #ifndef PNGCAPI # define PNGCAPI #endif #ifndef PNGCBAPI # define PNGCBAPI PNGCAPI #endif #ifndef PNGAPI # define PNGAPI PNGCAPI #endif /* PNG_IMPEXP may be set on the compilation system command line or (if not set) * then in an internal header file when building the library, otherwise (when * using the library) it is set here. */ #ifndef PNG_IMPEXP # if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) /* This forces use of a DLL, disallowing static linking */ # define PNG_IMPEXP PNG_DLL_IMPORT # endif # ifndef PNG_IMPEXP # define PNG_IMPEXP # endif #endif /* In 1.5.2 the definition of PNG_FUNCTION has been changed to always treat * 'attributes' as a storage class - the attributes go at the start of the * function definition, and attributes are always appended regardless of the * compiler. This considerably simplifies these macros but may cause problems * if any compilers both need function attributes and fail to handle them as * a storage class (this is unlikely.) */ #ifndef PNG_FUNCTION # define PNG_FUNCTION(type, name, args, attributes) attributes type name args #endif #ifndef PNG_EXPORT_TYPE # define PNG_EXPORT_TYPE(type) PNG_IMPEXP type #endif /* The ordinal value is only relevant when preprocessing png.h for symbol * table entries, so we discard it here. See the .dfn files in the * scripts directory. */ #ifndef PNG_EXPORTA # define PNG_EXPORTA(ordinal, type, name, args, attributes) \ PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), PNGARG(args), \ PNG_LINKAGE_API attributes) #endif /* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, * so make something non-empty to satisfy the requirement: */ #define PNG_EMPTY /*empty list*/ #define PNG_EXPORT(ordinal, type, name, args) \ PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) /* Use PNG_REMOVED to comment out a removed interface. */ #ifndef PNG_REMOVED # define PNG_REMOVED(ordinal, type, name, args, attributes) #endif #ifndef PNG_CALLBACK # define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) #endif /* Support for compiler specific function attributes. These are used * so that where compiler support is available incorrect use of API * functions in png.h will generate compiler warnings. * * Added at libpng-1.2.41. */ #ifndef PNG_NO_PEDANTIC_WARNINGS # ifndef PNG_PEDANTIC_WARNINGS_SUPPORTED # define PNG_PEDANTIC_WARNINGS_SUPPORTED # endif #endif #ifdef PNG_PEDANTIC_WARNINGS_SUPPORTED /* Support for compiler specific function attributes. These are used * so that where compiler support is available, incorrect use of API * functions in png.h will generate compiler warnings. Added at libpng * version 1.2.41. Disabling these removes the warnings but may also produce * less efficient code. */ # if defined(__clang__) && defined(__has_attribute) /* Clang defines both __clang__ and __GNUC__. Check __clang__ first. */ # if !defined(PNG_USE_RESULT) && __has_attribute(__warn_unused_result__) # define PNG_USE_RESULT __attribute__((__warn_unused_result__)) # endif # if !defined(PNG_NORETURN) && __has_attribute(__noreturn__) # define PNG_NORETURN __attribute__((__noreturn__)) # endif # if !defined(PNG_ALLOCATED) && __has_attribute(__malloc__) # define PNG_ALLOCATED __attribute__((__malloc__)) # endif # if !defined(PNG_DEPRECATED) && __has_attribute(__deprecated__) # define PNG_DEPRECATED __attribute__((__deprecated__)) # endif # if !defined(PNG_PRIVATE) # ifdef __has_extension # if __has_extension(attribute_unavailable_with_message) # define PNG_PRIVATE __attribute__((__unavailable__(\ "This function is not exported by libpng."))) # endif # endif # endif # ifndef PNG_RESTRICT # define PNG_RESTRICT __restrict # endif # elif defined(__GNUC__) # ifndef PNG_USE_RESULT # define PNG_USE_RESULT __attribute__((__warn_unused_result__)) # endif # ifndef PNG_NORETURN # define PNG_NORETURN __attribute__((__noreturn__)) # endif # if __GNUC__ >= 3 # ifndef PNG_ALLOCATED # define PNG_ALLOCATED __attribute__((__malloc__)) # endif # ifndef PNG_DEPRECATED # define PNG_DEPRECATED __attribute__((__deprecated__)) # endif # ifndef PNG_PRIVATE # if 0 /* Doesn't work so we use deprecated instead*/ # define PNG_PRIVATE \ __attribute__((warning("This function is not exported by libpng."))) # else # define PNG_PRIVATE \ __attribute__((__deprecated__)) # endif # endif # if ((__GNUC__ > 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) # ifndef PNG_RESTRICT # define PNG_RESTRICT __restrict # endif # endif /* __GNUC__.__GNUC_MINOR__ > 3.0 */ # endif /* __GNUC__ >= 3 */ # elif defined(_MSC_VER) && (_MSC_VER >= 1300) # ifndef PNG_USE_RESULT # define PNG_USE_RESULT /* not supported */ # endif # ifndef PNG_NORETURN # define PNG_NORETURN __declspec(noreturn) # endif # ifndef PNG_ALLOCATED # if (_MSC_VER >= 1400) # define PNG_ALLOCATED __declspec(restrict) # endif # endif # ifndef PNG_DEPRECATED # define PNG_DEPRECATED __declspec(deprecated) # endif # ifndef PNG_PRIVATE # define PNG_PRIVATE __declspec(deprecated) # endif # ifndef PNG_RESTRICT # if (_MSC_VER >= 1400) # define PNG_RESTRICT __restrict # endif # endif # elif defined(__WATCOMC__) # ifndef PNG_RESTRICT # define PNG_RESTRICT __restrict # endif # endif #endif /* PNG_PEDANTIC_WARNINGS */ #ifndef PNG_DEPRECATED # define PNG_DEPRECATED /* Use of this function is deprecated */ #endif #ifndef PNG_USE_RESULT # define PNG_USE_RESULT /* The result of this function must be checked */ #endif #ifndef PNG_NORETURN # define PNG_NORETURN /* This function does not return */ #endif #ifndef PNG_ALLOCATED # define PNG_ALLOCATED /* The result of the function is new memory */ #endif #ifndef PNG_PRIVATE # define PNG_PRIVATE /* This is a private libpng function */ #endif #ifndef PNG_RESTRICT # define PNG_RESTRICT /* The C99 "restrict" feature */ #endif #ifndef PNG_FP_EXPORT /* A floating point API. */ # ifdef PNG_FLOATING_POINT_SUPPORTED # define PNG_FP_EXPORT(ordinal, type, name, args)\ PNG_EXPORT(ordinal, type, name, args); # else /* No floating point APIs */ # define PNG_FP_EXPORT(ordinal, type, name, args) # endif #endif #ifndef PNG_FIXED_EXPORT /* A fixed point API. */ # ifdef PNG_FIXED_POINT_SUPPORTED # define PNG_FIXED_EXPORT(ordinal, type, name, args)\ PNG_EXPORT(ordinal, type, name, args); # else /* No fixed point APIs */ # define PNG_FIXED_EXPORT(ordinal, type, name, args) # endif #endif #ifndef PNG_BUILDING_SYMBOL_TABLE /* Some typedefs to get us started. These should be safe on most of the common * platforms. * * png_uint_32 and png_int_32 may, currently, be larger than required to hold a * 32-bit value however this is not normally advisable. * * png_uint_16 and png_int_16 should always be two bytes in size - this is * verified at library build time. * * png_byte must always be one byte in size. * * The checks below use constants from limits.h, as defined by the ISOC90 * standard. */ #if CHAR_BIT == 8 && UCHAR_MAX == 255 typedef unsigned char png_byte; #else # error "libpng requires 8-bit bytes" #endif #if INT_MIN == -32768 && INT_MAX == 32767 typedef int png_int_16; #elif SHRT_MIN == -32768 && SHRT_MAX == 32767 typedef short png_int_16; #else # error "libpng requires a signed 16-bit type" #endif #if UINT_MAX == 65535 typedef unsigned int png_uint_16; #elif USHRT_MAX == 65535 typedef unsigned short png_uint_16; #else # error "libpng requires an unsigned 16-bit type" #endif #if INT_MIN < -2147483646 && INT_MAX > 2147483646 typedef int png_int_32; #elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 typedef long int png_int_32; #else # error "libpng requires a signed 32-bit (or more) type" #endif #if UINT_MAX > 4294967294U typedef unsigned int png_uint_32; #elif ULONG_MAX > 4294967294U typedef unsigned long int png_uint_32; #else # error "libpng requires an unsigned 32-bit (or more) type" #endif /* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, * requires an ISOC90 compiler and relies on consistent behavior of sizeof. */ typedef size_t png_size_t; typedef ptrdiff_t png_ptrdiff_t; /* libpng needs to know the maximum value of 'size_t' and this controls the * definition of png_alloc_size_t, below. This maximum value of size_t limits * but does not control the maximum allocations the library makes - there is * direct application control of this through png_set_user_limits(). */ #ifndef PNG_SMALL_SIZE_T /* Compiler specific tests for systems where size_t is known to be less than * 32 bits (some of these systems may no longer work because of the lack of * 'far' support; see above.) */ # if (defined(__TURBOC__) && !defined(__FLAT__)) ||\ (defined(_MSC_VER) && defined(MAXSEG_64K)) # define PNG_SMALL_SIZE_T # endif #endif /* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to * png_alloc_size_t are not necessary; in fact, it is recommended not to use * them at all so that the compiler can complain when something turns out to be * problematic. * * Casts in the other direction (from png_alloc_size_t to png_size_t or * png_uint_32) should be explicitly applied; however, we do not expect to * encounter practical situations that require such conversions. * * PNG_SMALL_SIZE_T must be defined if the maximum value of size_t is less than * 4294967295 - i.e. less than the maximum value of png_uint_32. */ #ifdef PNG_SMALL_SIZE_T typedef png_uint_32 png_alloc_size_t; #else typedef png_size_t png_alloc_size_t; #endif /* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler * implementations of Intel CPU specific support of user-mode segmented address * spaces, where 16-bit pointers address more than 65536 bytes of memory using * separate 'segment' registers. The implementation requires two different * types of pointer (only one of which includes the segment value.) * * If required this support is available in version 1.2 of libpng and may be * available in versions through 1.5, although the correctness of the code has * not been verified recently. */ /* Typedef for floating-point numbers that are converted to fixed-point with a * multiple of 100,000, e.g., gamma */ typedef png_int_32 png_fixed_point; /* Add typedefs for pointers */ typedef void * png_voidp; typedef const void * png_const_voidp; typedef png_byte * png_bytep; typedef const png_byte * png_const_bytep; typedef png_uint_32 * png_uint_32p; typedef const png_uint_32 * png_const_uint_32p; typedef png_int_32 * png_int_32p; typedef const png_int_32 * png_const_int_32p; typedef png_uint_16 * png_uint_16p; typedef const png_uint_16 * png_const_uint_16p; typedef png_int_16 * png_int_16p; typedef const png_int_16 * png_const_int_16p; typedef char * png_charp; typedef const char * png_const_charp; typedef png_fixed_point * png_fixed_point_p; typedef const png_fixed_point * png_const_fixed_point_p; typedef png_size_t * png_size_tp; typedef const png_size_t * png_const_size_tp; #ifdef PNG_STDIO_SUPPORTED typedef FILE * png_FILE_p; #endif #ifdef PNG_FLOATING_POINT_SUPPORTED typedef double * png_doublep; typedef const double * png_const_doublep; #endif /* Pointers to pointers; i.e. arrays */ typedef png_byte * * png_bytepp; typedef png_uint_32 * * png_uint_32pp; typedef png_int_32 * * png_int_32pp; typedef png_uint_16 * * png_uint_16pp; typedef png_int_16 * * png_int_16pp; typedef const char * * png_const_charpp; typedef char * * png_charpp; typedef png_fixed_point * * png_fixed_point_pp; #ifdef PNG_FLOATING_POINT_SUPPORTED typedef double * * png_doublepp; #endif /* Pointers to pointers to pointers; i.e., pointer to array */ typedef char * * * png_charppp; #endif /* PNG_BUILDING_SYMBOL_TABLE */ #endif /* PNGCONF_H */ stella-5.1.1/src/libpng/pngdebug.h000066400000000000000000000123701324334165500170210ustar00rootroot00000000000000 /* pngdebug.h - Debugging macros for libpng, also used in pngtest.c * * Last changed in libpng 1.6.8 [December 19, 2013] * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ /* Define PNG_DEBUG at compile time for debugging information. Higher * numbers for PNG_DEBUG mean more debugging information. This has * only been added since version 0.95 so it is not implemented throughout * libpng yet, but more support will be added as needed. * * png_debug[1-2]?(level, message ,arg{0-2}) * Expands to a statement (either a simple expression or a compound * do..while(0) statement) that outputs a message with parameter * substitution if PNG_DEBUG is defined to 2 or more. If PNG_DEBUG * is undefined, 0 or 1 every png_debug expands to a simple expression * (actually ((void)0)). * * level: level of detail of message, starting at 0. A level 'n' * message is preceded by 'n' 3-space indentations (not implemented * on Microsoft compilers unless PNG_DEBUG_FILE is also * defined, to allow debug DLL compilation with no standard IO). * message: a printf(3) style text string. A trailing '\n' is added * to the message. * arg: 0 to 2 arguments for printf(3) style substitution in message. */ #ifndef PNGDEBUG_H #define PNGDEBUG_H /* These settings control the formatting of messages in png.c and pngerror.c */ /* Moved to pngdebug.h at 1.5.0 */ # ifndef PNG_LITERAL_SHARP # define PNG_LITERAL_SHARP 0x23 # endif # ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET # define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b # endif # ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET # define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d # endif # ifndef PNG_STRING_NEWLINE # define PNG_STRING_NEWLINE "\n" # endif #ifdef PNG_DEBUG # if (PNG_DEBUG > 0) # if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER) # include # if (PNG_DEBUG > 1) # ifndef _DEBUG # define _DEBUG # endif # ifndef png_debug # define png_debug(l,m) _RPT0(_CRT_WARN,m PNG_STRING_NEWLINE) # endif # ifndef png_debug1 # define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m PNG_STRING_NEWLINE,p1) # endif # ifndef png_debug2 # define png_debug2(l,m,p1,p2) \ _RPT2(_CRT_WARN,m PNG_STRING_NEWLINE,p1,p2) # endif # endif # else /* PNG_DEBUG_FILE || !_MSC_VER */ # ifndef PNG_STDIO_SUPPORTED # include /* not included yet */ # endif # ifndef PNG_DEBUG_FILE # define PNG_DEBUG_FILE stderr # endif /* PNG_DEBUG_FILE */ # if (PNG_DEBUG > 1) # ifdef __STDC__ # ifndef png_debug # define png_debug(l,m) \ do { \ int num_tabs=l; \ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ (num_tabs==2 ? " " : (num_tabs>2 ? " " : "")))); \ } while (0) # endif # ifndef png_debug1 # define png_debug1(l,m,p1) \ do { \ int num_tabs=l; \ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1); \ } while (0) # endif # ifndef png_debug2 # define png_debug2(l,m,p1,p2) \ do { \ int num_tabs=l; \ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1,p2);\ } while (0) # endif # else /* __STDC __ */ # ifndef png_debug # define png_debug(l,m) \ do { \ int num_tabs=l; \ char format[256]; \ snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ m,PNG_STRING_NEWLINE); \ fprintf(PNG_DEBUG_FILE,format); \ } while (0) # endif # ifndef png_debug1 # define png_debug1(l,m,p1) \ do { \ int num_tabs=l; \ char format[256]; \ snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ m,PNG_STRING_NEWLINE); \ fprintf(PNG_DEBUG_FILE,format,p1); \ } while (0) # endif # ifndef png_debug2 # define png_debug2(l,m,p1,p2) \ do { \ int num_tabs=l; \ char format[256]; \ snprintf(format,256,"%s%s%s",(num_tabs==1 ? "\t" : \ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))), \ m,PNG_STRING_NEWLINE); \ fprintf(PNG_DEBUG_FILE,format,p1,p2); \ } while (0) # endif # endif /* __STDC __ */ # endif /* (PNG_DEBUG > 1) */ # endif /* _MSC_VER */ # endif /* (PNG_DEBUG > 0) */ #endif /* PNG_DEBUG */ #ifndef png_debug # define png_debug(l, m) ((void)0) #endif #ifndef png_debug1 # define png_debug1(l, m, p1) ((void)0) #endif #ifndef png_debug2 # define png_debug2(l, m, p1, p2) ((void)0) #endif #endif /* PNGDEBUG_H */ stella-5.1.1/src/libpng/pngerror.c000066400000000000000000000710561324334165500170650ustar00rootroot00000000000000 /* pngerror.c - stub functions for i/o and memory allocation * * Last changed in libpng 1.6.31 [July 27, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * This file provides a location for all error handling. Users who * need special error handling are expected to write replacement functions * and use png_set_error_fn() to use those functions. See the instructions * at each function. */ #include "pngpriv.h" #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr, png_const_charp error_message)),PNG_NORETURN); #ifdef PNG_WARNINGS_SUPPORTED static void /* PRIVATE */ png_default_warning PNGARG((png_const_structrp png_ptr, png_const_charp warning_message)); #endif /* WARNINGS */ /* This function is called whenever there is a fatal error. This function * should not be changed. If there is a need to handle errors differently, * you should supply a replacement error function and use png_set_error_fn() * to replace the error function at run-time. */ #ifdef PNG_ERROR_TEXT_SUPPORTED PNG_FUNCTION(void,PNGAPI png_error,(png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN) { #ifdef PNG_ERROR_NUMBERS_SUPPORTED char msg[16]; if (png_ptr != NULL) { if ((png_ptr->flags & (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) { if (*error_message == PNG_LITERAL_SHARP) { /* Strip "#nnnn " from beginning of error message. */ int offset; for (offset = 1; offset<15; offset++) if (error_message[offset] == ' ') break; if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) { int i; for (i = 0; i < offset - 1; i++) msg[i] = error_message[i + 1]; msg[i - 1] = '\0'; error_message = msg; } else error_message += offset; } else { if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) { msg[0] = '0'; msg[1] = '\0'; error_message = msg; } } } } #endif if (png_ptr != NULL && png_ptr->error_fn != NULL) (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), error_message); /* If the custom handler doesn't exist, or if it returns, use the default handler, which will not return. */ png_default_error(png_ptr, error_message); } #else PNG_FUNCTION(void,PNGAPI png_err,(png_const_structrp png_ptr),PNG_NORETURN) { /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed * erroneously as '\0', instead of the empty string "". This was * apparently an error, introduced in libpng-1.2.20, and png_default_error * will crash in this case. */ if (png_ptr != NULL && png_ptr->error_fn != NULL) (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), ""); /* If the custom handler doesn't exist, or if it returns, use the default handler, which will not return. */ png_default_error(png_ptr, ""); } #endif /* ERROR_TEXT */ /* Utility to safely appends strings to a buffer. This never errors out so * error checking is not required in the caller. */ size_t png_safecat(png_charp buffer, size_t bufsize, size_t pos, png_const_charp string) { if (buffer != NULL && pos < bufsize) { if (string != NULL) while (*string != '\0' && pos < bufsize-1) buffer[pos++] = *string++; buffer[pos] = '\0'; } return pos; } #if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) /* Utility to dump an unsigned value into a buffer, given a start pointer and * and end pointer (which should point just *beyond* the end of the buffer!) * Returns the pointer to the start of the formatted string. */ png_charp png_format_number(png_const_charp start, png_charp end, int format, png_alloc_size_t number) { int count = 0; /* number of digits output */ int mincount = 1; /* minimum number required */ int output = 0; /* digit output (for the fixed point format) */ *--end = '\0'; /* This is written so that the loop always runs at least once, even with * number zero. */ while (end > start && (number != 0 || count < mincount)) { static const char digits[] = "0123456789ABCDEF"; switch (format) { case PNG_NUMBER_FORMAT_fixed: /* Needs five digits (the fraction) */ mincount = 5; if (output != 0 || number % 10 != 0) { *--end = digits[number % 10]; output = 1; } number /= 10; break; case PNG_NUMBER_FORMAT_02u: /* Expects at least 2 digits. */ mincount = 2; /* FALLTHROUGH */ case PNG_NUMBER_FORMAT_u: *--end = digits[number % 10]; number /= 10; break; case PNG_NUMBER_FORMAT_02x: /* This format expects at least two digits */ mincount = 2; /* FALLTHROUGH */ case PNG_NUMBER_FORMAT_x: *--end = digits[number & 0xf]; number >>= 4; break; default: /* an error */ number = 0; break; } /* Keep track of the number of digits added */ ++count; /* Float a fixed number here: */ if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start)) { /* End of the fraction, but maybe nothing was output? In that case * drop the decimal point. If the number is a true zero handle that * here. */ if (output != 0) *--end = '.'; else if (number == 0) /* and !output */ *--end = '0'; } } return end; } #endif #ifdef PNG_WARNINGS_SUPPORTED /* This function is called whenever there is a non-fatal error. This function * should not be changed. If there is a need to handle warnings differently, * you should supply a replacement warning function and use * png_set_error_fn() to replace the warning function at run-time. */ void PNGAPI png_warning(png_const_structrp png_ptr, png_const_charp warning_message) { int offset = 0; if (png_ptr != NULL) { #ifdef PNG_ERROR_NUMBERS_SUPPORTED if ((png_ptr->flags & (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) #endif { if (*warning_message == PNG_LITERAL_SHARP) { for (offset = 1; offset < 15; offset++) if (warning_message[offset] == ' ') break; } } } if (png_ptr != NULL && png_ptr->warning_fn != NULL) (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), warning_message + offset); else png_default_warning(png_ptr, warning_message + offset); } /* These functions support 'formatted' warning messages with up to * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter * is introduced by @, where 'number' starts at 1. This follows the * standard established by X/Open for internationalizable error messages. */ void png_warning_parameter(png_warning_parameters p, int number, png_const_charp string) { if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); } void png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, png_alloc_size_t value) { char buffer[PNG_NUMBER_BUFFER_SIZE]; png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); } void png_warning_parameter_signed(png_warning_parameters p, int number, int format, png_int_32 value) { png_alloc_size_t u; png_charp str; char buffer[PNG_NUMBER_BUFFER_SIZE]; /* Avoid overflow by doing the negate in a png_alloc_size_t: */ u = (png_alloc_size_t)value; if (value < 0) u = ~u + 1; str = PNG_FORMAT_NUMBER(buffer, format, u); if (value < 0 && str > buffer) *--str = '-'; png_warning_parameter(p, number, str); } void png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, png_const_charp message) { /* The internal buffer is just 192 bytes - enough for all our messages, * overflow doesn't happen because this code checks! If someone figures * out how to send us a message longer than 192 bytes, all that will * happen is that the message will be truncated appropriately. */ size_t i = 0; /* Index in the msg[] buffer: */ char msg[192]; /* Each iteration through the following loop writes at most one character * to msg[i++] then returns here to validate that there is still space for * the trailing '\0'. It may (in the case of a parameter) read more than * one character from message[]; it must check for '\0' and continue to the * test if it finds the end of string. */ while (i<(sizeof msg)-1 && *message != '\0') { /* '@' at end of string is now just printed (previously it was skipped); * it is an error in the calling code to terminate the string with @. */ if (p != NULL && *message == '@' && message[1] != '\0') { int parameter_char = *++message; /* Consume the '@' */ static const char valid_parameters[] = "123456789"; int parameter = 0; /* Search for the parameter digit, the index in the string is the * parameter to use. */ while (valid_parameters[parameter] != parameter_char && valid_parameters[parameter] != '\0') ++parameter; /* If the parameter digit is out of range it will just get printed. */ if (parameter < PNG_WARNING_PARAMETER_COUNT) { /* Append this parameter */ png_const_charp parm = p[parameter]; png_const_charp pend = p[parameter] + (sizeof p[parameter]); /* No need to copy the trailing '\0' here, but there is no guarantee * that parm[] has been initialized, so there is no guarantee of a * trailing '\0': */ while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend) msg[i++] = *parm++; /* Consume the parameter digit too: */ ++message; continue; } /* else not a parameter and there is a character after the @ sign; just * copy that. This is known not to be '\0' because of the test above. */ } /* At this point *message can't be '\0', even in the bad parameter case * above where there is a lone '@' at the end of the message string. */ msg[i++] = *message++; } /* i is always less than (sizeof msg), so: */ msg[i] = '\0'; /* And this is the formatted message. It may be larger than * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these * are not (currently) formatted. */ png_warning(png_ptr, msg); } #endif /* WARNINGS */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) { if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) { # ifdef PNG_READ_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && png_ptr->chunk_name != 0) png_chunk_warning(png_ptr, error_message); else # endif png_warning(png_ptr, error_message); } else { # ifdef PNG_READ_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && png_ptr->chunk_name != 0) png_chunk_error(png_ptr, error_message); else # endif png_error(png_ptr, error_message); } # ifndef PNG_ERROR_TEXT_SUPPORTED PNG_UNUSED(error_message) # endif } void /* PRIVATE */ png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) { if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0) png_warning(png_ptr, error_message); else png_error(png_ptr, error_message); # ifndef PNG_ERROR_TEXT_SUPPORTED PNG_UNUSED(error_message) # endif } void /* PRIVATE */ png_app_error(png_const_structrp png_ptr, png_const_charp error_message) { if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0) png_warning(png_ptr, error_message); else png_error(png_ptr, error_message); # ifndef PNG_ERROR_TEXT_SUPPORTED PNG_UNUSED(error_message) # endif } #endif /* BENIGN_ERRORS */ #define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */ #if defined(PNG_WARNINGS_SUPPORTED) || \ (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)) /* These utilities are used internally to build an error message that relates * to the current chunk. The chunk name comes from png_ptr->chunk_name, * which is used to prefix the message. The message is limited in length * to 63 bytes. The name characters are output as hex digits wrapped in [] * if the character is invalid. */ #define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) static PNG_CONST char png_digit[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static void /* PRIVATE */ png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp error_message) { png_uint_32 chunk_name = png_ptr->chunk_name; int iout = 0, ishift = 24; while (ishift >= 0) { int c = (int)(chunk_name >> ishift) & 0xff; ishift -= 8; if (isnonalpha(c) != 0) { buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; buffer[iout++] = png_digit[(c & 0xf0) >> 4]; buffer[iout++] = png_digit[c & 0x0f]; buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; } else { buffer[iout++] = (char)c; } } if (error_message == NULL) buffer[iout] = '\0'; else { int iin = 0; buffer[iout++] = ':'; buffer[iout++] = ' '; while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') buffer[iout++] = error_message[iin++]; /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ buffer[iout] = '\0'; } } #endif /* WARNINGS || ERROR_TEXT */ #if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) PNG_FUNCTION(void,PNGAPI png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN) { char msg[18+PNG_MAX_ERROR_TEXT]; if (png_ptr == NULL) png_error(png_ptr, error_message); else { png_format_buffer(png_ptr, msg, error_message); png_error(png_ptr, msg); } } #endif /* READ && ERROR_TEXT */ #ifdef PNG_WARNINGS_SUPPORTED void PNGAPI png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) { char msg[18+PNG_MAX_ERROR_TEXT]; if (png_ptr == NULL) png_warning(png_ptr, warning_message); else { png_format_buffer(png_ptr, msg, warning_message); png_warning(png_ptr, msg); } } #endif /* WARNINGS */ #ifdef PNG_READ_SUPPORTED #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp error_message) { if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) png_chunk_warning(png_ptr, error_message); else png_chunk_error(png_ptr, error_message); # ifndef PNG_ERROR_TEXT_SUPPORTED PNG_UNUSED(error_message) # endif } #endif #endif /* READ */ void /* PRIVATE */ png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) { # ifndef PNG_WARNINGS_SUPPORTED PNG_UNUSED(message) # endif /* This is always supported, but for just read or just write it * unconditionally does the right thing. */ # if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) # endif # ifdef PNG_READ_SUPPORTED { if (error < PNG_CHUNK_ERROR) png_chunk_warning(png_ptr, message); else png_chunk_benign_error(png_ptr, message); } # endif # if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) # endif # ifdef PNG_WRITE_SUPPORTED { if (error < PNG_CHUNK_WRITE_ERROR) png_app_warning(png_ptr, message); else png_app_error(png_ptr, message); } # endif } #ifdef PNG_ERROR_TEXT_SUPPORTED #ifdef PNG_FLOATING_POINT_SUPPORTED PNG_FUNCTION(void, png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) { # define fixed_message "fixed point overflow in " # define fixed_message_ln ((sizeof fixed_message)-1) unsigned int iin; char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; memcpy(msg, fixed_message, fixed_message_ln); iin = 0; if (name != NULL) while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) { msg[fixed_message_ln + iin] = name[iin]; ++iin; } msg[fixed_message_ln + iin] = 0; png_error(png_ptr, msg); } #endif #endif #ifdef PNG_SETJMP_SUPPORTED /* This API only exists if ANSI-C style error handling is used, * otherwise it is necessary for png_default_error to be overridden. */ jmp_buf* PNGAPI png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, size_t jmp_buf_size) { /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value * and it must not change after that. Libpng doesn't care how big the * buffer is, just that it doesn't change. * * If the buffer size is no *larger* than the size of jmp_buf when libpng is * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0 * semantics that this call will not fail. If the size is larger, however, * the buffer is allocated and this may fail, causing the function to return * NULL. */ if (png_ptr == NULL) return NULL; if (png_ptr->jmp_buf_ptr == NULL) { png_ptr->jmp_buf_size = 0; /* not allocated */ if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local)) png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; else { png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, png_malloc_warn(png_ptr, jmp_buf_size)); if (png_ptr->jmp_buf_ptr == NULL) return NULL; /* new NULL return on OOM */ png_ptr->jmp_buf_size = jmp_buf_size; } } else /* Already allocated: check the size */ { size_t size = png_ptr->jmp_buf_size; if (size == 0) { size = (sizeof png_ptr->jmp_buf_local); if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local) { /* This is an internal error in libpng: somehow we have been left * with a stack allocated jmp_buf when the application regained * control. It's always possible to fix this up, but for the moment * this is a png_error because that makes it easy to detect. */ png_error(png_ptr, "Libpng jmp_buf still allocated"); /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */ } } if (size != jmp_buf_size) { png_warning(png_ptr, "Application jmp_buf size changed"); return NULL; /* caller will probably crash: no choice here */ } } /* Finally fill in the function, now we have a satisfactory buffer. It is * valid to change the function on every call. */ png_ptr->longjmp_fn = longjmp_fn; return png_ptr->jmp_buf_ptr; } void /* PRIVATE */ png_free_jmpbuf(png_structrp png_ptr) { if (png_ptr != NULL) { jmp_buf *jb = png_ptr->jmp_buf_ptr; /* A size of 0 is used to indicate a local, stack, allocation of the * pointer; used here and in png.c */ if (jb != NULL && png_ptr->jmp_buf_size > 0) { /* This stuff is so that a failure to free the error control structure * does not leave libpng in a state with no valid error handling: the * free always succeeds, if there is an error it gets ignored. */ if (jb != &png_ptr->jmp_buf_local) { /* Make an internal, libpng, jmp_buf to return here */ jmp_buf free_jmp_buf; if (!setjmp(free_jmp_buf)) { png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */ png_ptr->jmp_buf_size = 0; /* stack allocation */ png_ptr->longjmp_fn = longjmp; png_free(png_ptr, jb); /* Return to setjmp on error */ } } } /* *Always* cancel everything out: */ png_ptr->jmp_buf_size = 0; png_ptr->jmp_buf_ptr = NULL; png_ptr->longjmp_fn = 0; } } #endif /* This is the default error handling function. Note that replacements for * this function MUST NOT RETURN, or the program will likely crash. This * function is used by default, or if the program supplies NULL for the * error function pointer in png_set_error_fn(). */ static PNG_FUNCTION(void /* PRIVATE */, png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN) { #ifdef PNG_CONSOLE_IO_SUPPORTED #ifdef PNG_ERROR_NUMBERS_SUPPORTED /* Check on NULL only added in 1.5.4 */ if (error_message != NULL && *error_message == PNG_LITERAL_SHARP) { /* Strip "#nnnn " from beginning of error message. */ int offset; char error_number[16]; for (offset = 0; offset<15; offset++) { error_number[offset] = error_message[offset + 1]; if (error_message[offset] == ' ') break; } if ((offset > 1) && (offset < 15)) { error_number[offset - 1] = '\0'; fprintf(stderr, "libpng error no. %s: %s", error_number, error_message + offset + 1); fprintf(stderr, PNG_STRING_NEWLINE); } else { fprintf(stderr, "libpng error: %s, offset=%d", error_message, offset); fprintf(stderr, PNG_STRING_NEWLINE); } } else #endif { fprintf(stderr, "libpng error: %s", error_message ? error_message : "undefined"); fprintf(stderr, PNG_STRING_NEWLINE); } #else PNG_UNUSED(error_message) /* Make compiler happy */ #endif png_longjmp(png_ptr, 1); } PNG_FUNCTION(void,PNGAPI png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN) { #ifdef PNG_SETJMP_SUPPORTED if (png_ptr != NULL && png_ptr->longjmp_fn != NULL && png_ptr->jmp_buf_ptr != NULL) png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); #else PNG_UNUSED(png_ptr) PNG_UNUSED(val) #endif /* If control reaches this point, png_longjmp() must not return. The only * choice is to terminate the whole process (or maybe the thread); to do * this the ANSI-C abort() function is used unless a different method is * implemented by overriding the default configuration setting for * PNG_ABORT(). */ PNG_ABORT(); } #ifdef PNG_WARNINGS_SUPPORTED /* This function is called when there is a warning, but the library thinks * it can continue anyway. Replacement functions don't have to do anything * here if you don't want them to. In the default configuration, png_ptr is * not used, but it is passed in case it may be useful. */ static void /* PRIVATE */ png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) { #ifdef PNG_CONSOLE_IO_SUPPORTED # ifdef PNG_ERROR_NUMBERS_SUPPORTED if (*warning_message == PNG_LITERAL_SHARP) { int offset; char warning_number[16]; for (offset = 0; offset < 15; offset++) { warning_number[offset] = warning_message[offset + 1]; if (warning_message[offset] == ' ') break; } if ((offset > 1) && (offset < 15)) { warning_number[offset + 1] = '\0'; fprintf(stderr, "libpng warning no. %s: %s", warning_number, warning_message + offset); fprintf(stderr, PNG_STRING_NEWLINE); } else { fprintf(stderr, "libpng warning: %s", warning_message); fprintf(stderr, PNG_STRING_NEWLINE); } } else # endif { fprintf(stderr, "libpng warning: %s", warning_message); fprintf(stderr, PNG_STRING_NEWLINE); } #else PNG_UNUSED(warning_message) /* Make compiler happy */ #endif PNG_UNUSED(png_ptr) /* Make compiler happy */ } #endif /* WARNINGS */ /* This function is called when the application wants to use another method * of handling errors and warnings. Note that the error function MUST NOT * return to the calling routine or serious problems will occur. The return * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1) */ void PNGAPI png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn) { if (png_ptr == NULL) return; png_ptr->error_ptr = error_ptr; png_ptr->error_fn = error_fn; #ifdef PNG_WARNINGS_SUPPORTED png_ptr->warning_fn = warning_fn; #else PNG_UNUSED(warning_fn) #endif } /* This function returns a pointer to the error_ptr associated with the user * functions. The application should free any memory associated with this * pointer before png_write_destroy and png_read_destroy are called. */ png_voidp PNGAPI png_get_error_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return NULL; return ((png_voidp)png_ptr->error_ptr); } #ifdef PNG_ERROR_NUMBERS_SUPPORTED void PNGAPI png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) { if (png_ptr != NULL) { png_ptr->flags &= ((~(PNG_FLAG_STRIP_ERROR_NUMBERS | PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); } } #endif #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) /* Currently the above both depend on SETJMP_SUPPORTED, however it would be * possible to implement without setjmp support just so long as there is some * way to handle the error return here: */ PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), PNG_NORETURN) { const png_const_structrp png_ptr = png_nonconst_ptr; png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); /* An error is always logged here, overwriting anything (typically a warning) * that is already there: */ if (image != NULL) { png_safecat(image->message, (sizeof image->message), 0, error_message); image->warning_or_error |= PNG_IMAGE_ERROR; /* Retrieve the jmp_buf from within the png_control, making this work for * C++ compilation too is pretty tricky: C++ wants a pointer to the first * element of a jmp_buf, but C doesn't tell us the type of that. */ if (image->opaque != NULL && image->opaque->error_buf != NULL) longjmp(png_control_jmp_buf(image->opaque), 1); /* Missing longjmp buffer, the following is to help debugging: */ { size_t pos = png_safecat(image->message, (sizeof image->message), 0, "bad longjmp: "); png_safecat(image->message, (sizeof image->message), pos, error_message); } } /* Here on an internal programming error. */ abort(); } #ifdef PNG_WARNINGS_SUPPORTED void /* PRIVATE */ PNGCBAPI png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) { const png_const_structrp png_ptr = png_nonconst_ptr; png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); /* A warning is only logged if there is no prior warning or error. */ if (image->warning_or_error == 0) { png_safecat(image->message, (sizeof image->message), 0, warning_message); image->warning_or_error |= PNG_IMAGE_WARNING; } } #endif int /* PRIVATE */ png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg) { volatile png_imagep image = image_in; volatile int result; volatile png_voidp saved_error_buf; jmp_buf safe_jmpbuf; /* Safely execute function(arg) with png_error returning to this function. */ saved_error_buf = image->opaque->error_buf; result = setjmp(safe_jmpbuf) == 0; if (result != 0) { image->opaque->error_buf = safe_jmpbuf; result = function(arg); } image->opaque->error_buf = saved_error_buf; /* And do the cleanup prior to any failure return. */ if (result == 0) png_image_free(image); return result; } #endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */ #endif /* READ || WRITE */ stella-5.1.1/src/libpng/pngget.c000066400000000000000000001024471324334165500165120ustar00rootroot00000000000000 /* pngget.c - retrieval of values from info struct * * Last changed in libpng 1.6.32 [August 24, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * */ #include "pngpriv.h" #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) png_uint_32 PNGAPI png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 flag) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->valid & flag); return(0); } png_size_t PNGAPI png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->rowbytes); return(0); } #ifdef PNG_INFO_IMAGE_SUPPORTED png_bytepp PNGAPI png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->row_pointers); return(0); } #endif #ifdef PNG_EASY_ACCESS_SUPPORTED /* Easy access to info, added in libpng-0.99 */ png_uint_32 PNGAPI png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->width; return (0); } png_uint_32 PNGAPI png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->height; return (0); } png_byte PNGAPI png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->bit_depth; return (0); } png_byte PNGAPI png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->color_type; return (0); } png_byte PNGAPI png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->filter_type; return (0); } png_byte PNGAPI png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->interlace_type; return (0); } png_byte PNGAPI png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return info_ptr->compression_type; return (0); } png_uint_32 PNGAPI png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_pHYs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_x_pixels_per_meter"); if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) return (info_ptr->x_pixels_per_unit); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return (0); } png_uint_32 PNGAPI png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_pHYs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_y_pixels_per_meter"); if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) return (info_ptr->y_pixels_per_unit); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return (0); } png_uint_32 PNGAPI png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_pHYs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER && info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit) return (info_ptr->x_pixels_per_unit); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return (0); } #ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_READ_pHYs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); if (info_ptr->x_pixels_per_unit != 0) return ((float)((float)info_ptr->y_pixels_per_unit /(float)info_ptr->x_pixels_per_unit)); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return ((float)0.0); } #endif #ifdef PNG_FIXED_POINT_SUPPORTED png_fixed_point PNGAPI png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_READ_pHYs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0 && info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 && info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX && info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) { png_fixed_point res; png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed"); /* The following casts work because a PNG 4 byte integer only has a valid * range of 0..2^31-1; otherwise the cast might overflow. */ if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1, (png_int_32)info_ptr->x_pixels_per_unit) != 0) return res; } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return 0; } #endif png_int_32 PNGAPI png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) return (info_ptr->x_offset); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return (0); } png_int_32 PNGAPI png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) return (info_ptr->y_offset); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return (0); } png_int_32 PNGAPI png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels"); if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) return (info_ptr->x_offset); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return (0); } png_int_32 PNGAPI png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels"); if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) return (info_ptr->y_offset); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif return (0); } #ifdef PNG_INCH_CONVERSIONS_SUPPORTED static png_uint_32 ppi_from_ppm(png_uint_32 ppm) { #if 0 /* The conversion is *(2.54/100), in binary (32 digits): * .00000110100000001001110101001001 */ png_uint_32 t1001, t1101; ppm >>= 1; /* .1 */ t1001 = ppm + (ppm >> 3); /* .1001 */ t1101 = t1001 + (ppm >> 1); /* .1101 */ ppm >>= 20; /* .000000000000000000001 */ t1101 += t1101 >> 15; /* .1101000000000001101 */ t1001 >>= 11; /* .000000000001001 */ t1001 += t1001 >> 12; /* .000000000001001000000001001 */ ppm += t1001; /* .000000000001001000001001001 */ ppm += t1101; /* .110100000001001110101001001 */ return (ppm + 16) >> 5;/* .00000110100000001001110101001001 */ #else /* The argument is a PNG unsigned integer, so it is not permitted * to be bigger than 2^31. */ png_fixed_point result; if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127, 5000) != 0) return (png_uint_32)result; /* Overflow. */ return 0; #endif } png_uint_32 PNGAPI png_get_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) { return ppi_from_ppm(png_get_pixels_per_meter(png_ptr, info_ptr)); } png_uint_32 PNGAPI png_get_x_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) { return ppi_from_ppm(png_get_x_pixels_per_meter(png_ptr, info_ptr)); } png_uint_32 PNGAPI png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) { return ppi_from_ppm(png_get_y_pixels_per_meter(png_ptr, info_ptr)); } #ifdef PNG_FIXED_POINT_SUPPORTED static png_fixed_point png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns) { /* Convert from metres * 1,000,000 to inches * 100,000, meters to * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127. * Notice that this can overflow - a warning is output and 0 is * returned. */ return png_muldiv_warn(png_ptr, microns, 500, 127); } png_fixed_point PNGAPI png_get_x_offset_inches_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr) { return png_fixed_inches_from_microns(png_ptr, png_get_x_offset_microns(png_ptr, info_ptr)); } #endif #ifdef PNG_FIXED_POINT_SUPPORTED png_fixed_point PNGAPI png_get_y_offset_inches_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr) { return png_fixed_inches_from_microns(png_ptr, png_get_y_offset_microns(png_ptr, info_ptr)); } #endif #ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI png_get_x_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) { /* To avoid the overflow do the conversion directly in floating * point. */ return (float)(png_get_x_offset_microns(png_ptr, info_ptr) * .00003937); } #endif #ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI png_get_y_offset_inches(png_const_structrp png_ptr, png_const_inforp info_ptr) { /* To avoid the overflow do the conversion directly in floating * point. */ return (float)(png_get_y_offset_microns(png_ptr, info_ptr) * .00003937); } #endif #ifdef PNG_pHYs_SUPPORTED png_uint_32 PNGAPI png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) { png_uint_32 retval = 0; if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_debug1(1, "in %s retrieval function", "pHYs"); if (res_x != NULL) { *res_x = info_ptr->x_pixels_per_unit; retval |= PNG_INFO_pHYs; } if (res_y != NULL) { *res_y = info_ptr->y_pixels_per_unit; retval |= PNG_INFO_pHYs; } if (unit_type != NULL) { *unit_type = (int)info_ptr->phys_unit_type; retval |= PNG_INFO_pHYs; if (*unit_type == 1) { if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50); if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50); } } } return (retval); } #endif /* pHYs */ #endif /* INCH_CONVERSIONS */ /* png_get_channels really belongs in here, too, but it's been around longer */ #endif /* EASY_ACCESS */ png_byte PNGAPI png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->channels); return (0); } #ifdef PNG_READ_SUPPORTED png_const_bytep PNGAPI png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return(info_ptr->signature); return (NULL); } #endif #ifdef PNG_bKGD_SUPPORTED png_uint_32 PNGAPI png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, png_color_16p *background) { if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0 && background != NULL) { png_debug1(1, "in %s retrieval function", "bKGD"); *background = &(info_ptr->background); return (PNG_INFO_bKGD); } return (0); } #endif #ifdef PNG_cHRM_SUPPORTED /* The XYZ APIs were added in 1.5.5 to take advantage of the code added at the * same time to correct the rgb grayscale coefficient defaults obtained from the * cHRM chunk in 1.5.4 */ # ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 PNGAPI png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, double *red_y, double *green_x, double *green_y, double *blue_x, double *blue_y) { /* Quiet API change: this code used to only return the end points if a cHRM * chunk was present, but the end points can also come from iCCP or sRGB * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and * the png_set_ APIs merely check that set end points are mutually * consistent. */ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { png_debug1(1, "in %s retrieval function", "cHRM"); if (white_x != NULL) *white_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.whitex, "cHRM white X"); if (white_y != NULL) *white_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y"); if (red_x != NULL) *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx, "cHRM red X"); if (red_y != NULL) *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy, "cHRM red Y"); if (green_x != NULL) *green_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.greenx, "cHRM green X"); if (green_y != NULL) *green_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y"); if (blue_x != NULL) *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex, "cHRM blue X"); if (blue_y != NULL) *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey, "cHRM blue Y"); return (PNG_INFO_cHRM); } return (0); } png_uint_32 PNGAPI png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, double *green_X, double *green_Y, double *green_Z, double *blue_X, double *blue_Y, double *blue_Z) { if (png_ptr != NULL && info_ptr != NULL && (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); if (red_X != NULL) *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X, "cHRM red X"); if (red_Y != NULL) *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y, "cHRM red Y"); if (red_Z != NULL) *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z, "cHRM red Z"); if (green_X != NULL) *green_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X"); if (green_Y != NULL) *green_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y"); if (green_Z != NULL) *green_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z"); if (blue_X != NULL) *blue_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X"); if (blue_Y != NULL) *blue_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y"); if (blue_Z != NULL) *blue_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z"); return (PNG_INFO_cHRM); } return (0); } # endif # ifdef PNG_FIXED_POINT_SUPPORTED png_uint_32 PNGAPI png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_red_X, png_fixed_point *int_red_Y, png_fixed_point *int_red_Z, png_fixed_point *int_green_X, png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, png_fixed_point *int_blue_Z) { if (png_ptr != NULL && info_ptr != NULL && (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); if (int_red_X != NULL) *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X; if (int_red_Y != NULL) *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y; if (int_red_Z != NULL) *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z; if (int_green_X != NULL) *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X; if (int_green_Y != NULL) *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y; if (int_green_Z != NULL) *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z; if (int_blue_X != NULL) *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X; if (int_blue_Y != NULL) *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y; if (int_blue_Z != NULL) *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z; return (PNG_INFO_cHRM); } return (0); } png_uint_32 PNGAPI png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, png_fixed_point *blue_x, png_fixed_point *blue_y) { png_debug1(1, "in %s retrieval function", "cHRM"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) { if (white_x != NULL) *white_x = info_ptr->colorspace.end_points_xy.whitex; if (white_y != NULL) *white_y = info_ptr->colorspace.end_points_xy.whitey; if (red_x != NULL) *red_x = info_ptr->colorspace.end_points_xy.redx; if (red_y != NULL) *red_y = info_ptr->colorspace.end_points_xy.redy; if (green_x != NULL) *green_x = info_ptr->colorspace.end_points_xy.greenx; if (green_y != NULL) *green_y = info_ptr->colorspace.end_points_xy.greeny; if (blue_x != NULL) *blue_x = info_ptr->colorspace.end_points_xy.bluex; if (blue_y != NULL) *blue_y = info_ptr->colorspace.end_points_xy.bluey; return (PNG_INFO_cHRM); } return (0); } # endif #endif #ifdef PNG_gAMA_SUPPORTED # ifdef PNG_FIXED_POINT_SUPPORTED png_uint_32 PNGAPI png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *file_gamma) { png_debug1(1, "in %s retrieval function", "gAMA"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && file_gamma != NULL) { *file_gamma = info_ptr->colorspace.gamma; return (PNG_INFO_gAMA); } return (0); } # endif # ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 PNGAPI png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr, double *file_gamma) { png_debug1(1, "in %s retrieval function", "gAMA(float)"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && file_gamma != NULL) { *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma, "png_get_gAMA"); return (PNG_INFO_gAMA); } return (0); } # endif #endif #ifdef PNG_sRGB_SUPPORTED png_uint_32 PNGAPI png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr, int *file_srgb_intent) { png_debug1(1, "in %s retrieval function", "sRGB"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) != 0 && file_srgb_intent != NULL) { *file_srgb_intent = info_ptr->colorspace.rendering_intent; return (PNG_INFO_sRGB); } return (0); } #endif #ifdef PNG_iCCP_SUPPORTED png_uint_32 PNGAPI png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, png_charpp name, int *compression_type, png_bytepp profile, png_uint_32 *proflen) { png_debug1(1, "in %s retrieval function", "iCCP"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) != 0 && name != NULL && compression_type != NULL && profile != NULL && proflen != NULL) { *name = info_ptr->iccp_name; *profile = info_ptr->iccp_profile; *proflen = png_get_uint_32(info_ptr->iccp_profile); /* This is somewhat irrelevant since the profile data returned has * actually been uncompressed. */ *compression_type = PNG_COMPRESSION_TYPE_BASE; return (PNG_INFO_iCCP); } return (0); } #endif #ifdef PNG_sPLT_SUPPORTED int PNGAPI png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, png_sPLT_tpp spalettes) { if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) { *spalettes = info_ptr->splt_palettes; return info_ptr->splt_palettes_num; } return (0); } #endif #ifdef PNG_eXIf_SUPPORTED png_uint_32 PNGAPI png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *exif) { png_warning(png_ptr, "png_get_eXIf does not work; use png_get_eXIf_1"); PNG_UNUSED(info_ptr) PNG_UNUSED(exif) return 0; } png_uint_32 PNGAPI png_get_eXIf_1(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *num_exif, png_bytep *exif) { png_debug1(1, "in %s retrieval function", "eXIf"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_eXIf) != 0 && exif != NULL) { *num_exif = info_ptr->num_exif; *exif = info_ptr->exif; return (PNG_INFO_eXIf); } return (0); } #endif #ifdef PNG_hIST_SUPPORTED png_uint_32 PNGAPI png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_16p *hist) { png_debug1(1, "in %s retrieval function", "hIST"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL) { *hist = info_ptr->hist; return (PNG_INFO_hIST); } return (0); } #endif png_uint_32 PNGAPI png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, int *interlace_type, int *compression_type, int *filter_type) { png_debug1(1, "in %s retrieval function", "IHDR"); if (png_ptr == NULL || info_ptr == NULL) return (0); if (width != NULL) *width = info_ptr->width; if (height != NULL) *height = info_ptr->height; if (bit_depth != NULL) *bit_depth = info_ptr->bit_depth; if (color_type != NULL) *color_type = info_ptr->color_type; if (compression_type != NULL) *compression_type = info_ptr->compression_type; if (filter_type != NULL) *filter_type = info_ptr->filter_type; if (interlace_type != NULL) *interlace_type = info_ptr->interlace_type; /* This is redundant if we can be sure that the info_ptr values were all * assigned in png_set_IHDR(). We do the check anyhow in case an * application has ignored our advice not to mess with the members * of info_ptr directly. */ png_check_IHDR(png_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, info_ptr->compression_type, info_ptr->filter_type); return (1); } #ifdef PNG_oFFs_SUPPORTED png_uint_32 PNGAPI png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type) { png_debug1(1, "in %s retrieval function", "oFFs"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0 && offset_x != NULL && offset_y != NULL && unit_type != NULL) { *offset_x = info_ptr->x_offset; *offset_y = info_ptr->y_offset; *unit_type = (int)info_ptr->offset_unit_type; return (PNG_INFO_oFFs); } return (0); } #endif #ifdef PNG_pCAL_SUPPORTED png_uint_32 PNGAPI png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams, png_charp *units, png_charpp *params) { png_debug1(1, "in %s retrieval function", "pCAL"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0 && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && nparams != NULL && units != NULL && params != NULL) { *purpose = info_ptr->pcal_purpose; *X0 = info_ptr->pcal_X0; *X1 = info_ptr->pcal_X1; *type = (int)info_ptr->pcal_type; *nparams = (int)info_ptr->pcal_nparams; *units = info_ptr->pcal_units; *params = info_ptr->pcal_params; return (PNG_INFO_pCAL); } return (0); } #endif #ifdef PNG_sCAL_SUPPORTED # ifdef PNG_FIXED_POINT_SUPPORTED # if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ defined(PNG_FLOATING_POINT_SUPPORTED) png_uint_32 PNGAPI png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, png_fixed_point *width, png_fixed_point *height) { if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0) { *unit = info_ptr->scal_unit; /*TODO: make this work without FP support; the API is currently eliminated * if neither floating point APIs nor internal floating point arithmetic * are enabled. */ *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width"); *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height), "sCAL height"); return (PNG_INFO_sCAL); } return(0); } # endif /* FLOATING_ARITHMETIC */ # endif /* FIXED_POINT */ # ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 PNGAPI png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, double *width, double *height) { if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0) { *unit = info_ptr->scal_unit; *width = atof(info_ptr->scal_s_width); *height = atof(info_ptr->scal_s_height); return (PNG_INFO_sCAL); } return(0); } # endif /* FLOATING POINT */ png_uint_32 PNGAPI png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, png_charpp width, png_charpp height) { if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0) { *unit = info_ptr->scal_unit; *width = info_ptr->scal_s_width; *height = info_ptr->scal_s_height; return (PNG_INFO_sCAL); } return(0); } #endif /* sCAL */ #ifdef PNG_pHYs_SUPPORTED png_uint_32 PNGAPI png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type) { png_uint_32 retval = 0; png_debug1(1, "in %s retrieval function", "pHYs"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { if (res_x != NULL) { *res_x = info_ptr->x_pixels_per_unit; retval |= PNG_INFO_pHYs; } if (res_y != NULL) { *res_y = info_ptr->y_pixels_per_unit; retval |= PNG_INFO_pHYs; } if (unit_type != NULL) { *unit_type = (int)info_ptr->phys_unit_type; retval |= PNG_INFO_pHYs; } } return (retval); } #endif /* pHYs */ png_uint_32 PNGAPI png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr, png_colorp *palette, int *num_palette) { png_debug1(1, "in %s retrieval function", "PLTE"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) != 0 && palette != NULL) { *palette = info_ptr->palette; *num_palette = info_ptr->num_palette; png_debug1(3, "num_palette = %d", *num_palette); return (PNG_INFO_PLTE); } return (0); } #ifdef PNG_sBIT_SUPPORTED png_uint_32 PNGAPI png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, png_color_8p *sig_bit) { png_debug1(1, "in %s retrieval function", "sBIT"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL) { *sig_bit = &(info_ptr->sig_bit); return (PNG_INFO_sBIT); } return (0); } #endif #ifdef PNG_TEXT_SUPPORTED int PNGAPI png_get_text(png_const_structrp png_ptr, png_inforp info_ptr, png_textp *text_ptr, int *num_text) { if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) { png_debug1(1, "in 0x%lx retrieval function", (unsigned long)png_ptr->chunk_name); if (text_ptr != NULL) *text_ptr = info_ptr->text; if (num_text != NULL) *num_text = info_ptr->num_text; return info_ptr->num_text; } if (num_text != NULL) *num_text = 0; return(0); } #endif #ifdef PNG_tIME_SUPPORTED png_uint_32 PNGAPI png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr, png_timep *mod_time) { png_debug1(1, "in %s retrieval function", "tIME"); if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL) { *mod_time = &(info_ptr->mod_time); return (PNG_INFO_tIME); } return (0); } #endif #ifdef PNG_tRNS_SUPPORTED png_uint_32 PNGAPI png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) { png_uint_32 retval = 0; if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0) { png_debug1(1, "in %s retrieval function", "tRNS"); if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if (trans_alpha != NULL) { *trans_alpha = info_ptr->trans_alpha; retval |= PNG_INFO_tRNS; } if (trans_color != NULL) *trans_color = &(info_ptr->trans_color); } else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */ { if (trans_color != NULL) { *trans_color = &(info_ptr->trans_color); retval |= PNG_INFO_tRNS; } if (trans_alpha != NULL) *trans_alpha = NULL; } if (num_trans != NULL) { *num_trans = info_ptr->num_trans; retval |= PNG_INFO_tRNS; } } return (retval); } #endif #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED int PNGAPI png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, png_unknown_chunkpp unknowns) { if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL) { *unknowns = info_ptr->unknown_chunks; return info_ptr->unknown_chunks_num; } return (0); } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED png_byte PNGAPI png_get_rgb_to_gray_status (png_const_structrp png_ptr) { return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); } #endif #ifdef PNG_USER_CHUNKS_SUPPORTED png_voidp PNGAPI png_get_user_chunk_ptr(png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_ptr : NULL); } #endif png_size_t PNGAPI png_get_compression_buffer_size(png_const_structrp png_ptr) { if (png_ptr == NULL) return 0; #ifdef PNG_WRITE_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) #endif { #ifdef PNG_SEQUENTIAL_READ_SUPPORTED return png_ptr->IDAT_read_size; #else return PNG_IDAT_READ_SIZE; #endif } #ifdef PNG_WRITE_SUPPORTED else return png_ptr->zbuffer_size; #endif } #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* These functions were added to libpng 1.2.6 and were enabled * by default in libpng-1.4.0 */ png_uint_32 PNGAPI png_get_user_width_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_width_max : 0); } png_uint_32 PNGAPI png_get_user_height_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_height_max : 0); } /* This function was added to libpng 1.4.0 */ png_uint_32 PNGAPI png_get_chunk_cache_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_cache_max : 0); } /* This function was added to libpng 1.4.1 */ png_alloc_size_t PNGAPI png_get_chunk_malloc_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); } #endif /* SET_USER_LIMITS */ /* These functions were added to libpng 1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED png_uint_32 PNGAPI png_get_io_state (png_const_structrp png_ptr) { return png_ptr->io_state; } png_uint_32 PNGAPI png_get_io_chunk_type (png_const_structrp png_ptr) { return png_ptr->chunk_name; } #endif /* IO_STATE */ #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED # ifdef PNG_GET_PALETTE_MAX_SUPPORTED int PNGAPI png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) { if (png_ptr != NULL && info_ptr != NULL) return png_ptr->num_palette_max; return (-1); } # endif #endif #endif /* READ || WRITE */ stella-5.1.1/src/libpng/pnginfo.h000066400000000000000000000303701324334165500166660ustar00rootroot00000000000000 /* pnginfo.h - header file for PNG reference library * * Last changed in libpng 1.6.1 [March 28, 2013] * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ /* png_info is a structure that holds the information in a PNG file so * that the application can find out the characteristics of the image. * If you are reading the file, this structure will tell you what is * in the PNG file. If you are writing the file, fill in the information * you want to put into the PNG file, using png_set_*() functions, then * call png_write_info(). * * The names chosen should be very close to the PNG specification, so * consult that document for information about the meaning of each field. * * With libpng < 0.95, it was only possible to directly set and read the * the values in the png_info_struct, which meant that the contents and * order of the values had to remain fixed. With libpng 0.95 and later, * however, there are now functions that abstract the contents of * png_info_struct from the application, so this makes it easier to use * libpng with dynamic libraries, and even makes it possible to use * libraries that don't have all of the libpng ancillary chunk-handing * functionality. In libpng-1.5.0 this was moved into a separate private * file that is not visible to applications. * * The following members may have allocated storage attached that should be * cleaned up before the structure is discarded: palette, trans, text, * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these * are automatically freed when the info structure is deallocated, if they were * allocated internally by libpng. This behavior can be changed by means * of the png_data_freer() function. * * More allocation details: all the chunk-reading functions that * change these members go through the corresponding png_set_* * functions. A function to clear these members is available: see * png_free_data(). The png_set_* functions do not depend on being * able to point info structure members to any of the storage they are * passed (they make their own copies), EXCEPT that the png_set_text * functions use the same storage passed to them in the text_ptr or * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns * functions do not make their own copies. */ #ifndef PNGINFO_H #define PNGINFO_H struct png_info_def { /* The following are necessary for every PNG file */ png_uint_32 width; /* width of image in pixels (from IHDR) */ png_uint_32 height; /* height of image in pixels (from IHDR) */ png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ png_size_t rowbytes; /* bytes needed to hold an untransformed row */ png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */ png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */ /* The following three should have been named *_method not *_type */ png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */ png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */ png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ /* The following are set by png_set_IHDR, called from the application on * write, but the are never actually used by the write code. */ png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */ png_byte pixel_depth; /* number of bits per pixel */ png_byte spare_byte; /* to align the data, and for future use */ #ifdef PNG_READ_SUPPORTED /* This is never set during write */ png_byte signature[8]; /* magic bytes read by libpng from start of file */ #endif /* The rest of the data is optional. If you are reading, check the * valid field to see if the information in these are valid. If you * are writing, set the valid field to those chunks you want written, * and initialize the appropriate fields below. */ #if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are * defined. When COLORSPACE is switched on all the colorspace-defining * chunks should be enabled, when GAMMA is switched on all the gamma-defining * chunks should be enabled. If this is not done it becomes possible to read * inconsistent PNG files and assign a probably incorrect interpretation to * the information. (In other words, by carefully choosing which chunks to * recognize the system configuration can select an interpretation for PNG * files containing ambiguous data and this will result in inconsistent * behavior between different libpng builds!) */ png_colorspace colorspace; #endif #ifdef PNG_iCCP_SUPPORTED /* iCCP chunk data. */ png_charp iccp_name; /* profile name */ png_bytep iccp_profile; /* International Color Consortium profile data */ png_uint_32 iccp_proflen; /* ICC profile data length */ #endif #ifdef PNG_TEXT_SUPPORTED /* The tEXt, and zTXt chunks contain human-readable textual data in * uncompressed, compressed, and optionally compressed forms, respectively. * The data in "text" is an array of pointers to uncompressed, * null-terminated C strings. Each chunk has a keyword that describes the * textual data contained in that chunk. Keywords are not required to be * unique, and the text string may be empty. Any number of text chunks may * be in an image. */ int num_text; /* number of comments read or comments to write */ int max_text; /* current size of text array */ png_textp text; /* array of comments read or comments to write */ #endif /* TEXT */ #ifdef PNG_tIME_SUPPORTED /* The tIME chunk holds the last time the displayed image data was * modified. See the png_time struct for the contents of this struct. */ png_time mod_time; #endif #ifdef PNG_sBIT_SUPPORTED /* The sBIT chunk specifies the number of significant high-order bits * in the pixel data. Values are in the range [1, bit_depth], and are * only specified for the channels in the pixel data. The contents of * the low-order bits is not specified. Data is valid if * (valid & PNG_INFO_sBIT) is non-zero. */ png_color_8 sig_bit; /* significant bits in color channels */ #endif #if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \ defined(PNG_READ_BACKGROUND_SUPPORTED) /* The tRNS chunk supplies transparency data for paletted images and * other image types that don't need a full alpha channel. There are * "num_trans" transparency values for a paletted image, stored in the * same order as the palette colors, starting from index 0. Values * for the data are in the range [0, 255], ranging from fully transparent * to fully opaque, respectively. For non-paletted images, there is a * single color specified that should be treated as fully transparent. * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. */ png_bytep trans_alpha; /* alpha values for paletted image */ png_color_16 trans_color; /* transparent color for non-palette image */ #endif #if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) /* The bKGD chunk gives the suggested image background color if the * display program does not have its own background color and the image * is needs to composited onto a background before display. The colors * in "background" are normally in the same color space/depth as the * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero. */ png_color_16 background; #endif #ifdef PNG_oFFs_SUPPORTED /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards * and downwards from the top-left corner of the display, page, or other * application-specific co-ordinate space. See the PNG_OFFSET_ defines * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero. */ png_int_32 x_offset; /* x offset on page */ png_int_32 y_offset; /* y offset on page */ png_byte offset_unit_type; /* offset units type */ #endif #ifdef PNG_pHYs_SUPPORTED /* The pHYs chunk gives the physical pixel density of the image for * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_ * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero. */ png_uint_32 x_pixels_per_unit; /* horizontal pixel density */ png_uint_32 y_pixels_per_unit; /* vertical pixel density */ png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ #endif #ifdef PNG_eXIf_SUPPORTED int num_exif; /* Added at libpng-1.6.31 */ png_bytep exif; # ifdef PNG_READ_eXIf_SUPPORTED png_bytep eXIf_buf; /* Added at libpng-1.6.32 */ # endif #endif #ifdef PNG_hIST_SUPPORTED /* The hIST chunk contains the relative frequency or importance of the * various palette entries, so that a viewer can intelligently select a * reduced-color palette, if required. Data is an array of "num_palette" * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST) * is non-zero. */ png_uint_16p hist; #endif #ifdef PNG_pCAL_SUPPORTED /* The pCAL chunk describes a transformation between the stored pixel * values and original physical data values used to create the image. * The integer range [0, 2^bit_depth - 1] maps to the floating-point * range given by [pcal_X0, pcal_X1], and are further transformed by a * (possibly non-linear) transformation function given by "pcal_type" * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_ * defines below, and the PNG-Group's PNG extensions document for a * complete description of the transformations and how they should be * implemented, and for a description of the ASCII parameter strings. * Data values are valid if (valid & PNG_INFO_pCAL) non-zero. */ png_charp pcal_purpose; /* pCAL chunk description string */ png_int_32 pcal_X0; /* minimum value */ png_int_32 pcal_X1; /* maximum value */ png_charp pcal_units; /* Latin-1 string giving physical units */ png_charpp pcal_params; /* ASCII strings containing parameter values */ png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */ png_byte pcal_nparams; /* number of parameters given in pcal_params */ #endif /* New members added in libpng-1.0.6 */ png_uint_32 free_me; /* flags items libpng is responsible for freeing */ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED /* Storage for unknown chunks that the library doesn't recognize. */ png_unknown_chunkp unknown_chunks; /* The type of this field is limited by the type of * png_struct::user_chunk_cache_max, else overflow can occur. */ int unknown_chunks_num; #endif #ifdef PNG_sPLT_SUPPORTED /* Data on sPLT chunks (there may be more than one). */ png_sPLT_tp splt_palettes; int splt_palettes_num; /* Match type returned by png_get API */ #endif #ifdef PNG_sCAL_SUPPORTED /* The sCAL chunk describes the actual physical dimensions of the * subject matter of the graphic. The chunk contains a unit specification * a byte value, and two ASCII strings representing floating-point * values. The values are width and height corresponsing to one pixel * in the image. Data values are valid if (valid & PNG_INFO_sCAL) is * non-zero. */ png_byte scal_unit; /* unit of physical scale */ png_charp scal_s_width; /* string containing height */ png_charp scal_s_height; /* string containing width */ #endif #ifdef PNG_INFO_IMAGE_SUPPORTED /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */ /* Data valid if (valid & PNG_INFO_IDAT) non-zero */ png_bytepp row_pointers; /* the image bits */ #endif }; #endif /* PNGINFO_H */ stella-5.1.1/src/libpng/pnglibconf.h000066400000000000000000000166141324334165500173540ustar00rootroot00000000000000/* pnglibconf.h - library build configuration */ /* libpng version 1.6.34, September 29, 2017 */ /* Copyright (c) 1998-2017 Glenn Randers-Pehrson */ /* This code is released under the libpng license. */ /* For conditions of distribution and use, see the disclaimer */ /* and license in png.h */ /* pnglibconf.h */ /* Machine generated file: DO NOT EDIT */ /* Derived from: scripts/pnglibconf.dfa */ #ifndef PNGLCONF_H #define PNGLCONF_H /* options */ #define PNG_16BIT_SUPPORTED #define PNG_ALIGNED_MEMORY_SUPPORTED /*#undef PNG_ARM_NEON_API_SUPPORTED*/ /*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ #define PNG_BENIGN_ERRORS_SUPPORTED #define PNG_BENIGN_READ_ERRORS_SUPPORTED /*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ #define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED #define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED #define PNG_COLORSPACE_SUPPORTED #define PNG_CONSOLE_IO_SUPPORTED #define PNG_CONVERT_tIME_SUPPORTED #define PNG_EASY_ACCESS_SUPPORTED /*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ #define PNG_ERROR_TEXT_SUPPORTED #define PNG_FIXED_POINT_SUPPORTED #define PNG_FLOATING_ARITHMETIC_SUPPORTED #define PNG_FLOATING_POINT_SUPPORTED #define PNG_FORMAT_AFIRST_SUPPORTED #define PNG_FORMAT_BGR_SUPPORTED #define PNG_GAMMA_SUPPORTED #define PNG_GET_PALETTE_MAX_SUPPORTED #define PNG_HANDLE_AS_UNKNOWN_SUPPORTED #define PNG_INCH_CONVERSIONS_SUPPORTED #define PNG_INFO_IMAGE_SUPPORTED #define PNG_IO_STATE_SUPPORTED #define PNG_MNG_FEATURES_SUPPORTED #define PNG_POINTER_INDEXING_SUPPORTED /*#undef PNG_POWERPC_VSX_API_SUPPORTED*/ /*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/ #define PNG_PROGRESSIVE_READ_SUPPORTED #define PNG_READ_16BIT_SUPPORTED #define PNG_READ_ALPHA_MODE_SUPPORTED #define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED #define PNG_READ_BACKGROUND_SUPPORTED #define PNG_READ_BGR_SUPPORTED #define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED #define PNG_READ_COMPOSITE_NODIV_SUPPORTED #define PNG_READ_COMPRESSED_TEXT_SUPPORTED #define PNG_READ_EXPAND_16_SUPPORTED #define PNG_READ_EXPAND_SUPPORTED #define PNG_READ_FILLER_SUPPORTED #define PNG_READ_GAMMA_SUPPORTED #define PNG_READ_GET_PALETTE_MAX_SUPPORTED #define PNG_READ_GRAY_TO_RGB_SUPPORTED #define PNG_READ_INTERLACING_SUPPORTED #define PNG_READ_INT_FUNCTIONS_SUPPORTED #define PNG_READ_INVERT_ALPHA_SUPPORTED #define PNG_READ_INVERT_SUPPORTED #define PNG_READ_OPT_PLTE_SUPPORTED #define PNG_READ_PACKSWAP_SUPPORTED #define PNG_READ_PACK_SUPPORTED #define PNG_READ_QUANTIZE_SUPPORTED #define PNG_READ_RGB_TO_GRAY_SUPPORTED #define PNG_READ_SCALE_16_TO_8_SUPPORTED #define PNG_READ_SHIFT_SUPPORTED #define PNG_READ_STRIP_16_TO_8_SUPPORTED #define PNG_READ_STRIP_ALPHA_SUPPORTED #define PNG_READ_SUPPORTED #define PNG_READ_SWAP_ALPHA_SUPPORTED #define PNG_READ_SWAP_SUPPORTED #define PNG_READ_TEXT_SUPPORTED #define PNG_READ_TRANSFORMS_SUPPORTED #define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED #define PNG_READ_USER_CHUNKS_SUPPORTED #define PNG_READ_USER_TRANSFORM_SUPPORTED #define PNG_READ_bKGD_SUPPORTED #define PNG_READ_cHRM_SUPPORTED #define PNG_READ_eXIf_SUPPORTED #define PNG_READ_gAMA_SUPPORTED #define PNG_READ_hIST_SUPPORTED #define PNG_READ_iCCP_SUPPORTED #define PNG_READ_iTXt_SUPPORTED #define PNG_READ_oFFs_SUPPORTED #define PNG_READ_pCAL_SUPPORTED #define PNG_READ_pHYs_SUPPORTED #define PNG_READ_sBIT_SUPPORTED #define PNG_READ_sCAL_SUPPORTED #define PNG_READ_sPLT_SUPPORTED #define PNG_READ_sRGB_SUPPORTED #define PNG_READ_tEXt_SUPPORTED #define PNG_READ_tIME_SUPPORTED #define PNG_READ_tRNS_SUPPORTED #define PNG_READ_zTXt_SUPPORTED #define PNG_SAVE_INT_32_SUPPORTED #define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_SEQUENTIAL_READ_SUPPORTED #define PNG_SETJMP_SUPPORTED #define PNG_SET_OPTION_SUPPORTED #define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED #define PNG_SET_USER_LIMITS_SUPPORTED #define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED #define PNG_SIMPLIFIED_READ_BGR_SUPPORTED #define PNG_SIMPLIFIED_READ_SUPPORTED #define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED #define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED #define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED #define PNG_SIMPLIFIED_WRITE_SUPPORTED #define PNG_STDIO_SUPPORTED #define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_TEXT_SUPPORTED #define PNG_TIME_RFC1123_SUPPORTED #define PNG_UNKNOWN_CHUNKS_SUPPORTED #define PNG_USER_CHUNKS_SUPPORTED #define PNG_USER_LIMITS_SUPPORTED #define PNG_USER_MEM_SUPPORTED #define PNG_USER_TRANSFORM_INFO_SUPPORTED #define PNG_USER_TRANSFORM_PTR_SUPPORTED #define PNG_WARNINGS_SUPPORTED #define PNG_WRITE_16BIT_SUPPORTED #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED #define PNG_WRITE_BGR_SUPPORTED #define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED #define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED #define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED #define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED #define PNG_WRITE_FILLER_SUPPORTED #define PNG_WRITE_FILTER_SUPPORTED #define PNG_WRITE_FLUSH_SUPPORTED #define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED #define PNG_WRITE_INTERLACING_SUPPORTED #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED #define PNG_WRITE_INVERT_ALPHA_SUPPORTED #define PNG_WRITE_INVERT_SUPPORTED #define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED #define PNG_WRITE_PACKSWAP_SUPPORTED #define PNG_WRITE_PACK_SUPPORTED #define PNG_WRITE_SHIFT_SUPPORTED #define PNG_WRITE_SUPPORTED #define PNG_WRITE_SWAP_ALPHA_SUPPORTED #define PNG_WRITE_SWAP_SUPPORTED #define PNG_WRITE_TEXT_SUPPORTED #define PNG_WRITE_TRANSFORMS_SUPPORTED #define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_WRITE_USER_TRANSFORM_SUPPORTED #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED #define PNG_WRITE_bKGD_SUPPORTED #define PNG_WRITE_cHRM_SUPPORTED #define PNG_WRITE_eXIf_SUPPORTED #define PNG_WRITE_gAMA_SUPPORTED #define PNG_WRITE_hIST_SUPPORTED #define PNG_WRITE_iCCP_SUPPORTED #define PNG_WRITE_iTXt_SUPPORTED #define PNG_WRITE_oFFs_SUPPORTED #define PNG_WRITE_pCAL_SUPPORTED #define PNG_WRITE_pHYs_SUPPORTED #define PNG_WRITE_sBIT_SUPPORTED #define PNG_WRITE_sCAL_SUPPORTED #define PNG_WRITE_sPLT_SUPPORTED #define PNG_WRITE_sRGB_SUPPORTED #define PNG_WRITE_tEXt_SUPPORTED #define PNG_WRITE_tIME_SUPPORTED #define PNG_WRITE_tRNS_SUPPORTED #define PNG_WRITE_zTXt_SUPPORTED #define PNG_bKGD_SUPPORTED #define PNG_cHRM_SUPPORTED #define PNG_eXIf_SUPPORTED #define PNG_gAMA_SUPPORTED #define PNG_hIST_SUPPORTED #define PNG_iCCP_SUPPORTED #define PNG_iTXt_SUPPORTED #define PNG_oFFs_SUPPORTED #define PNG_pCAL_SUPPORTED #define PNG_pHYs_SUPPORTED #define PNG_sBIT_SUPPORTED #define PNG_sCAL_SUPPORTED #define PNG_sPLT_SUPPORTED #define PNG_sRGB_SUPPORTED #define PNG_tEXt_SUPPORTED #define PNG_tIME_SUPPORTED #define PNG_tRNS_SUPPORTED #define PNG_zTXt_SUPPORTED /* end of options */ /* settings */ #define PNG_API_RULE 0 #define PNG_DEFAULT_READ_MACROS 1 #define PNG_GAMMA_THRESHOLD_FIXED 5000 #define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE #define PNG_INFLATE_BUF_SIZE 1024 #define PNG_LINKAGE_API extern #define PNG_LINKAGE_CALLBACK extern #define PNG_LINKAGE_DATA extern #define PNG_LINKAGE_FUNCTION extern #define PNG_MAX_GAMMA_8 11 #define PNG_QUANTIZE_BLUE_BITS 5 #define PNG_QUANTIZE_GREEN_BITS 5 #define PNG_QUANTIZE_RED_BITS 5 #define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) #define PNG_TEXT_Z_DEFAULT_STRATEGY 0 #define PNG_USER_CHUNK_CACHE_MAX 1000 #define PNG_USER_CHUNK_MALLOC_MAX 8000000 #define PNG_USER_HEIGHT_MAX 1000000 #define PNG_USER_WIDTH_MAX 1000000 #define PNG_ZBUF_SIZE 8192 #define PNG_ZLIB_VERNUM 0x12b0 #define PNG_Z_DEFAULT_COMPRESSION (-1) #define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 #define PNG_Z_DEFAULT_STRATEGY 1 #define PNG_sCAL_PRECISION 5 #define PNG_sRGB_PROFILE_CHECKS 2 /* end of settings */ #endif /* PNGLCONF_H */ stella-5.1.1/src/libpng/pngmem.c000066400000000000000000000202641324334165500165050ustar00rootroot00000000000000 /* pngmem.c - stub functions for memory allocation * * Last changed in libpng 1.6.26 [October 20, 2016] * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * This file provides a location for all memory allocation. Users who * need special memory handling are expected to supply replacement * functions for png_malloc() and png_free(), and to use * png_create_read_struct_2() and png_create_write_struct_2() to * identify the replacement functions. */ #include "pngpriv.h" #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) /* Free a png_struct */ void /* PRIVATE */ png_destroy_png_struct(png_structrp png_ptr) { if (png_ptr != NULL) { /* png_free might call png_error and may certainly call * png_get_mem_ptr, so fake a temporary png_struct to support this. */ png_struct dummy_struct = *png_ptr; memset(png_ptr, 0, (sizeof *png_ptr)); png_free(&dummy_struct, png_ptr); # ifdef PNG_SETJMP_SUPPORTED /* We may have a jmp_buf left to deallocate. */ png_free_jmpbuf(&dummy_struct); # endif } } /* Allocate memory. For reasonable files, size should never exceed * 64K. However, zlib may allocate more than 64K if you don't tell * it not to. See zconf.h and png.h for more information. zlib does * need to allocate exactly 64K, so whatever you call here must * have the ability to do that. */ PNG_FUNCTION(png_voidp,PNGAPI png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) { png_voidp ret; ret = png_malloc(png_ptr, size); if (ret != NULL) memset(ret, 0, size); return ret; } /* png_malloc_base, an internal function added at libpng 1.6.0, does the work of * allocating memory, taking into account limits and PNG_USER_MEM_SUPPORTED. * Checking and error handling must happen outside this routine; it returns NULL * if the allocation cannot be done (for any reason.) */ PNG_FUNCTION(png_voidp /* PRIVATE */, png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size), PNG_ALLOCATED) { /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS * allocators have also been removed in 1.6.0, so any 16-bit system now has * to implement a user memory handler. This checks to be sure it isn't * called with big numbers. */ #ifndef PNG_USER_MEM_SUPPORTED PNG_UNUSED(png_ptr) #endif /* Some compilers complain that this is always true. However, it * can be false when integer overflow happens. */ if (size > 0 && size <= PNG_SIZE_MAX # ifdef PNG_MAX_MALLOC_64K && size <= 65536U # endif ) { #ifdef PNG_USER_MEM_SUPPORTED if (png_ptr != NULL && png_ptr->malloc_fn != NULL) return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size); else #endif return malloc((size_t)size); /* checked for truncation above */ } else return NULL; } #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) /* This is really here only to work round a spurious warning in GCC 4.6 and 4.7 * that arises because of the checks in png_realloc_array that are repeated in * png_malloc_array. */ static png_voidp png_malloc_array_checked(png_const_structrp png_ptr, int nelements, size_t element_size) { png_alloc_size_t req = (png_alloc_size_t)nelements; /* known to be > 0 */ if (req <= PNG_SIZE_MAX/element_size) return png_malloc_base(png_ptr, req * element_size); /* The failure case when the request is too large */ return NULL; } PNG_FUNCTION(png_voidp /* PRIVATE */, png_malloc_array,(png_const_structrp png_ptr, int nelements, size_t element_size),PNG_ALLOCATED) { if (nelements <= 0 || element_size == 0) png_error(png_ptr, "internal error: array alloc"); return png_malloc_array_checked(png_ptr, nelements, element_size); } PNG_FUNCTION(png_voidp /* PRIVATE */, png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED) { /* These are internal errors: */ if (add_elements <= 0 || element_size == 0 || old_elements < 0 || (old_array == NULL && old_elements > 0)) png_error(png_ptr, "internal error: array realloc"); /* Check for overflow on the elements count (so the caller does not have to * check.) */ if (add_elements <= INT_MAX - old_elements) { png_voidp new_array = png_malloc_array_checked(png_ptr, old_elements+add_elements, element_size); if (new_array != NULL) { /* Because png_malloc_array worked the size calculations below cannot * overflow. */ if (old_elements > 0) memcpy(new_array, old_array, element_size*(unsigned)old_elements); memset((char*)new_array + element_size*(unsigned)old_elements, 0, element_size*(unsigned)add_elements); return new_array; } } return NULL; /* error */ } #endif /* TEXT || sPLT || STORE_UNKNOWN_CHUNKS */ /* Various functions that have different error handling are derived from this. * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate * function png_malloc_default is also provided. */ PNG_FUNCTION(png_voidp,PNGAPI png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) { png_voidp ret; if (png_ptr == NULL) return NULL; ret = png_malloc_base(png_ptr, size); if (ret == NULL) png_error(png_ptr, "Out of memory"); /* 'm' means png_malloc */ return ret; } #ifdef PNG_USER_MEM_SUPPORTED PNG_FUNCTION(png_voidp,PNGAPI png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED) { png_voidp ret; if (png_ptr == NULL) return NULL; /* Passing 'NULL' here bypasses the application provided memory handler. */ ret = png_malloc_base(NULL/*use malloc*/, size); if (ret == NULL) png_error(png_ptr, "Out of Memory"); /* 'M' means png_malloc_default */ return ret; } #endif /* USER_MEM */ /* This function was added at libpng version 1.2.3. The png_malloc_warn() * function will issue a png_warning and return NULL instead of issuing a * png_error, if it fails to allocate the requested memory. */ PNG_FUNCTION(png_voidp,PNGAPI png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size), PNG_ALLOCATED) { if (png_ptr != NULL) { png_voidp ret = png_malloc_base(png_ptr, size); if (ret != NULL) return ret; png_warning(png_ptr, "Out of memory"); } return NULL; } /* Free a pointer allocated by png_malloc(). If ptr is NULL, return * without taking any action. */ void PNGAPI png_free(png_const_structrp png_ptr, png_voidp ptr) { if (png_ptr == NULL || ptr == NULL) return; #ifdef PNG_USER_MEM_SUPPORTED if (png_ptr->free_fn != NULL) png_ptr->free_fn(png_constcast(png_structrp,png_ptr), ptr); else png_free_default(png_ptr, ptr); } PNG_FUNCTION(void,PNGAPI png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED) { if (png_ptr == NULL || ptr == NULL) return; #endif /* USER_MEM */ free(ptr); } #ifdef PNG_USER_MEM_SUPPORTED /* This function is called when the application wants to use another method * of allocating and freeing memory. */ void PNGAPI png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn) { if (png_ptr != NULL) { png_ptr->mem_ptr = mem_ptr; png_ptr->malloc_fn = malloc_fn; png_ptr->free_fn = free_fn; } } /* This function returns a pointer to the mem_ptr associated with the user * functions. The application should free any memory associated with this * pointer before png_write_destroy and png_read_destroy are called. */ png_voidp PNGAPI png_get_mem_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return NULL; return png_ptr->mem_ptr; } #endif /* USER_MEM */ #endif /* READ || WRITE */ stella-5.1.1/src/libpng/pngpread.c000066400000000000000000000761331324334165500170300ustar00rootroot00000000000000 /* pngpread.c - read a png file in push mode * * Last changed in libpng 1.6.32 [August 24, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ #include "pngpriv.h" #ifdef PNG_PROGRESSIVE_READ_SUPPORTED /* Push model modes */ #define PNG_READ_SIG_MODE 0 #define PNG_READ_CHUNK_MODE 1 #define PNG_READ_IDAT_MODE 2 #define PNG_READ_tEXt_MODE 4 #define PNG_READ_zTXt_MODE 5 #define PNG_READ_DONE_MODE 6 #define PNG_READ_iTXt_MODE 7 #define PNG_ERROR_MODE 8 #define PNG_PUSH_SAVE_BUFFER_IF_FULL \ if (png_ptr->push_length + 4 > png_ptr->buffer_size) \ { png_push_save_buffer(png_ptr); return; } #define PNG_PUSH_SAVE_BUFFER_IF_LT(N) \ if (png_ptr->buffer_size < N) \ { png_push_save_buffer(png_ptr); return; } void PNGAPI png_process_data(png_structrp png_ptr, png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size) { if (png_ptr == NULL || info_ptr == NULL) return; png_push_restore_buffer(png_ptr, buffer, buffer_size); while (png_ptr->buffer_size) { png_process_some_data(png_ptr, info_ptr); } } png_size_t PNGAPI png_process_data_pause(png_structrp png_ptr, int save) { if (png_ptr != NULL) { /* It's easiest for the caller if we do the save; then the caller doesn't * have to supply the same data again: */ if (save != 0) png_push_save_buffer(png_ptr); else { /* This includes any pending saved bytes: */ png_size_t remaining = png_ptr->buffer_size; png_ptr->buffer_size = 0; /* So subtract the saved buffer size, unless all the data * is actually 'saved', in which case we just return 0 */ if (png_ptr->save_buffer_size < remaining) return remaining - png_ptr->save_buffer_size; } } return 0; } png_uint_32 PNGAPI png_process_data_skip(png_structrp png_ptr) { /* TODO: Deprecate and remove this API. * Somewhere the implementation of this seems to have been lost, * or abandoned. It was only to support some internal back-door access * to png_struct) in libpng-1.4.x. */ png_app_warning(png_ptr, "png_process_data_skip is not implemented in any current version of libpng"); return 0; } /* What we do with the incoming data depends on what we were previously * doing before we ran out of data... */ void /* PRIVATE */ png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) { if (png_ptr == NULL) return; switch (png_ptr->process_mode) { case PNG_READ_SIG_MODE: { png_push_read_sig(png_ptr, info_ptr); break; } case PNG_READ_CHUNK_MODE: { png_push_read_chunk(png_ptr, info_ptr); break; } case PNG_READ_IDAT_MODE: { png_push_read_IDAT(png_ptr); break; } default: { png_ptr->buffer_size = 0; break; } } } /* Read any remaining signature bytes from the stream and compare them with * the correct PNG signature. It is possible that this routine is called * with bytes already read from the signature, either because they have been * checked by the calling application, or because of multiple calls to this * routine. */ void /* PRIVATE */ png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) { png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */ num_to_check = 8 - num_checked; if (png_ptr->buffer_size < num_to_check) { num_to_check = png_ptr->buffer_size; } png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) { if (num_checked < 4 && png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) png_error(png_ptr, "Not a PNG file"); else png_error(png_ptr, "PNG file corrupted by ASCII conversion"); } else { if (png_ptr->sig_bytes >= 8) { png_ptr->process_mode = PNG_READ_CHUNK_MODE; } } } void /* PRIVATE */ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) { png_uint_32 chunk_name; #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED int keep; /* unknown handling method */ #endif /* First we make sure we have enough data for the 4-byte chunk name * and the 4-byte chunk length before proceeding with decoding the * chunk data. To fully decode each of these chunks, we also make * sure we have enough data in the buffer for the 4-byte CRC at the * end of every chunk (except IDAT, which is handled separately). */ if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) { png_byte chunk_length[4]; png_byte chunk_tag[4]; PNG_PUSH_SAVE_BUFFER_IF_LT(8) png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, chunk_tag, 4); png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); png_check_chunk_name(png_ptr, png_ptr->chunk_name); png_check_chunk_length(png_ptr, png_ptr->push_length); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; } chunk_name = png_ptr->chunk_name; if (chunk_name == png_IDAT) { if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; /* If we reach an IDAT chunk, this means we have read all of the * header chunks, and we can start reading the image (or if this * is called after the image has been read - we have an error). */ if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && (png_ptr->mode & PNG_HAVE_PLTE) == 0) png_error(png_ptr, "Missing PLTE before IDAT"); png_ptr->process_mode = PNG_READ_IDAT_MODE; if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0) if (png_ptr->push_length == 0) return; png_ptr->mode |= PNG_HAVE_IDAT; if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) png_benign_error(png_ptr, "Too many IDATs found"); } if (chunk_name == png_IHDR) { if (png_ptr->push_length != 13) png_error(png_ptr, "Invalid IHDR length"); PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IEND) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); png_ptr->process_mode = PNG_READ_DONE_MODE; png_push_have_end(png_ptr, info_ptr); } #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; } #endif else if (chunk_name == png_PLTE) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IDAT) { png_ptr->idat_size = png_ptr->push_length; png_ptr->process_mode = PNG_READ_IDAT_MODE; png_push_have_info(png_ptr, info_ptr); png_ptr->zstream.avail_out = (uInt) PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1; png_ptr->zstream.next_out = png_ptr->row_buf; return; } #ifdef PNG_READ_gAMA_SUPPORTED else if (png_ptr->chunk_name == png_gAMA) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sBIT_SUPPORTED else if (png_ptr->chunk_name == png_sBIT) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_cHRM_SUPPORTED else if (png_ptr->chunk_name == png_cHRM) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sRGB_SUPPORTED else if (chunk_name == png_sRGB) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iCCP_SUPPORTED else if (png_ptr->chunk_name == png_iCCP) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sPLT_SUPPORTED else if (chunk_name == png_sPLT) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tRNS_SUPPORTED else if (chunk_name == png_tRNS) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_bKGD_SUPPORTED else if (chunk_name == png_bKGD) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_hIST_SUPPORTED else if (chunk_name == png_hIST) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pHYs_SUPPORTED else if (chunk_name == png_pHYs) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_oFFs_SUPPORTED else if (chunk_name == png_oFFs) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_pCAL_SUPPORTED else if (chunk_name == png_pCAL) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_sCAL_SUPPORTED else if (chunk_name == png_sCAL) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tIME_SUPPORTED else if (chunk_name == png_tIME) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_tEXt_SUPPORTED else if (chunk_name == png_tEXt) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_zTXt_SUPPORTED else if (chunk_name == png_zTXt) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif #ifdef PNG_READ_iTXt_SUPPORTED else if (chunk_name == png_iTXt) { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); } #endif else { PNG_PUSH_SAVE_BUFFER_IF_FULL png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, PNG_HANDLE_CHUNK_AS_DEFAULT); } png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; } void PNGCBAPI png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) { png_bytep ptr; if (png_ptr == NULL) return; ptr = buffer; if (png_ptr->save_buffer_size != 0) { png_size_t save_size; if (length < png_ptr->save_buffer_size) save_size = length; else save_size = png_ptr->save_buffer_size; memcpy(ptr, png_ptr->save_buffer_ptr, save_size); length -= save_size; ptr += save_size; png_ptr->buffer_size -= save_size; png_ptr->save_buffer_size -= save_size; png_ptr->save_buffer_ptr += save_size; } if (length != 0 && png_ptr->current_buffer_size != 0) { png_size_t save_size; if (length < png_ptr->current_buffer_size) save_size = length; else save_size = png_ptr->current_buffer_size; memcpy(ptr, png_ptr->current_buffer_ptr, save_size); png_ptr->buffer_size -= save_size; png_ptr->current_buffer_size -= save_size; png_ptr->current_buffer_ptr += save_size; } } void /* PRIVATE */ png_push_save_buffer(png_structrp png_ptr) { if (png_ptr->save_buffer_size != 0) { if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) { png_size_t i, istop; png_bytep sp; png_bytep dp; istop = png_ptr->save_buffer_size; for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer; i < istop; i++, sp++, dp++) { *dp = *sp; } } } if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > png_ptr->save_buffer_max) { png_size_t new_max; png_bytep old_buffer; if (png_ptr->save_buffer_size > PNG_SIZE_MAX - (png_ptr->current_buffer_size + 256)) { png_error(png_ptr, "Potential overflow of save_buffer"); } new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; old_buffer = png_ptr->save_buffer; png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, (png_size_t)new_max); if (png_ptr->save_buffer == NULL) { png_free(png_ptr, old_buffer); png_error(png_ptr, "Insufficient memory for save_buffer"); } if (old_buffer) memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); else if (png_ptr->save_buffer_size) png_error(png_ptr, "save_buffer error"); png_free(png_ptr, old_buffer); png_ptr->save_buffer_max = new_max; } if (png_ptr->current_buffer_size) { memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size, png_ptr->current_buffer_ptr, png_ptr->current_buffer_size); png_ptr->save_buffer_size += png_ptr->current_buffer_size; png_ptr->current_buffer_size = 0; } png_ptr->save_buffer_ptr = png_ptr->save_buffer; png_ptr->buffer_size = 0; } void /* PRIVATE */ png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length) { png_ptr->current_buffer = buffer; png_ptr->current_buffer_size = buffer_length; png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size; png_ptr->current_buffer_ptr = png_ptr->current_buffer; } void /* PRIVATE */ png_push_read_IDAT(png_structrp png_ptr) { if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) { png_byte chunk_length[4]; png_byte chunk_tag[4]; /* TODO: this code can be commoned up with the same code in push_read */ PNG_PUSH_SAVE_BUFFER_IF_LT(8) png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); png_crc_read(png_ptr, chunk_tag, 4); png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; if (png_ptr->chunk_name != png_IDAT) { png_ptr->process_mode = PNG_READ_CHUNK_MODE; if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) png_error(png_ptr, "Not enough compressed data"); return; } png_ptr->idat_size = png_ptr->push_length; } if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0) { png_size_t save_size = png_ptr->save_buffer_size; png_uint_32 idat_size = png_ptr->idat_size; /* We want the smaller of 'idat_size' and 'current_buffer_size', but they * are of different types and we don't know which variable has the fewest * bits. Carefully select the smaller and cast it to the type of the * larger - this cannot overflow. Do not cast in the following test - it * will break on either 16-bit or 64-bit platforms. */ if (idat_size < save_size) save_size = (png_size_t)idat_size; else idat_size = (png_uint_32)save_size; png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size); png_ptr->idat_size -= idat_size; png_ptr->buffer_size -= save_size; png_ptr->save_buffer_size -= save_size; png_ptr->save_buffer_ptr += save_size; } if (png_ptr->idat_size != 0 && png_ptr->current_buffer_size != 0) { png_size_t save_size = png_ptr->current_buffer_size; png_uint_32 idat_size = png_ptr->idat_size; /* We want the smaller of 'idat_size' and 'current_buffer_size', but they * are of different types and we don't know which variable has the fewest * bits. Carefully select the smaller and cast it to the type of the * larger - this cannot overflow. */ if (idat_size < save_size) save_size = (png_size_t)idat_size; else idat_size = (png_uint_32)save_size; png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size); png_ptr->idat_size -= idat_size; png_ptr->buffer_size -= save_size; png_ptr->current_buffer_size -= save_size; png_ptr->current_buffer_ptr += save_size; } if (png_ptr->idat_size == 0) { PNG_PUSH_SAVE_BUFFER_IF_LT(4) png_crc_finish(png_ptr, 0); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->zowner = 0; } } void /* PRIVATE */ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length) { /* The caller checks for a non-zero buffer length. */ if (!(buffer_length > 0) || buffer == NULL) png_error(png_ptr, "No IDAT data (internal error)"); /* This routine must process all the data it has been given * before returning, calling the row callback as required to * handle the uncompressed results. */ png_ptr->zstream.next_in = buffer; /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ png_ptr->zstream.avail_in = (uInt)buffer_length; /* Keep going until the decompressed data is all processed * or the stream marked as finished. */ while (png_ptr->zstream.avail_in > 0 && (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) { int ret; /* We have data for zlib, but we must check that zlib * has someplace to put the results. It doesn't matter * if we don't expect any results -- it may be the input * data is just the LZ end code. */ if (!(png_ptr->zstream.avail_out > 0)) { /* TODO: WARNING: TRUNCATION ERROR: DANGER WILL ROBINSON: */ png_ptr->zstream.avail_out = (uInt)(PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); png_ptr->zstream.next_out = png_ptr->row_buf; } /* Using Z_SYNC_FLUSH here means that an unterminated * LZ stream (a stream with a missing end code) can still * be handled, otherwise (Z_NO_FLUSH) a future zlib * implementation might defer output and therefore * change the current behavior (see comments in inflate.c * for why this doesn't happen at present with zlib 1.2.5). */ ret = PNG_INFLATE(png_ptr, Z_SYNC_FLUSH); /* Check for any failure before proceeding. */ if (ret != Z_OK && ret != Z_STREAM_END) { /* Terminate the decompression. */ png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; png_ptr->zowner = 0; /* This may be a truncated stream (missing or * damaged end code). Treat that as a warning. */ if (png_ptr->row_number >= png_ptr->num_rows || png_ptr->pass > 6) png_warning(png_ptr, "Truncated compressed data in IDAT"); else { if (ret == Z_DATA_ERROR) png_benign_error(png_ptr, "IDAT: ADLER32 checksum mismatch"); else png_error(png_ptr, "Decompression error in IDAT"); } /* Skip the check on unprocessed input */ return; } /* Did inflate output any data? */ if (png_ptr->zstream.next_out != png_ptr->row_buf) { /* Is this unexpected data after the last row? * If it is, artificially terminate the LZ output * here. */ if (png_ptr->row_number >= png_ptr->num_rows || png_ptr->pass > 6) { /* Extra data. */ png_warning(png_ptr, "Extra compressed data in IDAT"); png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; png_ptr->zowner = 0; /* Do no more processing; skip the unprocessed * input check below. */ return; } /* Do we have a complete row? */ if (png_ptr->zstream.avail_out == 0) png_push_process_row(png_ptr); } /* And check for the end of the stream. */ if (ret == Z_STREAM_END) png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; } /* All the data should have been processed, if anything * is left at this point we have bytes of IDAT data * after the zlib end code. */ if (png_ptr->zstream.avail_in > 0) png_warning(png_ptr, "Extra compression data in IDAT"); } void /* PRIVATE */ png_push_process_row(png_structrp png_ptr) { /* 1.5.6: row_info moved out of png_struct to a local here. */ png_row_info row_info; row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ row_info.color_type = png_ptr->color_type; row_info.bit_depth = png_ptr->bit_depth; row_info.channels = png_ptr->channels; row_info.pixel_depth = png_ptr->pixel_depth; row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) { if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, png_ptr->prev_row + 1, png_ptr->row_buf[0]); else png_error(png_ptr, "bad adaptive filter value"); } /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before * 1.5.6, while the buffer really is this big in current versions of libpng * it may not be in the future, so this was changed just to copy the * interlaced row count: */ memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); #ifdef PNG_READ_TRANSFORMS_SUPPORTED if (png_ptr->transformations != 0) png_do_read_transformations(png_ptr, &row_info); #endif /* The transformed pixel depth should match the depth now in row_info. */ if (png_ptr->transformed_pixel_depth == 0) { png_ptr->transformed_pixel_depth = row_info.pixel_depth; if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) png_error(png_ptr, "progressive row overflow"); } else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) png_error(png_ptr, "internal progressive row size calculation error"); #ifdef PNG_READ_INTERLACING_SUPPORTED /* Expand interlaced rows to full size */ if (png_ptr->interlaced != 0 && (png_ptr->transformations & PNG_INTERLACE) != 0) { if (png_ptr->pass < 6) png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); switch (png_ptr->pass) { case 0: { int i; for (i = 0; i < 8 && png_ptr->pass == 0; i++) { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); /* Updates png_ptr->pass */ } if (png_ptr->pass == 2) /* Pass 1 might be empty */ { for (i = 0; i < 4 && png_ptr->pass == 2; i++) { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } } if (png_ptr->pass == 4 && png_ptr->height <= 4) { for (i = 0; i < 2 && png_ptr->pass == 4; i++) { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } } if (png_ptr->pass == 6 && png_ptr->height <= 4) { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } break; } case 1: { int i; for (i = 0; i < 8 && png_ptr->pass == 1; i++) { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); } if (png_ptr->pass == 2) /* Skip top 4 generated rows */ { for (i = 0; i < 4 && png_ptr->pass == 2; i++) { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } } break; } case 2: { int i; for (i = 0; i < 4 && png_ptr->pass == 2; i++) { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); } for (i = 0; i < 4 && png_ptr->pass == 2; i++) { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } if (png_ptr->pass == 4) /* Pass 3 might be empty */ { for (i = 0; i < 2 && png_ptr->pass == 4; i++) { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } } break; } case 3: { int i; for (i = 0; i < 4 && png_ptr->pass == 3; i++) { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); } if (png_ptr->pass == 4) /* Skip top two generated rows */ { for (i = 0; i < 2 && png_ptr->pass == 4; i++) { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } } break; } case 4: { int i; for (i = 0; i < 2 && png_ptr->pass == 4; i++) { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); } for (i = 0; i < 2 && png_ptr->pass == 4; i++) { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } if (png_ptr->pass == 6) /* Pass 5 might be empty */ { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } break; } case 5: { int i; for (i = 0; i < 2 && png_ptr->pass == 5; i++) { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); } if (png_ptr->pass == 6) /* Skip top generated row */ { png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } break; } default: case 6: { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); if (png_ptr->pass != 6) break; png_push_have_row(png_ptr, NULL); png_read_push_finish_row(png_ptr); } } } else #endif { png_push_have_row(png_ptr, png_ptr->row_buf + 1); png_read_push_finish_row(png_ptr); } } void /* PRIVATE */ png_read_push_finish_row(png_structrp png_ptr) { #ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; /* Height of interlace block. This is not currently used - if you need * it, uncomment it here and in png.h static PNG_CONST png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; */ #endif png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; #ifdef PNG_READ_INTERLACING_SUPPORTED if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); do { png_ptr->pass++; if ((png_ptr->pass == 1 && png_ptr->width < 5) || (png_ptr->pass == 3 && png_ptr->width < 3) || (png_ptr->pass == 5 && png_ptr->width < 2)) png_ptr->pass++; if (png_ptr->pass > 7) png_ptr->pass--; if (png_ptr->pass >= 7) break; png_ptr->iwidth = (png_ptr->width + png_pass_inc[png_ptr->pass] - 1 - png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; if ((png_ptr->transformations & PNG_INTERLACE) != 0) break; png_ptr->num_rows = (png_ptr->height + png_pass_yinc[png_ptr->pass] - 1 - png_pass_ystart[png_ptr->pass]) / png_pass_yinc[png_ptr->pass]; } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); } #endif /* READ_INTERLACING */ } void /* PRIVATE */ png_push_have_info(png_structrp png_ptr, png_inforp info_ptr) { if (png_ptr->info_fn != NULL) (*(png_ptr->info_fn))(png_ptr, info_ptr); } void /* PRIVATE */ png_push_have_end(png_structrp png_ptr, png_inforp info_ptr) { if (png_ptr->end_fn != NULL) (*(png_ptr->end_fn))(png_ptr, info_ptr); } void /* PRIVATE */ png_push_have_row(png_structrp png_ptr, png_bytep row) { if (png_ptr->row_fn != NULL) (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, (int)png_ptr->pass); } #ifdef PNG_READ_INTERLACING_SUPPORTED void PNGAPI png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, png_const_bytep new_row) { if (png_ptr == NULL) return; /* new_row is a flag here - if it is NULL then the app callback was called * from an empty row (see the calls to png_struct::row_fn below), otherwise * it must be png_ptr->row_buf+1 */ if (new_row != NULL) png_combine_row(png_ptr, old_row, 1/*blocky display*/); } #endif /* READ_INTERLACING */ void PNGAPI png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn) { if (png_ptr == NULL) return; png_ptr->info_fn = info_fn; png_ptr->row_fn = row_fn; png_ptr->end_fn = end_fn; png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer); } png_voidp PNGAPI png_get_progressive_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); return png_ptr->io_ptr; } #endif /* PROGRESSIVE_READ */ stella-5.1.1/src/libpng/pngpriv.h000066400000000000000000002553301324334165500167200ustar00rootroot00000000000000 /* pngpriv.h - private declarations for use inside libpng * * Last changed in libpng 1.6.32 [August 24, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ /* The symbols declared in this file (including the functions declared * as extern) are PRIVATE. They are not part of the libpng public * interface, and are not recommended for use by regular applications. * Some of them may become public in the future; others may stay private, * change in an incompatible way, or even disappear. * Although the libpng users are not forbidden to include this header, * they should be well aware of the issues that may arise from doing so. */ #ifndef PNGPRIV_H #define PNGPRIV_H /* Feature Test Macros. The following are defined here to ensure that correctly * implemented libraries reveal the APIs libpng needs to build and hide those * that are not needed and potentially damaging to the compilation. * * Feature Test Macros must be defined before any system header is included (see * POSIX 1003.1 2.8.2 "POSIX Symbols." * * These macros only have an effect if the operating system supports either * POSIX 1003.1 or C99, or both. On other operating systems (particularly * Windows/Visual Studio) there is no effect; the OS specific tests below are * still required (as of 2011-05-02.) */ #ifndef _POSIX_SOURCE # define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ #endif #ifndef PNG_VERSION_INFO_ONLY /* Standard library headers not required by png.h: */ # include # include #endif #define PNGLIB_BUILD /*libpng is being built, not used*/ /* If HAVE_CONFIG_H is defined during the build then the build system must * provide an appropriate "config.h" file on the include path. The header file * must provide definitions as required below (search for "HAVE_CONFIG_H"); * see configure.ac for more details of the requirements. The macro * "PNG_NO_CONFIG_H" is provided for maintainers to test for dependencies on * 'configure'; define this macro to prevent the configure build including the * configure generated config.h. Libpng is expected to compile without *any* * special build system support on a reasonably ANSI-C compliant system. */ #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) # include /* Pick up the definition of 'restrict' from config.h if it was read: */ # define PNG_RESTRICT restrict #endif /* To support symbol prefixing it is necessary to know *before* including png.h * whether the fixed point (and maybe other) APIs are exported, because if they * are not internal definitions may be required. This is handled below just * before png.h is included, but load the configuration now if it is available. */ #ifndef PNGLCONF_H # include "pnglibconf.h" #endif /* Local renames may change non-exported API functions from png.h */ #if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) # include "pngprefix.h" #endif #ifdef PNG_USER_CONFIG # include "pngusr.h" /* These should have been defined in pngusr.h */ # ifndef PNG_USER_PRIVATEBUILD # define PNG_USER_PRIVATEBUILD "Custom libpng build" # endif # ifndef PNG_USER_DLLFNAME_POSTFIX # define PNG_USER_DLLFNAME_POSTFIX "Cb" # endif #endif /* Compile time options. * ===================== * In a multi-arch build the compiler may compile the code several times for the * same object module, producing different binaries for different architectures. * When this happens configure-time setting of the target host options cannot be * done and this interferes with the handling of the ARM NEON optimizations, and * possibly other similar optimizations. Put additional tests here; in general * this is needed when the same option can be changed at both compile time and * run time depending on the target OS (i.e. iOS vs Android.) * * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because * this is not possible with certain compilers (Oracle SUN OS CC), as a result * it is necessary to ensure that all extern functions that *might* be used * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__ * below is one example of this behavior because it is controlled by the * presence or not of -mfpu=neon on the GCC command line, it is possible to do * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely * do this. */ #ifndef PNG_ARM_NEON_OPT /* ARM NEON optimizations are being controlled by the compiler settings, * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon * with GCC) then the compiler will define __ARM_NEON__ and we can rely * unconditionally on NEON instructions not crashing, otherwise we must * disable use of NEON instructions. * * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they * can only be turned on automatically if that is supported too. If * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail * to compile with an appropriate #error if ALIGNED_MEMORY has been turned * off. * * Note that gcc-4.9 defines __ARM_NEON instead of the deprecated * __ARM_NEON__, so we check both variants. * * To disable ARM_NEON optimizations entirely, and skip compiling the * associated assembler code, pass --enable-arm-neon=no to configure * or put -DPNG_ARM_NEON_OPT=0 in CPPFLAGS. */ # if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \ defined(PNG_ALIGNED_MEMORY_SUPPORTED) # define PNG_ARM_NEON_OPT 2 # else # define PNG_ARM_NEON_OPT 0 # endif #endif #if PNG_ARM_NEON_OPT > 0 /* NEON optimizations are to be at least considered by libpng, so enable the * callbacks to do this. */ # define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon /* By default the 'intrinsics' code in arm/filter_neon_intrinsics.c is used * if possible - if __ARM_NEON__ is set and the compiler version is not known * to be broken. This is controlled by PNG_ARM_NEON_IMPLEMENTATION which can * be: * * 1 The intrinsics code (the default with __ARM_NEON__) * 2 The hand coded assembler (the default without __ARM_NEON__) * * It is possible to set PNG_ARM_NEON_IMPLEMENTATION in CPPFLAGS, however * this is *NOT* supported and may cease to work even after a minor revision * to libpng. It *is* valid to do this for testing purposes, e.g. speed * testing or a new compiler, but the results should be communicated to the * libpng implementation list for incorporation in the next minor release. */ # ifndef PNG_ARM_NEON_IMPLEMENTATION # if defined(__ARM_NEON__) || defined(__ARM_NEON) # if defined(__clang__) /* At present it is unknown by the libpng developers which versions * of clang support the intrinsics, however some or perhaps all * versions do not work with the assembler so this may be * irrelevant, so just use the default (do nothing here.) */ # elif defined(__GNUC__) /* GCC 4.5.4 NEON support is known to be broken. 4.6.3 is known to * work, so if this *is* GCC, or G++, look for a version >4.5 */ # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) # define PNG_ARM_NEON_IMPLEMENTATION 2 # endif /* no GNUC support */ # endif /* __GNUC__ */ # else /* !defined __ARM_NEON__ */ /* The 'intrinsics' code simply won't compile without this -mfpu=neon: */ # define PNG_ARM_NEON_IMPLEMENTATION 2 # endif /* __ARM_NEON__ */ # endif /* !PNG_ARM_NEON_IMPLEMENTATION */ # ifndef PNG_ARM_NEON_IMPLEMENTATION /* Use the intrinsics code by default. */ # define PNG_ARM_NEON_IMPLEMENTATION 1 # endif #endif /* PNG_ARM_NEON_OPT > 0 */ #ifndef PNG_MIPS_MSA_OPT # if defined(__mips_msa) && (__mips_isa_rev >= 5) && defined(PNG_ALIGNED_MEMORY_SUPPORTED) # define PNG_MIPS_MSA_OPT 2 # else # define PNG_MIPS_MSA_OPT 0 # endif #endif #ifndef PNG_POWERPC_VSX_OPT # if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__) # define PNG_POWERPC_VSX_OPT 2 # else # define PNG_POWERPC_VSX_OPT 0 # endif #endif #ifndef PNG_INTEL_SSE_OPT # ifdef PNG_INTEL_SSE /* Only check for SSE if the build configuration has been modified to * enable SSE optimizations. This means that these optimizations will * be off by default. See contrib/intel for more details. */ # if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \ defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \ (defined(_M_IX86_FP) && _M_IX86_FP >= 2) # define PNG_INTEL_SSE_OPT 1 # endif # endif #endif #if PNG_INTEL_SSE_OPT > 0 # ifndef PNG_INTEL_SSE_IMPLEMENTATION # if defined(__SSE4_1__) || defined(__AVX__) /* We are not actually using AVX, but checking for AVX is the best way we can detect SSE4.1 and SSSE3 on MSVC. */ # define PNG_INTEL_SSE_IMPLEMENTATION 3 # elif defined(__SSSE3__) # define PNG_INTEL_SSE_IMPLEMENTATION 2 # elif defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \ (defined(_M_IX86_FP) && _M_IX86_FP >= 2) # define PNG_INTEL_SSE_IMPLEMENTATION 1 # else # define PNG_INTEL_SSE_IMPLEMENTATION 0 # endif # endif # if PNG_INTEL_SSE_IMPLEMENTATION > 0 # define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_sse2 # endif #endif #if PNG_MIPS_MSA_OPT > 0 # define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_msa # ifndef PNG_MIPS_MSA_IMPLEMENTATION # if defined(__mips_msa) # if defined(__clang__) # elif defined(__GNUC__) # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) # define PNG_MIPS_MSA_IMPLEMENTATION 2 # endif /* no GNUC support */ # endif /* __GNUC__ */ # else /* !defined __mips_msa */ # define PNG_MIPS_MSA_IMPLEMENTATION 2 # endif /* __mips_msa */ # endif /* !PNG_MIPS_MSA_IMPLEMENTATION */ # ifndef PNG_MIPS_MSA_IMPLEMENTATION # define PNG_MIPS_MSA_IMPLEMENTATION 1 # endif #endif /* PNG_MIPS_MSA_OPT > 0 */ #if PNG_POWERPC_VSX_OPT > 0 # define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx # define PNG_POWERPC_VSX_IMPLEMENTATION 1 #endif /* Is this a build of a DLL where compilation of the object modules requires * different preprocessor settings to those required for a simple library? If * so PNG_BUILD_DLL must be set. * * If libpng is used inside a DLL but that DLL does not export the libpng APIs * PNG_BUILD_DLL must not be set. To avoid the code below kicking in build a * static library of libpng then link the DLL against that. */ #ifndef PNG_BUILD_DLL # ifdef DLL_EXPORT /* This is set by libtool when files are compiled for a DLL; libtool * always compiles twice, even on systems where it isn't necessary. Set * PNG_BUILD_DLL in case it is necessary: */ # define PNG_BUILD_DLL # else # ifdef _WINDLL /* This is set by the Microsoft Visual Studio IDE in projects that * build a DLL. It can't easily be removed from those projects (it * isn't visible in the Visual Studio UI) so it is a fairly reliable * indication that PNG_IMPEXP needs to be set to the DLL export * attributes. */ # define PNG_BUILD_DLL # else # ifdef __DLL__ /* This is set by the Borland C system when compiling for a DLL * (as above.) */ # define PNG_BUILD_DLL # else /* Add additional compiler cases here. */ # endif # endif # endif #endif /* Setting PNG_BUILD_DLL if required */ /* See pngconf.h for more details: the builder of the library may set this on * the command line to the right thing for the specific compilation system or it * may be automagically set above (at present we know of no system where it does * need to be set on the command line.) * * PNG_IMPEXP must be set here when building the library to prevent pngconf.h * setting it to the "import" setting for a DLL build. */ #ifndef PNG_IMPEXP # ifdef PNG_BUILD_DLL # define PNG_IMPEXP PNG_DLL_EXPORT # else /* Not building a DLL, or the DLL doesn't require specific export * definitions. */ # define PNG_IMPEXP # endif #endif /* No warnings for private or deprecated functions in the build: */ #ifndef PNG_DEPRECATED # define PNG_DEPRECATED #endif #ifndef PNG_PRIVATE # define PNG_PRIVATE #endif /* Symbol preprocessing support. * * To enable listing global, but internal, symbols the following macros should * always be used to declare an extern data or function object in this file. */ #ifndef PNG_INTERNAL_DATA # define PNG_INTERNAL_DATA(type, name, array) PNG_LINKAGE_DATA type name array #endif #ifndef PNG_INTERNAL_FUNCTION # define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ PNG_LINKAGE_FUNCTION PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) #endif #ifndef PNG_INTERNAL_CALLBACK # define PNG_INTERNAL_CALLBACK(type, name, args, attributes)\ PNG_LINKAGE_CALLBACK PNG_FUNCTION(type, (PNGCBAPI name), args,\ PNG_EMPTY attributes) #endif /* If floating or fixed point APIs are disabled they may still be compiled * internally. To handle this make sure they are declared as the appropriate * internal extern function (otherwise the symbol prefixing stuff won't work and * the functions will be used without definitions.) * * NOTE: although all the API functions are declared here they are not all * actually built! Because the declarations are still made it is necessary to * fake out types that they depend on. */ #ifndef PNG_FP_EXPORT # ifndef PNG_FLOATING_POINT_SUPPORTED # define PNG_FP_EXPORT(ordinal, type, name, args)\ PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); # ifndef PNG_VERSION_INFO_ONLY typedef struct png_incomplete png_double; typedef png_double* png_doublep; typedef const png_double* png_const_doublep; typedef png_double** png_doublepp; # endif # endif #endif #ifndef PNG_FIXED_EXPORT # ifndef PNG_FIXED_POINT_SUPPORTED # define PNG_FIXED_EXPORT(ordinal, type, name, args)\ PNG_INTERNAL_FUNCTION(type, name, args, PNG_EMPTY); # endif #endif #include "png.h" /* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */ #ifndef PNG_DLL_EXPORT # define PNG_DLL_EXPORT #endif /* This is a global switch to set the compilation for an installed system * (a release build). It can be set for testing debug builds to ensure that * they will compile when the build type is switched to RC or STABLE, the * default is just to use PNG_LIBPNG_BUILD_BASE_TYPE. Set this in CPPFLAGS * with either: * * -DPNG_RELEASE_BUILD Turns on the release compile path * -DPNG_RELEASE_BUILD=0 Turns it off * or in your pngusr.h with * #define PNG_RELEASE_BUILD=1 Turns on the release compile path * #define PNG_RELEASE_BUILD=0 Turns it off */ #ifndef PNG_RELEASE_BUILD # define PNG_RELEASE_BUILD (PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC) #endif /* SECURITY and SAFETY: * * libpng is built with support for internal limits on image dimensions and * memory usage. These are documented in scripts/pnglibconf.dfa of the * source and recorded in the machine generated header file pnglibconf.h. */ /* If you are running on a machine where you cannot allocate more * than 64K of memory at once, uncomment this. While libpng will not * normally need that much memory in a chunk (unless you load up a very * large file), zlib needs to know how big of a chunk it can use, and * libpng thus makes sure to check any memory allocation to verify it * will fit into memory. * * zlib provides 'MAXSEG_64K' which, if defined, indicates the * same limit and pngconf.h (already included) sets the limit * if certain operating systems are detected. */ #if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) # define PNG_MAX_MALLOC_64K #endif #ifndef PNG_UNUSED /* Unused formal parameter warnings are silenced using the following macro * which is expected to have no bad effects on performance (optimizing * compilers will probably remove it entirely). Note that if you replace * it with something other than whitespace, you must include the terminating * semicolon. */ # define PNG_UNUSED(param) (void)param; #endif /* Just a little check that someone hasn't tried to define something * contradictory. */ #if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K) # undef PNG_ZBUF_SIZE # define PNG_ZBUF_SIZE 65536L #endif /* If warnings or errors are turned off the code is disabled or redirected here. * From 1.5.4 functions have been added to allow very limited formatting of * error and warning messages - this code will also be disabled here. */ #ifdef PNG_WARNINGS_SUPPORTED # define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; #else # define png_warning_parameter(p,number,string) ((void)0) # define png_warning_parameter_unsigned(p,number,format,value) ((void)0) # define png_warning_parameter_signed(p,number,format,value) ((void)0) # define png_formatted_warning(pp,p,message) ((void)(pp)) # define PNG_WARNING_PARAMETERS(p) #endif #ifndef PNG_ERROR_TEXT_SUPPORTED # define png_fixed_error(s1,s2) png_err(s1) #endif /* Some fixed point APIs are still required even if not exported because * they get used by the corresponding floating point APIs. This magic * deals with this: */ #ifdef PNG_FIXED_POINT_SUPPORTED # define PNGFAPI PNGAPI #else # define PNGFAPI /* PRIVATE */ #endif #ifndef PNG_VERSION_INFO_ONLY /* Other defines specific to compilers can go here. Try to keep * them inside an appropriate ifdef/endif pair for portability. */ /* C allows up-casts from (void*) to any pointer and (const void*) to any * pointer to a const object. C++ regards this as a type error and requires an * explicit, static, cast and provides the static_cast<> rune to ensure that * const is not cast away. */ #ifdef __cplusplus # define png_voidcast(type, value) static_cast(value) # define png_constcast(type, value) const_cast(value) # define png_aligncast(type, value) \ static_cast(static_cast(value)) # define png_aligncastconst(type, value) \ static_cast(static_cast(value)) #else # define png_voidcast(type, value) (value) # ifdef _WIN64 # ifdef __GNUC__ typedef unsigned long long png_ptruint; # else typedef unsigned __int64 png_ptruint; # endif # else typedef unsigned long png_ptruint; # endif # define png_constcast(type, value) ((type)(png_ptruint)(const void*)(value)) # define png_aligncast(type, value) ((void*)(value)) # define png_aligncastconst(type, value) ((const void*)(value)) #endif /* __cplusplus */ #if defined(PNG_FLOATING_POINT_SUPPORTED) ||\ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) /* png.c requires the following ANSI-C constants if the conversion of * floating point to ASCII is implemented therein: * * DBL_DIG Maximum number of decimal digits (can be set to any constant) * DBL_MIN Smallest normalized fp number (can be set to an arbitrary value) * DBL_MAX Maximum floating point number (can be set to an arbitrary value) */ # include # if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) /* We need to check that hasn't already been included earlier * as it seems it doesn't agree with , yet we should really use * if possible. */ # if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) # include # endif # else # include # endif # if defined(_AMIGA) && defined(__SASC) && defined(_M68881) /* Amiga SAS/C: We must include builtin FPU functions when compiling using * MATH=68881 */ # include # endif #endif /* This provides the non-ANSI (far) memory allocation routines. */ #if defined(__TURBOC__) && defined(__MSDOS__) # include # include #endif #if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ defined(_WIN32) || defined(__WIN32__) # include /* defines _WINDOWS_ macro */ #endif #endif /* PNG_VERSION_INFO_ONLY */ /* Moved here around 1.5.0beta36 from pngconf.h */ /* Users may want to use these so they are not private. Any library * functions that are passed far data must be model-independent. */ /* Memory model/platform independent fns */ #ifndef PNG_ABORT # ifdef _WINDOWS_ # define PNG_ABORT() ExitProcess(0) # else # define PNG_ABORT() abort() # endif #endif /* These macros may need to be architecture dependent. */ #define PNG_ALIGN_NONE 0 /* do not use data alignment */ #define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ #ifdef offsetof # define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ #else # define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ #endif #define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ #ifndef PNG_ALIGN_TYPE /* Default to using aligned access optimizations and requiring alignment to a * multiple of the data type size. Override in a compiler specific fashion * if necessary by inserting tests here: */ # define PNG_ALIGN_TYPE PNG_ALIGN_SIZE #endif #if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE /* This is used because in some compiler implementations non-aligned * structure members are supported, so the offsetof approach below fails. * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access * is good for performance. Do not do this unless you have tested the result * and understand it. */ # define png_alignof(type) (sizeof (type)) #else # if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET # define png_alignof(type) offsetof(struct{char c; type t;}, t) # else # if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS # define png_alignof(type) (1) # endif /* Else leave png_alignof undefined to prevent use thereof */ # endif #endif /* This implicitly assumes alignment is always to a power of 2. */ #ifdef png_alignof # define png_isaligned(ptr, type)\ (((type)((const char*)ptr-(const char*)0) & \ (type)(png_alignof(type)-1)) == 0) #else # define png_isaligned(ptr, type) 0 #endif /* End of memory model/platform independent support */ /* End of 1.5.0beta36 move from pngconf.h */ /* CONSTANTS and UTILITY MACROS * These are used internally by libpng and not exposed in the API */ /* Various modes of operation. Note that after an init, mode is set to * zero automatically when the structure is created. Three of these * are defined in png.h because they need to be visible to applications * that call png_set_unknown_chunk(). */ /* #define PNG_HAVE_IHDR 0x01U (defined in png.h) */ /* #define PNG_HAVE_PLTE 0x02U (defined in png.h) */ #define PNG_HAVE_IDAT 0x04U /* #define PNG_AFTER_IDAT 0x08U (defined in png.h) */ #define PNG_HAVE_IEND 0x10U /* 0x20U (unused) */ /* 0x40U (unused) */ /* 0x80U (unused) */ #define PNG_HAVE_CHUNK_HEADER 0x100U #define PNG_WROTE_tIME 0x200U #define PNG_WROTE_INFO_BEFORE_PLTE 0x400U #define PNG_BACKGROUND_IS_GRAY 0x800U #define PNG_HAVE_PNG_SIGNATURE 0x1000U #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */ /* 0x4000U (unused) */ #define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */ /* Flags for the transformations the PNG library does on the image data */ #define PNG_BGR 0x0001U #define PNG_INTERLACE 0x0002U #define PNG_PACK 0x0004U #define PNG_SHIFT 0x0008U #define PNG_SWAP_BYTES 0x0010U #define PNG_INVERT_MONO 0x0020U #define PNG_QUANTIZE 0x0040U #define PNG_COMPOSE 0x0080U /* Was PNG_BACKGROUND */ #define PNG_BACKGROUND_EXPAND 0x0100U #define PNG_EXPAND_16 0x0200U /* Added to libpng 1.5.2 */ #define PNG_16_TO_8 0x0400U /* Becomes 'chop' in 1.5.4 */ #define PNG_RGBA 0x0800U #define PNG_EXPAND 0x1000U #define PNG_GAMMA 0x2000U #define PNG_GRAY_TO_RGB 0x4000U #define PNG_FILLER 0x8000U #define PNG_PACKSWAP 0x10000U #define PNG_SWAP_ALPHA 0x20000U #define PNG_STRIP_ALPHA 0x40000U #define PNG_INVERT_ALPHA 0x80000U #define PNG_USER_TRANSFORM 0x100000U #define PNG_RGB_TO_GRAY_ERR 0x200000U #define PNG_RGB_TO_GRAY_WARN 0x400000U #define PNG_RGB_TO_GRAY 0x600000U /* two bits, RGB_TO_GRAY_ERR|WARN */ #define PNG_ENCODE_ALPHA 0x800000U /* Added to libpng-1.5.4 */ #define PNG_ADD_ALPHA 0x1000000U /* Added to libpng-1.2.7 */ #define PNG_EXPAND_tRNS 0x2000000U /* Added to libpng-1.2.9 */ #define PNG_SCALE_16_TO_8 0x4000000U /* Added to libpng-1.5.4 */ /* 0x8000000U unused */ /* 0x10000000U unused */ /* 0x20000000U unused */ /* 0x40000000U unused */ /* Flags for png_create_struct */ #define PNG_STRUCT_PNG 0x0001U #define PNG_STRUCT_INFO 0x0002U /* Flags for the png_ptr->flags rather than declaring a byte for each one */ #define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001U #define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002U /* Added to libpng-1.6.0 */ /* 0x0004U unused */ #define PNG_FLAG_ZSTREAM_ENDED 0x0008U /* Added to libpng-1.6.0 */ /* 0x0010U unused */ /* 0x0020U unused */ #define PNG_FLAG_ROW_INIT 0x0040U #define PNG_FLAG_FILLER_AFTER 0x0080U #define PNG_FLAG_CRC_ANCILLARY_USE 0x0100U #define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200U #define PNG_FLAG_CRC_CRITICAL_USE 0x0400U #define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800U #define PNG_FLAG_ASSUME_sRGB 0x1000U /* Added to libpng-1.5.4 */ #define PNG_FLAG_OPTIMIZE_ALPHA 0x2000U /* Added to libpng-1.5.4 */ #define PNG_FLAG_DETECT_UNINITIALIZED 0x4000U /* Added to libpng-1.5.4 */ /* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000U */ /* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000U */ #define PNG_FLAG_LIBRARY_MISMATCH 0x20000U #define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000U #define PNG_FLAG_STRIP_ERROR_TEXT 0x80000U #define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000U /* Added to libpng-1.4.0 */ #define PNG_FLAG_APP_WARNINGS_WARN 0x200000U /* Added to libpng-1.6.0 */ #define PNG_FLAG_APP_ERRORS_WARN 0x400000U /* Added to libpng-1.6.0 */ /* 0x800000U unused */ /* 0x1000000U unused */ /* 0x2000000U unused */ /* 0x4000000U unused */ /* 0x8000000U unused */ /* 0x10000000U unused */ /* 0x20000000U unused */ /* 0x40000000U unused */ #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ PNG_FLAG_CRC_ANCILLARY_NOWARN) #define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ PNG_FLAG_CRC_CRITICAL_IGNORE) #define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ PNG_FLAG_CRC_CRITICAL_MASK) /* Save typing and make code easier to understand */ #define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ abs((int)((c1).green) - (int)((c2).green)) + \ abs((int)((c1).blue) - (int)((c2).blue))) /* Added to libpng-1.6.0: scale a 16-bit value in the range 0..65535 to 0..255 * by dividing by 257 *with rounding*. This macro is exact for the given range. * See the discourse in pngrtran.c png_do_scale_16_to_8. The values in the * macro were established by experiment (modifying the added value). The macro * has a second variant that takes a value already scaled by 255 and divides by * 65535 - this has a maximum error of .502. Over the range 0..65535*65535 it * only gives off-by-one errors and only for 0.5% (1 in 200) of the values. */ #define PNG_DIV65535(v24) (((v24) + 32895) >> 16) #define PNG_DIV257(v16) PNG_DIV65535((png_uint_32)(v16) * 255) /* Added to libpng-1.2.6 JB */ #define PNG_ROWBYTES(pixel_bits, width) \ ((pixel_bits) >= 8 ? \ ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) /* This returns the number of trailing bits in the last byte of a row, 0 if the * last byte is completely full of pixels. It is, in principle, (pixel_bits x * width) % 8, but that would overflow for large 'width'. The second macro is * the same except that it returns the number of unused bits in the last byte; * (8-TRAILBITS), but 0 when TRAILBITS is 0. * * NOTE: these macros are intended to be self-evidently correct and never * overflow on the assumption that pixel_bits is in the range 0..255. The * arguments are evaluated only once and they can be signed (e.g. as a result of * the integral promotions). The result of the expression always has type * (png_uint_32), however the compiler always knows it is in the range 0..7. */ #define PNG_TRAILBITS(pixel_bits, width) \ (((pixel_bits) * ((width) % (png_uint_32)8)) % 8) #define PNG_PADBITS(pixel_bits, width) \ ((8 - PNG_TRAILBITS(pixel_bits, width)) % 8) /* PNG_OUT_OF_RANGE returns true if value is outside the range * ideal-delta..ideal+delta. Each argument is evaluated twice. * "ideal" and "delta" should be constants, normally simple * integers, "value" a variable. Added to libpng-1.2.6 JB */ #define PNG_OUT_OF_RANGE(value, ideal, delta) \ ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) /* Conversions between fixed and floating point, only defined if * required (to make sure the code doesn't accidentally use float * when it is supposedly disabled.) */ #ifdef PNG_FLOATING_POINT_SUPPORTED /* The floating point conversion can't overflow, though it can and * does lose accuracy relative to the original fixed point value. * In practice this doesn't matter because png_fixed_point only * stores numbers with very low precision. The png_ptr and s * arguments are unused by default but are there in case error * checking becomes a requirement. */ #define png_float(png_ptr, fixed, s) (.00001 * (fixed)) /* The fixed point conversion performs range checking and evaluates * its argument multiple times, so must be used with care. The * range checking uses the PNG specification values for a signed * 32-bit fixed point value except that the values are deliberately * rounded-to-zero to an integral value - 21474 (21474.83 is roughly * (2^31-1) * 100000). 's' is a string that describes the value being * converted. * * NOTE: this macro will raise a png_error if the range check fails, * therefore it is normally only appropriate to use this on values * that come from API calls or other sources where an out of range * error indicates a programming error, not a data error! * * NOTE: by default this is off - the macro is not used - because the * function call saves a lot of code. */ #ifdef PNG_FIXED_POINT_MACRO_SUPPORTED #define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) #endif /* else the corresponding function is defined below, inside the scope of the * cplusplus test. */ #endif /* Constants for known chunk types. If you need to add a chunk, define the name * here. For historical reasons these constants have the form png_; i.e. * the prefix is lower case. Please use decimal values as the parameters to * match the ISO PNG specification and to avoid relying on the C locale * interpretation of character values. * * Prior to 1.5.6 these constants were strings, as of 1.5.6 png_uint_32 values * are computed and a new macro (PNG_STRING_FROM_CHUNK) added to allow a string * to be generated if required. * * PNG_32b correctly produces a value shifted by up to 24 bits, even on * architectures where (int) is only 16 bits. */ #define PNG_32b(b,s) ((png_uint_32)(b) << (s)) #define PNG_U32(b1,b2,b3,b4) \ (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) /* Constants for known chunk types. * * MAINTAINERS: If you need to add a chunk, define the name here. * For historical reasons these constants have the form png_; i.e. * the prefix is lower case. Please use decimal values as the parameters to * match the ISO PNG specification and to avoid relying on the C locale * interpretation of character values. Please keep the list sorted. * * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk * type. In fact the specification does not express chunk types this way, * however using a 32-bit value means that the chunk type can be read from the * stream using exactly the same code as used for a 32-bit unsigned value and * can be examined far more efficiently (using one arithmetic compare). * * Prior to 1.5.6 the chunk type constants were expressed as C strings. The * libpng API still uses strings for 'unknown' chunks and a macro, * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice * that for portable code numeric values must still be used; the string "IHDR" * is not portable and neither is PNG_U32('I', 'H', 'D', 'R'). * * In 1.7.0 the definitions will be made public in png.h to avoid having to * duplicate the same definitions in application code. */ #define png_IDAT PNG_U32( 73, 68, 65, 84) #define png_IEND PNG_U32( 73, 69, 78, 68) #define png_IHDR PNG_U32( 73, 72, 68, 82) #define png_PLTE PNG_U32( 80, 76, 84, 69) #define png_bKGD PNG_U32( 98, 75, 71, 68) #define png_cHRM PNG_U32( 99, 72, 82, 77) #define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */ #define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ #define png_gAMA PNG_U32(103, 65, 77, 65) #define png_gIFg PNG_U32(103, 73, 70, 103) #define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ #define png_gIFx PNG_U32(103, 73, 70, 120) #define png_hIST PNG_U32(104, 73, 83, 84) #define png_iCCP PNG_U32(105, 67, 67, 80) #define png_iTXt PNG_U32(105, 84, 88, 116) #define png_oFFs PNG_U32(111, 70, 70, 115) #define png_pCAL PNG_U32(112, 67, 65, 76) #define png_pHYs PNG_U32(112, 72, 89, 115) #define png_sBIT PNG_U32(115, 66, 73, 84) #define png_sCAL PNG_U32(115, 67, 65, 76) #define png_sPLT PNG_U32(115, 80, 76, 84) #define png_sRGB PNG_U32(115, 82, 71, 66) #define png_sTER PNG_U32(115, 84, 69, 82) #define png_tEXt PNG_U32(116, 69, 88, 116) #define png_tIME PNG_U32(116, 73, 77, 69) #define png_tRNS PNG_U32(116, 82, 78, 83) #define png_zTXt PNG_U32(122, 84, 88, 116) /* The following will work on (signed char*) strings, whereas the get_uint_32 * macro will fail on top-bit-set values because of the sign extension. */ #define PNG_CHUNK_FROM_STRING(s)\ PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3]) /* This uses (char), not (png_byte) to avoid warnings on systems where (char) is * signed and the argument is a (char[]) This macro will fail miserably on * systems where (char) is more than 8 bits. */ #define PNG_STRING_FROM_CHUNK(s,c)\ (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \ ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\ ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \ ((char*)(s))[3]=(char)((c & 0xff))) /* Do the same but terminate with a null character. */ #define PNG_CSTRING_FROM_CHUNK(s,c)\ (void)(PNG_STRING_FROM_CHUNK(s,c), ((char*)(s))[4] = 0) /* Test on flag values as defined in the spec (section 5.4): */ #define PNG_CHUNK_ANCILLARY(c) (1 & ((c) >> 29)) #define PNG_CHUNK_CRITICAL(c) (!PNG_CHUNK_ANCILLARY(c)) #define PNG_CHUNK_PRIVATE(c) (1 & ((c) >> 21)) #define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) #define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) /* Gamma values (new at libpng-1.5.4): */ #define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ #define PNG_GAMMA_MAC_INVERSE 65909 #define PNG_GAMMA_sRGB_INVERSE 45455 /* Almost everything below is C specific; the #defines above can be used in * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. */ #ifndef PNG_VERSION_INFO_ONLY #include "pngstruct.h" #include "pnginfo.h" /* Validate the include paths - the include path used to generate pnglibconf.h * must match that used in the build, or we must be using pnglibconf.h.prebuilt: */ #if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM # error ZLIB_VERNUM != PNG_ZLIB_VERNUM \ "-I (include path) error: see the notes in pngpriv.h" /* This means that when pnglibconf.h was built the copy of zlib.h that it * used is not the same as the one being used here. Because the build of * libpng makes decisions to use inflateInit2 and inflateReset2 based on the * zlib version number and because this affects handling of certain broken * PNG files the -I directives must match. * * The most likely explanation is that you passed a -I in CFLAGS. This will * not work; all the preprocessor directories and in particular all the -I * directives must be in CPPFLAGS. */ #endif /* This is used for 16-bit gamma tables -- only the top level pointers are * const; this could be changed: */ typedef const png_uint_16p * png_const_uint_16pp; /* Added to libpng-1.5.7: sRGB conversion tables */ #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) #ifdef PNG_SIMPLIFIED_READ_SUPPORTED PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); /* Convert from an sRGB encoded value 0..255 to a 16-bit linear value, * 0..65535. This table gives the closest 16-bit answers (no errors). */ #endif PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); #define PNG_sRGB_FROM_LINEAR(linear) \ ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \ + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8))) /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB * encoded value with maximum error 0.646365. Note that the input is not a * 16-bit value; it has been multiplied by 255! */ #endif /* SIMPLIFIED_READ/WRITE */ /* Inhibit C++ name-mangling for libpng functions but not for system calls. */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /* Internal functions; these are not exported from a DLL however because they * are used within several of the C source files they have to be C extern. * * All of these functions must be declared with PNG_INTERNAL_FUNCTION. */ /* Zlib support */ #define PNG_UNEXPECTED_ZLIB_RETURN (-7) PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), PNG_EMPTY); /* Used by the zlib handling functions to ensure that z_stream::msg is always * set before they return. */ #ifdef PNG_WRITE_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, png_compression_bufferp *list),PNG_EMPTY); /* Free the buffer list used by the compressed write code. */ #endif #if defined(PNG_FLOATING_POINT_SUPPORTED) && \ !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ (defined(PNG_sCAL_SUPPORTED) && \ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, double fp, png_const_charp text),PNG_EMPTY); #endif /* Check the user version string for compatibility, returns false if the version * numbers aren't compatible. */ PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, png_const_charp user_png_ver),PNG_EMPTY); /* Internal base allocator - no messages, NULL on failure to allocate. This * does, however, call the application provided allocator and that could call * png_error (although that would be a bug in the application implementation.) */ PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED); #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) /* Internal array allocator, outputs no error or warning messages on failure, * just returns NULL. */ PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, int nelements, size_t element_size),PNG_ALLOCATED); /* The same but an existing array is extended by add_elements. This function * also memsets the new elements to 0 and copies the old elements. The old * array is not freed or altered. */ PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, png_const_voidp array, int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED); #endif /* text, sPLT or unknown chunks */ /* Magic to create a struct when there is no struct to call the user supplied * memory allocators. Because error handling has not been set up the memory * handlers can't safely call png_error, but this is an obscure and undocumented * restriction so libpng has to assume that the 'free' handler, at least, might * call png_error. */ PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED); /* Free memory from internal libpng struct */ PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), PNG_EMPTY); /* Free an allocated jmp_buf (always succeeds) */ PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); /* Function to allocate memory for zlib. PNGAPI is disallowed. */ PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), PNG_ALLOCATED); /* Function to free memory for zlib. PNGAPI is disallowed. */ PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); /* Next four functions are used internally as callbacks. PNGCBAPI is required * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to * PNGCBAPI at 1.5.0 */ PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, png_bytep data, png_size_t length),PNG_EMPTY); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, png_bytep buffer, png_size_t length),PNG_EMPTY); #endif PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, png_bytep data, png_size_t length),PNG_EMPTY); #ifdef PNG_WRITE_FLUSH_SUPPORTED # ifdef PNG_STDIO_SUPPORTED PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), PNG_EMPTY); # endif #endif /* Reset the CRC variable */ PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); /* Write the "data" buffer to whatever output you are using */ PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, png_const_bytep data, png_size_t length),PNG_EMPTY); /* Read and check the PNG file signature */ PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); /* Read the chunk header (length + type name) */ PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), PNG_EMPTY); /* Read data from whatever input you are using into the "data" buffer */ PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, png_size_t length),PNG_EMPTY); /* Read bytes into buf, and update png_ptr->crc */ PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, png_uint_32 length),PNG_EMPTY); /* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, png_uint_32 skip),PNG_EMPTY); /* Read the CRC from the file and compare it to the libpng calculated CRC */ PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY); /* Calculate the CRC over a section of data. Note that we are only * passing a maximum of 64K on systems that have this as a memory limit, * since this is the maximum buffer size we can specify. */ PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, png_const_bytep ptr, png_size_t length),PNG_EMPTY); #ifdef PNG_WRITE_FLUSH_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); #endif /* Write various chunks */ /* Write the IHDR chunk, and update the png_struct with the necessary * information. */ PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int compression_method, int filter_method, int interlace_method),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); #ifdef PNG_WRITE_gAMA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, png_fixed_point file_gamma),PNG_EMPTY); #endif #ifdef PNG_WRITE_sBIT_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, png_const_color_8p sbit, int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_cHRM_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, const png_xy *xy), PNG_EMPTY); /* The xy value must have been previously validated */ #endif #ifdef PNG_WRITE_sRGB_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, int intent),PNG_EMPTY); #endif #ifdef PNG_WRITE_eXIf_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_eXIf,(png_structrp png_ptr, png_bytep exif, int num_exif),PNG_EMPTY); #endif #ifdef PNG_WRITE_iCCP_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, png_const_charp name, png_const_bytep profile), PNG_EMPTY); /* The profile must have been previously validated for correctness, the * length comes from the first four bytes. Only the base, deflate, * compression is supported. */ #endif #ifdef PNG_WRITE_sPLT_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, png_const_sPLT_tp palette),PNG_EMPTY); #endif #ifdef PNG_WRITE_tRNS_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, png_const_bytep trans, png_const_color_16p values, int number, int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_bKGD_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, png_const_color_16p values, int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_hIST_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, png_const_uint_16p hist, int num_hist),PNG_EMPTY); #endif /* Chunks that have keywords */ #ifdef PNG_WRITE_tEXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY); #endif #ifdef PNG_WRITE_zTXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp key, png_const_charp text, int compression),PNG_EMPTY); #endif #ifdef PNG_WRITE_iTXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, int compression, png_const_charp key, png_const_charp lang, png_const_charp lang_key, png_const_charp text),PNG_EMPTY); #endif #ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_pCAL_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params),PNG_EMPTY); #endif #ifdef PNG_WRITE_pHYs_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, int unit_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_tIME_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, png_const_timep mod_time),PNG_EMPTY); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); #endif /* Called when finished processing a row of data */ PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), PNG_EMPTY); /* Internal use only. Called before first row of data */ PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), PNG_EMPTY); /* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an * array of png_ptr->width pixels. If the image is not interlaced or this * is the final pass this just does a memcpy, otherwise the "display" flag * is used to determine whether to copy pixels that are not in the current pass. * * Because 'png_do_read_interlace' (below) replicates pixels this allows this * function to achieve the documented 'blocky' appearance during interlaced read * if display is 1 and the 'sparkle' appearance, where existing pixels in 'row' * are not changed if they are not in the current pass, when display is 0. * * 'display' must be 0 or 1, otherwise the memcpy will be done regardless. * * The API always reads from the png_struct row buffer and always assumes that * it is full width (png_do_read_interlace has already been called.) * * This function is only ever used to write to row buffers provided by the * caller of the relevant libpng API and the row must have already been * transformed by the read transformations. * * The PNG_USE_COMPILE_TIME_MASKS option causes generation of pre-computed * bitmasks for use within the code, otherwise runtime generated masks are used. * The default is compile time masks. */ #ifndef PNG_USE_COMPILE_TIME_MASKS # define PNG_USE_COMPILE_TIME_MASKS 1 #endif PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, png_bytep row, int display),PNG_EMPTY); #ifdef PNG_READ_INTERLACING_SUPPORTED /* Expand an interlaced row: the 'row_info' describes the pass data that has * been read in and must correspond to the pixels in 'row', the pixels are * expanded (moved apart) in 'row' to match the final layout, when doing this * the pixels are *replicated* to the intervening space. This is essential for * the correct operation of png_combine_row, above. */ PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); #endif /* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Grab pixels out of a row for an interlaced pass */ PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, png_bytep row, int pass),PNG_EMPTY); #endif /* Unfilter a row: check the filter value before calling this, there is no point * calling it for PNG_FILTER_VALUE_NONE. */ PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); #if PNG_ARM_NEON_OPT > 0 PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); #endif #if PNG_MIPS_MSA_OPT > 0 PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_msa,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_msa,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_msa,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_msa,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_msa,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_msa,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_msa,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); #endif #if PNG_POWERPC_VSX_OPT > 0 PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_vsx,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_vsx,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_vsx,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_vsx,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_vsx,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_vsx,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_vsx,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); #endif #if PNG_INTEL_SSE_IMPLEMENTATION > 0 PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_sse2,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_sse2,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_sse2,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_sse2,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_sse2,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_sse2,(png_row_infop row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); #endif /* Choose the best filter to use and filter the row data */ PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer * is NULL the function checks, instead, for the end of the stream. In this * case a benign error will be issued if the stream end is not found or if * extra data has to be consumed. */ PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), PNG_EMPTY); /* This cleans up when the IDAT LZ stream does not end when the last image * byte is read; there is still some pending input. */ PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), PNG_EMPTY); /* Finish a row while reading, dealing with interlacing passes, etc. */ #endif /* SEQUENTIAL_READ */ /* Initialize the row buffers, etc. */ PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); #if ZLIB_VERNUM >= 0x1240 PNG_INTERNAL_FUNCTION(int,png_zlib_inflate,(png_structrp png_ptr, int flush), PNG_EMPTY); # define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush) #else /* Zlib < 1.2.4 */ # define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush) #endif /* Zlib < 1.2.4 */ #ifdef PNG_READ_TRANSFORMS_SUPPORTED /* Optional call to update the users info structure */ PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); #endif /* Shared transform functions, defined in pngtran.c */ #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, png_bytep row, int at_start),PNG_EMPTY); #endif #ifdef PNG_16BIT_SUPPORTED #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ defined(PNG_WRITE_PACKSWAP_SUPPORTED) PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, png_bytep row),PNG_EMPTY); #endif /* The following decodes the appropriate chunks, and does error correction, * then calls the appropriate callback for the chunk if it is valid. */ /* Decode the IHDR chunk */ PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #ifdef PNG_READ_bKGD_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_cHRM_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_eXIf_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_eXIf,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_gAMA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_hIST_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_iCCP_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif /* READ_iCCP */ #ifdef PNG_READ_iTXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_oFFs_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_pCAL_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_pHYs_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sBIT_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sCAL_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_sPLT_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif /* READ_sPLT */ #ifdef PNG_READ_sRGB_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tEXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tIME_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_tRNS_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif #ifdef PNG_READ_zTXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); #endif PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_const_structrp png_ptr, const png_uint_32 chunk_name),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_check_chunk_length,(png_const_structrp png_ptr, const png_uint_32 chunk_length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY); /* This is the function that gets called for unknown chunks. The 'keep' * argument is either non-zero for a known chunk that has been set to be * handled as unknown or zero for an unknown chunk. By default the function * just skips the chunk or errors out if it is critical. */ #if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); /* Exactly as the API png_handle_as_unknown() except that the argument is a * 32-bit chunk name, not a string. */ #endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ /* Handle the transformations for reading and writing */ #ifdef PNG_READ_TRANSFORMS_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); #endif #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); #endif #ifdef PNG_READ_TRANSFORMS_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), PNG_EMPTY); #endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, png_bytep row),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), PNG_EMPTY); # ifdef PNG_READ_tEXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); # endif # ifdef PNG_READ_zTXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); # endif # ifdef PNG_READ_iTXt_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr, png_inforp info_ptr),PNG_EMPTY); # endif #endif /* PROGRESSIVE_READ */ /* Added at libpng version 1.6.0 */ #ifdef PNG_GAMMA_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr, png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY); /* Set the colorspace gamma with a value provided by the application or by * the gAMA chunk on read. The value will override anything set by an ICC * profile. */ PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr, png_inforp info_ptr), PNG_EMPTY); /* Synchronize the info 'valid' flags with the colorspace */ PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, png_inforp info_ptr), PNG_EMPTY); /* Copy the png_struct colorspace to the info_struct and call the above to * synchronize the flags. Checks for NULL info_ptr and does nothing. */ #endif /* Added at libpng version 1.4.0 */ #ifdef PNG_COLORSPACE_SUPPORTED /* These internal functions are for maintaining the colorspace structure within * a png_info or png_struct (or, indeed, both). */ PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities, (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, int preferred), PNG_EMPTY); PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints, (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ, int preferred), PNG_EMPTY); #ifdef PNG_sRGB_SUPPORTED PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr, png_colorspacerp colorspace, int intent), PNG_EMPTY); /* This does set the colorspace gAMA and cHRM values too, but doesn't set the * flags to write them, if it returns false there was a problem and an error * message has already been output (but the colorspace may still need to be * synced to record the invalid flag). */ #endif /* sRGB */ #ifdef PNG_iCCP_SUPPORTED PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length, png_const_bytep profile, int color_type), PNG_EMPTY); /* The 'name' is used for information only */ /* Routines for checking parts of an ICC profile. */ #ifdef PNG_READ_iCCP_SUPPORTED PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length), PNG_EMPTY); #endif /* READ_iCCP */ PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length, png_const_bytep profile /* first 132 bytes only */, int color_type), PNG_EMPTY); PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_charp name, png_uint_32 profile_length, png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); #ifdef PNG_sRGB_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,( png_const_structrp png_ptr, png_colorspacerp colorspace, png_const_bytep profile, uLong adler), PNG_EMPTY); /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may * be zero to indicate that it is not available. It is used, if provided, * as a fast check on the profile when checking to see if it is sRGB. */ #endif #endif /* iCCP */ #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients, (png_structrp png_ptr), PNG_EMPTY); /* Set the rgb_to_gray coefficients from the colorspace Y values */ #endif /* READ_RGB_TO_GRAY */ #endif /* COLORSPACE */ /* Added at libpng version 1.4.0 */ PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, int filter_type),PNG_EMPTY); /* Added at libpng version 1.5.10 */ #if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); #endif #if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN); #endif /* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite * the end. Always leaves the buffer nul terminated. Never errors out (and * there is no error code.) */ PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, size_t pos, png_const_charp string),PNG_EMPTY); /* Various internal functions to handle formatted warning messages, currently * only implemented for warnings. */ #if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) /* Utility to dump an unsigned value into a buffer, given a start pointer and * and end pointer (which should point just *beyond* the end of the buffer!) * Returns the pointer to the start of the formatted string. This utility only * does unsigned values. */ PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); /* Convenience macro that takes an array: */ #define PNG_FORMAT_NUMBER(buffer,format,number) \ png_format_number(buffer, buffer + (sizeof buffer), format, number) /* Suggested size for a number buffer (enough for 64 bits and a sign!) */ #define PNG_NUMBER_BUFFER_SIZE 24 /* These are the integer formats currently supported, the name is formed from * the standard printf(3) format string. */ #define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */ #define PNG_NUMBER_FORMAT_02u 2 #define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */ #define PNG_NUMBER_FORMAT_02d 2 #define PNG_NUMBER_FORMAT_x 3 #define PNG_NUMBER_FORMAT_02x 4 #define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */ #endif #ifdef PNG_WARNINGS_SUPPORTED /* New defines and members adding in libpng-1.5.4 */ # define PNG_WARNING_PARAMETER_SIZE 32 # define PNG_WARNING_PARAMETER_COUNT 8 /* Maximum 9; see pngerror.c */ /* An l-value of this type has to be passed to the APIs below to cache the * values of the parameters to a formatted warning message. */ typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ PNG_WARNING_PARAMETER_SIZE]; PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, int number, png_const_charp string),PNG_EMPTY); /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, * including the trailing '\0'. */ PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, (png_warning_parameters p, int number, int format, png_alloc_size_t value), PNG_EMPTY); /* Use png_alloc_size_t because it is an unsigned type as big as any we * need to output. Use the following for a signed value. */ PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, (png_warning_parameters p, int number, int format, png_int_32 value), PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, png_warning_parameters p, png_const_charp message),PNG_EMPTY); /* 'message' follows the X/Open approach of using @1, @2 to insert * parameters previously supplied using the above functions. Errors in * specifying the parameters will simply result in garbage substitutions. */ #endif #ifdef PNG_BENIGN_ERRORS_SUPPORTED /* Application errors (new in 1.6); use these functions (declared below) for * errors in the parameters or order of API function calls on read. The * 'warning' should be used for an error that can be handled completely; the * 'error' for one which can be handled safely but which may lose application * information or settings. * * By default these both result in a png_error call prior to release, while in a * released version the 'warning' is just a warning. However if the application * explicitly disables benign errors (explicitly permitting the code to lose * information) they both turn into warnings. * * If benign errors aren't supported they end up as the corresponding base call * (png_warning or png_error.) */ PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, png_const_charp message),PNG_EMPTY); /* The application provided invalid parameters to an API function or called * an API function at the wrong time, libpng can completely recover. */ PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, png_const_charp message),PNG_EMPTY); /* As above but libpng will ignore the call, or attempt some other partial * recovery from the error. */ #else # define png_app_warning(pp,s) png_warning(pp,s) # define png_app_error(pp,s) png_error(pp,s) #endif PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, png_const_charp message, int error),PNG_EMPTY); /* Report a recoverable issue in chunk data. On read this is used to report * a problem found while reading a particular chunk and the * png_chunk_benign_error or png_chunk_warning function is used as * appropriate. On write this is used to report an error that comes from * data set via an application call to a png_set_ API and png_app_error or * png_app_warning is used as appropriate. * * The 'error' parameter must have one of the following values: */ #define PNG_CHUNK_WARNING 0 /* never an error */ #define PNG_CHUNK_WRITE_ERROR 1 /* an error only on write */ #define PNG_CHUNK_ERROR 2 /* always an error */ /* ASCII to FP interfaces, currently only implemented if sCAL * support is required. */ #if defined(PNG_sCAL_SUPPORTED) /* MAX_DIGITS is actually the maximum number of characters in an sCAL * width or height, derived from the precision (number of significant * digits - a build time settable option) and assumptions about the * maximum ridiculous exponent. */ #define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) #ifdef PNG_FLOATING_POINT_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, png_charp ascii, png_size_t size, double fp, unsigned int precision), PNG_EMPTY); #endif /* FLOATING_POINT */ #ifdef PNG_FIXED_POINT_SUPPORTED PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY); #endif /* FIXED_POINT */ #endif /* sCAL */ #if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) /* An internal API to validate the format of a floating point number. * The result is the index of the next character. If the number is * not valid it will be the index of a character in the supposed number. * * The format of a number is defined in the PNG extensions specification * and this API is strictly conformant to that spec, not anyone elses! * * The format as a regular expression is: * * [+-]?[0-9]+.?([Ee][+-]?[0-9]+)? * * or: * * [+-]?.[0-9]+(.[0-9]+)?([Ee][+-]?[0-9]+)? * * The complexity is that either integer or fraction must be present and the * fraction is permitted to have no digits only if the integer is present. * * NOTE: The dangling E problem. * There is a PNG valid floating point number in the following: * * PNG floating point numbers are not greedy. * * Working this out requires *TWO* character lookahead (because of the * sign), the parser does not do this - it will fail at the 'r' - this * doesn't matter for PNG sCAL chunk values, but it requires more care * if the value were ever to be embedded in something more complex. Use * ANSI-C strtod if you need the lookahead. */ /* State table for the parser. */ #define PNG_FP_INTEGER 0 /* before or in integer */ #define PNG_FP_FRACTION 1 /* before or in fraction */ #define PNG_FP_EXPONENT 2 /* before or in exponent */ #define PNG_FP_STATE 3 /* mask for the above */ #define PNG_FP_SAW_SIGN 4 /* Saw +/- in current state */ #define PNG_FP_SAW_DIGIT 8 /* Saw a digit in current state */ #define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */ #define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */ #define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */ /* These three values don't affect the parser. They are set but not used. */ #define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */ #define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */ #define PNG_FP_NONZERO 256 /* A non-zero value */ #define PNG_FP_STICKY 448 /* The above three flags */ /* This is available for the caller to store in 'state' if required. Do not * call the parser after setting it (the parser sometimes clears it.) */ #define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ /* Result codes for the parser (boolean - true meants ok, false means * not ok yet.) */ #define PNG_FP_MAYBE 0 /* The number may be valid in the future */ #define PNG_FP_OK 1 /* The number is valid */ /* Tests on the sticky non-zero and negative flags. To pass these checks * the state must also indicate that the whole number is valid - this is * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this * is equivalent to PNG_FP_OK above.) */ #define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO) /* NZ_MASK: the string is valid and a non-zero negative value */ #define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO) /* Z MASK: the string is valid and a non-zero value. */ /* PNG_FP_SAW_DIGIT: the string is valid. */ #define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) #define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) #define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) /* The actual parser. This can be called repeatedly. It updates * the index into the string and the state variable (which must * be initialized to 0). It returns a result code, as above. There * is no point calling the parser any more if it fails to advance to * the end of the string - it is stuck on an invalid character (or * terminated by '\0'). * * Note that the pointer will consume an E or even an E+ and then leave * a 'maybe' state even though a preceding integer.fraction is valid. * The PNG_FP_WAS_VALID flag indicates that a preceding substring was * a valid number. It's possible to recover from this by calling * the parser again (from the start, with state 0) but with a string * that omits the last character (i.e. set the size to the index of * the problem character.) This has not been tested within libpng. */ PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); /* This is the same but it checks a complete string and returns true * only if it just contains a floating point number. As of 1.5.4 this * function also returns the state at the end of parsing the number if * it was valid (otherwise it returns 0.) This can be used for testing * for negative or zero values using the sticky flag. */ PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, png_size_t size),PNG_EMPTY); #endif /* pCAL || sCAL */ #if defined(PNG_GAMMA_SUPPORTED) ||\ defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) /* Added at libpng version 1.5.0 */ /* This is a utility to provide a*times/div (rounded) and indicate * if there is an overflow. The result is a boolean - false (0) * for overflow, true (1) if no overflow, in which case *res * holds the result. */ PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); #endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) /* Same deal, but issue a warning on overflow and return 0. */ PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn, (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); #endif #ifdef PNG_GAMMA_SUPPORTED /* Calculate a reciprocal - used for gamma values. This returns * 0 if the argument is 0 in order to maintain an undefined value; * there are no warnings. */ PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), PNG_EMPTY); #ifdef PNG_READ_GAMMA_SUPPORTED /* The same but gives a reciprocal of the product of two fixed point * values. Accuracy is suitable for gamma calculations but this is * not exact - use png_muldiv for that. Only required at present on read. */ PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, png_fixed_point b),PNG_EMPTY); #endif /* Return true if the gamma value is significantly different from 1.0 */ PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), PNG_EMPTY); #endif #ifdef PNG_READ_GAMMA_SUPPORTED /* Internal fixed point gamma correction. These APIs are called as * required to convert single values - they don't need to be fast, * they are not used when processing image pixel values. * * While the input is an 'unsigned' value it must actually be the * correct bit value - 0..255 or 0..65535 as required. */ PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), PNG_EMPTY); PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, int bit_depth),PNG_EMPTY); #endif /* SIMPLIFIED READ/WRITE SUPPORT */ #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) /* The internal structure that png_image::opaque points to. */ typedef struct png_control { png_structp png_ptr; png_infop info_ptr; png_voidp error_buf; /* Always a jmp_buf at present. */ png_const_bytep memory; /* Memory buffer. */ png_size_t size; /* Size of the memory buffer. */ unsigned int for_write :1; /* Otherwise it is a read structure */ unsigned int owned_file :1; /* We own the file in io_ptr */ } png_control; /* Return the pointer to the jmp_buf from a png_control: necessary because C * does not reveal the type of the elements of jmp_buf. */ #ifdef __cplusplus # define png_control_jmp_buf(pc) (((jmp_buf*)((pc)->error_buf))[0]) #else # define png_control_jmp_buf(pc) ((pc)->error_buf) #endif /* Utility to safely execute a piece of libpng code catching and logging any * errors that might occur. Returns true on success, false on failure (either * of the function or as a result of a png_error.) */ PNG_INTERNAL_CALLBACK(void,png_safe_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN); #ifdef PNG_WARNINGS_SUPPORTED PNG_INTERNAL_CALLBACK(void,png_safe_warning,(png_structp png_ptr, png_const_charp warning_message),PNG_EMPTY); #else # define png_safe_warning 0/*dummy argument*/ #endif PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); /* Utility to log an error; this also cleans up the png_image; the function * always returns 0 (false). */ PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, png_const_charp error_message),PNG_EMPTY); #ifndef PNG_SIMPLIFIED_READ_SUPPORTED /* png_image_free is used by the write code but not exported */ PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); #endif /* !SIMPLIFIED_READ */ #endif /* SIMPLIFIED READ/WRITE */ /* These are initialization functions for hardware specific PNG filter * optimizations; list these here then select the appropriate one at compile * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined * the generic code is used. */ #ifdef PNG_FILTER_OPTIMIZATIONS PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); /* Just declare the optimization that will be used */ #else /* List *all* the possible optimizations here - this branch is required if * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. */ # if PNG_ARM_NEON_OPT > 0 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); #endif #if PNG_MIPS_MSA_OPT > 0 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_msa, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); #endif # if PNG_INTEL_SSE_IMPLEMENTATION > 0 PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); # endif #endif PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, (png_structrp png_ptr, png_const_charp key, png_bytep new_key), PNG_EMPTY); /* Maintainer: Put new private prototypes here ^ */ #include "pngdebug.h" #ifdef __cplusplus } #endif #endif /* PNG_VERSION_INFO_ONLY */ #endif /* PNGPRIV_H */ stella-5.1.1/src/libpng/pngread.c000066400000000000000000004257311324334165500166520ustar00rootroot00000000000000 /* pngread.c - read a PNG file * * Last changed in libpng 1.6.33 [September 28, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * This file contains routines that an application calls directly to * read a PNG file or stream. */ #include "pngpriv.h" #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) # include #endif #ifdef PNG_READ_SUPPORTED /* Create a PNG structure for reading, and allocate any memory needed. */ PNG_FUNCTION(png_structp,PNGAPI png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) { #ifndef PNG_USER_MEM_SUPPORTED png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, error_fn, warn_fn, NULL, NULL, NULL); #else return png_create_read_struct_2(user_png_ver, error_ptr, error_fn, warn_fn, NULL, NULL, NULL); } /* Alternate create PNG structure for reading, and allocate any memory * needed. */ PNG_FUNCTION(png_structp,PNGAPI png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); #endif /* USER_MEM */ if (png_ptr != NULL) { png_ptr->mode = PNG_IS_READ_STRUCT; /* Added in libpng-1.6.0; this can be used to detect a read structure if * required (it will be zero in a write structure.) */ # ifdef PNG_SEQUENTIAL_READ_SUPPORTED png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE; # endif # ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; /* In stable builds only warn if an application error can be completely * handled. */ # if PNG_RELEASE_BUILD png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; # endif # endif /* TODO: delay this, it can be done in png_init_io (if the app doesn't * do it itself) avoiding setting the default function if it is not * required. */ png_set_read_fn(png_ptr, NULL, NULL); } return png_ptr; } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the information before the actual image data. This has been * changed in v0.90 to allow reading a file that already has the magic * bytes read from the stream. You can tell libpng how many bytes have * been read from the beginning of the stream (up to the maximum of 8) * via png_set_sig_bytes(), and we will only check the remaining bytes * here. The application can then have access to the signature bytes we * read if it is determined that this isn't a valid PNG file. */ void PNGAPI png_read_info(png_structrp png_ptr, png_inforp info_ptr) { #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED int keep; #endif png_debug(1, "in png_read_info"); if (png_ptr == NULL || info_ptr == NULL) return; /* Read and check the PNG file signature. */ png_read_sig(png_ptr, info_ptr); for (;;) { png_uint_32 length = png_read_chunk_header(png_ptr); png_uint_32 chunk_name = png_ptr->chunk_name; /* IDAT logic needs to happen here to simplify getting the two flags * right. */ if (chunk_name == png_IDAT) { if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && (png_ptr->mode & PNG_HAVE_PLTE) == 0) png_chunk_error(png_ptr, "Missing PLTE before IDAT"); else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) png_chunk_benign_error(png_ptr, "Too many IDATs found"); png_ptr->mode |= PNG_HAVE_IDAT; } else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; png_ptr->mode |= PNG_AFTER_IDAT; } /* This should be a binary subdivision search or a hash for * matching the chunk name rather than a linear search. */ if (chunk_name == png_IHDR) png_handle_IHDR(png_ptr, info_ptr, length); else if (chunk_name == png_IEND) png_handle_IEND(png_ptr, info_ptr, length); #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { png_handle_unknown(png_ptr, info_ptr, length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; else if (chunk_name == png_IDAT) { png_ptr->idat_size = 0; /* It has been consumed */ break; } } #endif else if (chunk_name == png_PLTE) png_handle_PLTE(png_ptr, info_ptr, length); else if (chunk_name == png_IDAT) { png_ptr->idat_size = length; break; } #ifdef PNG_READ_bKGD_SUPPORTED else if (chunk_name == png_bKGD) png_handle_bKGD(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_cHRM_SUPPORTED else if (chunk_name == png_cHRM) png_handle_cHRM(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_eXIf_SUPPORTED else if (chunk_name == png_eXIf) png_handle_eXIf(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_gAMA_SUPPORTED else if (chunk_name == png_gAMA) png_handle_gAMA(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_hIST_SUPPORTED else if (chunk_name == png_hIST) png_handle_hIST(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_oFFs_SUPPORTED else if (chunk_name == png_oFFs) png_handle_oFFs(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_pCAL_SUPPORTED else if (chunk_name == png_pCAL) png_handle_pCAL(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sCAL_SUPPORTED else if (chunk_name == png_sCAL) png_handle_sCAL(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_pHYs_SUPPORTED else if (chunk_name == png_pHYs) png_handle_pHYs(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sBIT_SUPPORTED else if (chunk_name == png_sBIT) png_handle_sBIT(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sRGB_SUPPORTED else if (chunk_name == png_sRGB) png_handle_sRGB(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_iCCP_SUPPORTED else if (chunk_name == png_iCCP) png_handle_iCCP(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sPLT_SUPPORTED else if (chunk_name == png_sPLT) png_handle_sPLT(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tEXt_SUPPORTED else if (chunk_name == png_tEXt) png_handle_tEXt(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tIME_SUPPORTED else if (chunk_name == png_tIME) png_handle_tIME(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tRNS_SUPPORTED else if (chunk_name == png_tRNS) png_handle_tRNS(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_zTXt_SUPPORTED else if (chunk_name == png_zTXt) png_handle_zTXt(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_iTXt_SUPPORTED else if (chunk_name == png_iTXt) png_handle_iTXt(png_ptr, info_ptr, length); #endif else png_handle_unknown(png_ptr, info_ptr, length, PNG_HANDLE_CHUNK_AS_DEFAULT); } } #endif /* SEQUENTIAL_READ */ /* Optional call to update the users info_ptr structure */ void PNGAPI png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_read_update_info"); if (png_ptr != NULL) { if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) { png_read_start_row(png_ptr); # ifdef PNG_READ_TRANSFORMS_SUPPORTED png_read_transform_info(png_ptr, info_ptr); # else PNG_UNUSED(info_ptr) # endif } /* New in 1.6.0 this avoids the bug of doing the initializations twice */ else png_app_error(png_ptr, "png_read_update_info/png_start_read_image: duplicate call"); } } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Initialize palette, background, etc, after transformations * are set, but before any reading takes place. This allows * the user to obtain a gamma-corrected palette, for example. * If the user doesn't call this, we will do it ourselves. */ void PNGAPI png_start_read_image(png_structrp png_ptr) { png_debug(1, "in png_start_read_image"); if (png_ptr != NULL) { if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) png_read_start_row(png_ptr); /* New in 1.6.0 this avoids the bug of doing the initializations twice */ else png_app_error(png_ptr, "png_start_read_image/png_read_update_info: duplicate call"); } } #endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED /* Undoes intrapixel differencing, * NOTE: this is apparently only supported in the 'sequential' reader. */ static void png_do_read_intrapixel(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_read_intrapixel"); if ( (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { int bytes_per_pixel; png_uint_32 row_width = row_info->width; if (row_info->bit_depth == 8) { png_bytep rp; png_uint_32 i; if (row_info->color_type == PNG_COLOR_TYPE_RGB) bytes_per_pixel = 3; else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) bytes_per_pixel = 4; else return; for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); } } else if (row_info->bit_depth == 16) { png_bytep rp; png_uint_32 i; if (row_info->color_type == PNG_COLOR_TYPE_RGB) bytes_per_pixel = 6; else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) bytes_per_pixel = 8; else return; for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1); png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3); png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5); png_uint_32 red = (s0 + s1 + 65536) & 0xffff; png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; *(rp ) = (png_byte)((red >> 8) & 0xff); *(rp + 1) = (png_byte)(red & 0xff); *(rp + 4) = (png_byte)((blue >> 8) & 0xff); *(rp + 5) = (png_byte)(blue & 0xff); } } } } #endif /* MNG_FEATURES */ void PNGAPI png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) { png_row_info row_info; if (png_ptr == NULL) return; png_debug2(1, "in png_read_row (row %lu, pass %d)", (unsigned long)png_ptr->row_number, png_ptr->pass); /* png_read_start_row sets the information (in particular iwidth) for this * interlace pass. */ if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) png_read_start_row(png_ptr); /* 1.5.6: row_info moved out of png_struct to a local here. */ row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */ row_info.color_type = png_ptr->color_type; row_info.bit_depth = png_ptr->bit_depth; row_info.channels = png_ptr->channels; row_info.pixel_depth = png_ptr->pixel_depth; row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); #ifdef PNG_WARNINGS_SUPPORTED if (png_ptr->row_number == 0 && png_ptr->pass == 0) { /* Check for transforms that have been set but were defined out */ #if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) if ((png_ptr->transformations & PNG_FILLER) != 0) png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ !defined(PNG_READ_PACKSWAP_SUPPORTED) if ((png_ptr->transformations & PNG_PACKSWAP) != 0) png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) if ((png_ptr->transformations & PNG_PACK) != 0) png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) if ((png_ptr->transformations & PNG_SHIFT) != 0) png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) if ((png_ptr->transformations & PNG_BGR) != 0) png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); #endif } #endif /* WARNINGS */ #ifdef PNG_READ_INTERLACING_SUPPORTED /* If interlaced and we do not need a new row, combine row and return. * Notice that the pixels we have from previous rows have been transformed * already; we can only combine like with like (transformed or * untransformed) and, because of the libpng API for interlaced images, this * means we must transform before de-interlacing. */ if (png_ptr->interlaced != 0 && (png_ptr->transformations & PNG_INTERLACE) != 0) { switch (png_ptr->pass) { case 0: if (png_ptr->row_number & 0x07) { if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, 1/*display*/); png_read_finish_row(png_ptr); return; } break; case 1: if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) { if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, 1/*display*/); png_read_finish_row(png_ptr); return; } break; case 2: if ((png_ptr->row_number & 0x07) != 4) { if (dsp_row != NULL && (png_ptr->row_number & 4)) png_combine_row(png_ptr, dsp_row, 1/*display*/); png_read_finish_row(png_ptr); return; } break; case 3: if ((png_ptr->row_number & 3) || png_ptr->width < 3) { if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, 1/*display*/); png_read_finish_row(png_ptr); return; } break; case 4: if ((png_ptr->row_number & 3) != 2) { if (dsp_row != NULL && (png_ptr->row_number & 2)) png_combine_row(png_ptr, dsp_row, 1/*display*/); png_read_finish_row(png_ptr); return; } break; case 5: if ((png_ptr->row_number & 1) || png_ptr->width < 2) { if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, 1/*display*/); png_read_finish_row(png_ptr); return; } break; default: case 6: if ((png_ptr->row_number & 1) == 0) { png_read_finish_row(png_ptr); return; } break; } } #endif if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) png_error(png_ptr, "Invalid attempt to read row data"); /* Fill the row with IDAT data: */ png_ptr->row_buf[0]=255; /* to force error if no data was found */ png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) { if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, png_ptr->prev_row + 1, png_ptr->row_buf[0]); else png_error(png_ptr, "bad adaptive filter value"); } /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before * 1.5.6, while the buffer really is this big in current versions of libpng * it may not be in the future, so this was changed just to copy the * interlaced count: */ memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); #ifdef PNG_MNG_FEATURES_SUPPORTED if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1); } #endif #ifdef PNG_READ_TRANSFORMS_SUPPORTED if (png_ptr->transformations) png_do_read_transformations(png_ptr, &row_info); #endif /* The transformed pixel depth should match the depth now in row_info. */ if (png_ptr->transformed_pixel_depth == 0) { png_ptr->transformed_pixel_depth = row_info.pixel_depth; if (row_info.pixel_depth > png_ptr->maximum_pixel_depth) png_error(png_ptr, "sequential row overflow"); } else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth) png_error(png_ptr, "internal sequential row size calculation error"); #ifdef PNG_READ_INTERLACING_SUPPORTED /* Expand interlaced rows to full size */ if (png_ptr->interlaced != 0 && (png_ptr->transformations & PNG_INTERLACE) != 0) { if (png_ptr->pass < 6) png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations); if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, 1/*display*/); if (row != NULL) png_combine_row(png_ptr, row, 0/*row*/); } else #endif { if (row != NULL) png_combine_row(png_ptr, row, -1/*ignored*/); if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, -1/*ignored*/); } png_read_finish_row(png_ptr); if (png_ptr->read_row_fn != NULL) (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); } #endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. If the image is interlaced, * and png_set_interlace_handling() has been called, the rows need to * contain the contents of the rows from the previous pass. If the * image has alpha or transparency, and png_handle_alpha()[*] has been * called, the rows contents must be initialized to the contents of the * screen. * * "row" holds the actual image, and pixels are placed in it * as they arrive. If the image is displayed after each pass, it will * appear to "sparkle" in. "display_row" can be used to display a * "chunky" progressive image, with finer detail added as it becomes * available. If you do not want this "chunky" display, you may pass * NULL for display_row. If you do not want the sparkle display, and * you have not called png_handle_alpha(), you may pass NULL for rows. * If you have called png_handle_alpha(), and the image has either an * alpha channel or a transparency chunk, you must provide a buffer for * rows. In this case, you do not have to provide a display_row buffer * also, but you may. If the image is not interlaced, or if you have * not called png_set_interlace_handling(), the display_row buffer will * be ignored, so pass NULL to it. * * [*] png_handle_alpha() does not exist yet, as of this version of libpng */ void PNGAPI png_read_rows(png_structrp png_ptr, png_bytepp row, png_bytepp display_row, png_uint_32 num_rows) { png_uint_32 i; png_bytepp rp; png_bytepp dp; png_debug(1, "in png_read_rows"); if (png_ptr == NULL) return; rp = row; dp = display_row; if (rp != NULL && dp != NULL) for (i = 0; i < num_rows; i++) { png_bytep rptr = *rp++; png_bytep dptr = *dp++; png_read_row(png_ptr, rptr, dptr); } else if (rp != NULL) for (i = 0; i < num_rows; i++) { png_bytep rptr = *rp; png_read_row(png_ptr, rptr, NULL); rp++; } else if (dp != NULL) for (i = 0; i < num_rows; i++) { png_bytep dptr = *dp; png_read_row(png_ptr, NULL, dptr); dp++; } } #endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the entire image. If the image has an alpha channel or a tRNS * chunk, and you have called png_handle_alpha()[*], you will need to * initialize the image to the current image that PNG will be overlaying. * We set the num_rows again here, in case it was incorrectly set in * png_read_start_row() by a call to png_read_update_info() or * png_start_read_image() if png_set_interlace_handling() wasn't called * prior to either of these functions like it should have been. You can * only call this function once. If you desire to have an image for * each pass of a interlaced image, use png_read_rows() instead. * * [*] png_handle_alpha() does not exist yet, as of this version of libpng */ void PNGAPI png_read_image(png_structrp png_ptr, png_bytepp image) { png_uint_32 i, image_height; int pass, j; png_bytepp rp; png_debug(1, "in png_read_image"); if (png_ptr == NULL) return; #ifdef PNG_READ_INTERLACING_SUPPORTED if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) { pass = png_set_interlace_handling(png_ptr); /* And make sure transforms are initialized. */ png_start_read_image(png_ptr); } else { if (png_ptr->interlaced != 0 && (png_ptr->transformations & PNG_INTERLACE) == 0) { /* Caller called png_start_read_image or png_read_update_info without * first turning on the PNG_INTERLACE transform. We can fix this here, * but the caller should do it! */ png_warning(png_ptr, "Interlace handling should be turned on when " "using png_read_image"); /* Make sure this is set correctly */ png_ptr->num_rows = png_ptr->height; } /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in * the above error case. */ pass = png_set_interlace_handling(png_ptr); } #else if (png_ptr->interlaced) png_error(png_ptr, "Cannot read interlaced image -- interlace handler disabled"); pass = 1; #endif image_height=png_ptr->height; for (j = 0; j < pass; j++) { rp = image; for (i = 0; i < image_height; i++) { png_read_row(png_ptr, *rp, NULL); rp++; } } } #endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. Will not read past the end of the * file, will verify the end is accurate, and will read any comments * or time information at the end of the file, if info is not NULL. */ void PNGAPI png_read_end(png_structrp png_ptr, png_inforp info_ptr) { #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED int keep; #endif png_debug(1, "in png_read_end"); if (png_ptr == NULL) return; /* If png_read_end is called in the middle of reading the rows there may * still be pending IDAT data and an owned zstream. Deal with this here. */ #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0) #endif png_read_finish_IDAT(png_ptr); #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Report invalid palette index; added at libng-1.5.10 */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_palette_max > png_ptr->num_palette) png_benign_error(png_ptr, "Read palette index exceeding num_palette"); #endif do { png_uint_32 length = png_read_chunk_header(png_ptr); png_uint_32 chunk_name = png_ptr->chunk_name; if (chunk_name != png_IDAT) png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; if (chunk_name == png_IEND) png_handle_IEND(png_ptr, info_ptr, length); else if (chunk_name == png_IHDR) png_handle_IHDR(png_ptr, info_ptr, length); else if (info_ptr == NULL) png_crc_finish(png_ptr, length); #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { if (chunk_name == png_IDAT) { if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) png_benign_error(png_ptr, ".Too many IDATs found"); } png_handle_unknown(png_ptr, info_ptr, length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; } #endif else if (chunk_name == png_IDAT) { /* Zero length IDATs are legal after the last IDAT has been * read, but not after other chunks have been read. 1.6 does not * always read all the deflate data; specifically it cannot be relied * upon to read the Adler32 at the end. If it doesn't ignore IDAT * chunks which are longer than zero as well: */ if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) png_benign_error(png_ptr, "..Too many IDATs found"); png_crc_finish(png_ptr, length); } else if (chunk_name == png_PLTE) png_handle_PLTE(png_ptr, info_ptr, length); #ifdef PNG_READ_bKGD_SUPPORTED else if (chunk_name == png_bKGD) png_handle_bKGD(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_cHRM_SUPPORTED else if (chunk_name == png_cHRM) png_handle_cHRM(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_eXIf_SUPPORTED else if (chunk_name == png_eXIf) png_handle_eXIf(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_gAMA_SUPPORTED else if (chunk_name == png_gAMA) png_handle_gAMA(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_hIST_SUPPORTED else if (chunk_name == png_hIST) png_handle_hIST(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_oFFs_SUPPORTED else if (chunk_name == png_oFFs) png_handle_oFFs(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_pCAL_SUPPORTED else if (chunk_name == png_pCAL) png_handle_pCAL(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sCAL_SUPPORTED else if (chunk_name == png_sCAL) png_handle_sCAL(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_pHYs_SUPPORTED else if (chunk_name == png_pHYs) png_handle_pHYs(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sBIT_SUPPORTED else if (chunk_name == png_sBIT) png_handle_sBIT(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sRGB_SUPPORTED else if (chunk_name == png_sRGB) png_handle_sRGB(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_iCCP_SUPPORTED else if (chunk_name == png_iCCP) png_handle_iCCP(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_sPLT_SUPPORTED else if (chunk_name == png_sPLT) png_handle_sPLT(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tEXt_SUPPORTED else if (chunk_name == png_tEXt) png_handle_tEXt(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tIME_SUPPORTED else if (chunk_name == png_tIME) png_handle_tIME(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_tRNS_SUPPORTED else if (chunk_name == png_tRNS) png_handle_tRNS(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_zTXt_SUPPORTED else if (chunk_name == png_zTXt) png_handle_zTXt(png_ptr, info_ptr, length); #endif #ifdef PNG_READ_iTXt_SUPPORTED else if (chunk_name == png_iTXt) png_handle_iTXt(png_ptr, info_ptr, length); #endif else png_handle_unknown(png_ptr, info_ptr, length, PNG_HANDLE_CHUNK_AS_DEFAULT); } while ((png_ptr->mode & PNG_HAVE_IEND) == 0); } #endif /* SEQUENTIAL_READ */ /* Free all memory used in the read struct */ static void png_read_destroy(png_structrp png_ptr) { png_debug(1, "in png_read_destroy"); #ifdef PNG_READ_GAMMA_SUPPORTED png_destroy_gamma_table(png_ptr); #endif png_free(png_ptr, png_ptr->big_row_buf); png_ptr->big_row_buf = NULL; png_free(png_ptr, png_ptr->big_prev_row); png_ptr->big_prev_row = NULL; png_free(png_ptr, png_ptr->read_buffer); png_ptr->read_buffer = NULL; #ifdef PNG_READ_QUANTIZE_SUPPORTED png_free(png_ptr, png_ptr->palette_lookup); png_ptr->palette_lookup = NULL; png_free(png_ptr, png_ptr->quantize_index); png_ptr->quantize_index = NULL; #endif if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) { png_zfree(png_ptr, png_ptr->palette); png_ptr->palette = NULL; } png_ptr->free_me &= ~PNG_FREE_PLTE; #if defined(PNG_tRNS_SUPPORTED) || \ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) { png_free(png_ptr, png_ptr->trans_alpha); png_ptr->trans_alpha = NULL; } png_ptr->free_me &= ~PNG_FREE_TRNS; #endif inflateEnd(&png_ptr->zstream); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED png_free(png_ptr, png_ptr->save_buffer); png_ptr->save_buffer = NULL; #endif #if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \ defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) png_free(png_ptr, png_ptr->unknown_chunk.data); png_ptr->unknown_chunk.data = NULL; #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED png_free(png_ptr, png_ptr->chunk_list); png_ptr->chunk_list = NULL; #endif /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error * callbacks are still set at this point. They are required to complete the * destruction of the png_struct itself. */ } /* Free all memory used by the read */ void PNGAPI png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr) { png_structrp png_ptr = NULL; png_debug(1, "in png_destroy_read_struct"); if (png_ptr_ptr != NULL) png_ptr = *png_ptr_ptr; if (png_ptr == NULL) return; /* libpng 1.6.0: use the API to destroy info structs to ensure consistent * behavior. Prior to 1.6.0 libpng did extra 'info' destruction in this API. * The extra was, apparently, unnecessary yet this hides memory leak bugs. */ png_destroy_info_struct(png_ptr, end_info_ptr_ptr); png_destroy_info_struct(png_ptr, info_ptr_ptr); *png_ptr_ptr = NULL; png_read_destroy(png_ptr); png_destroy_png_struct(png_ptr); } void PNGAPI png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) { if (png_ptr == NULL) return; png_ptr->read_row_fn = read_row_fn; } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI png_read_png(png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params) { if (png_ptr == NULL || info_ptr == NULL) return; /* png_read_info() gives us all of the information from the * PNG file before the first IDAT (image data chunk). */ png_read_info(png_ptr, info_ptr); if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep))) png_error(png_ptr, "Image is too high to process with png_read_png()"); /* -------------- image transformations start here ------------------- */ /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM * is not implemented. This will only happen in de-configured (non-default) * libpng builds. The results can be unexpected - png_read_png may return * short or mal-formed rows because the transform is skipped. */ /* Tell libpng to strip 16-bit/color files down to 8 bits per color. */ if ((transforms & PNG_TRANSFORM_SCALE_16) != 0) /* Added at libpng-1.5.4. "strip_16" produces the same result that it * did in earlier versions, while "scale_16" is now more accurate. */ #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_SCALE_16 not supported"); #endif /* If both SCALE and STRIP are required pngrtran will effectively cancel the * latter by doing SCALE first. This is ok and allows apps not to check for * which is supported to get the right answer. */ if ((transforms & PNG_TRANSFORM_STRIP_16) != 0) #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED png_set_strip_16(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_16 not supported"); #endif /* Strip alpha bytes from the input data without combining with * the background (not recommended). */ if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0) #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED png_set_strip_alpha(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_ALPHA not supported"); #endif /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ if ((transforms & PNG_TRANSFORM_PACKING) != 0) #ifdef PNG_READ_PACK_SUPPORTED png_set_packing(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); #endif /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) #ifdef PNG_READ_PACKSWAP_SUPPORTED png_set_packswap(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif /* Expand paletted colors into true RGB triplets * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel * Expand paletted or RGB images with transparency to full alpha * channels so the data will be available as RGBA quartets. */ if ((transforms & PNG_TRANSFORM_EXPAND) != 0) #ifdef PNG_READ_EXPAND_SUPPORTED png_set_expand(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND not supported"); #endif /* We don't handle background color or gamma transformation or quantizing. */ /* Invert monochrome files to have 0 as white and 1 as black */ if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) #ifdef PNG_READ_INVERT_SUPPORTED png_set_invert_mono(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ if ((transforms & PNG_TRANSFORM_SHIFT) != 0) #ifdef PNG_READ_SHIFT_SUPPORTED if ((info_ptr->valid & PNG_INFO_sBIT) != 0) png_set_shift(png_ptr, &info_ptr->sig_bit); #else png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); #endif /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ if ((transforms & PNG_TRANSFORM_BGR) != 0) #ifdef PNG_READ_BGR_SUPPORTED png_set_bgr(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED png_set_swap_alpha(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif /* Swap bytes of 16-bit files to least significant byte first */ if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) #ifdef PNG_READ_SWAP_SUPPORTED png_set_swap(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif /* Added at libpng-1.2.41 */ /* Invert the alpha channel from opacity to transparency */ if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED png_set_invert_alpha(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* Added at libpng-1.2.41 */ /* Expand grayscale image to RGB */ if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0) #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED png_set_gray_to_rgb(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_GRAY_TO_RGB not supported"); #endif /* Added at libpng-1.5.4 */ if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0) #ifdef PNG_READ_EXPAND_16_SUPPORTED png_set_expand_16(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND_16 not supported"); #endif /* We don't handle adding filler bytes */ /* We use png_read_image and rely on that for interlace handling, but we also * call png_read_update_info therefore must turn on interlace handling now: */ (void)png_set_interlace_handling(png_ptr); /* Optional call to gamma correct and add the background to the palette * and update info structure. REQUIRED if you are expecting libpng to * update the palette for you (i.e., you selected such a transform above). */ png_read_update_info(png_ptr, info_ptr); /* -------------- image transformations end here ------------------- */ png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); if (info_ptr->row_pointers == NULL) { png_uint_32 iptr; info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr, info_ptr->height * (sizeof (png_bytep)))); for (iptr=0; iptrheight; iptr++) info_ptr->row_pointers[iptr] = NULL; info_ptr->free_me |= PNG_FREE_ROWS; for (iptr = 0; iptr < info_ptr->height; iptr++) info_ptr->row_pointers[iptr] = png_voidcast(png_bytep, png_malloc(png_ptr, info_ptr->rowbytes)); } png_read_image(png_ptr, info_ptr->row_pointers); info_ptr->valid |= PNG_INFO_IDAT; /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); PNG_UNUSED(params) } #endif /* INFO_IMAGE */ #endif /* SEQUENTIAL_READ */ #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* SIMPLIFIED READ * * This code currently relies on the sequential reader, though it could easily * be made to work with the progressive one. */ /* Arguments to png_image_finish_read: */ /* Encoding of PNG data (used by the color-map code) */ # define P_NOTSET 0 /* File encoding not yet known */ # define P_sRGB 1 /* 8-bit encoded to sRGB gamma */ # define P_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ # define P_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ # define P_LINEAR8 4 /* 8-bit linear: only from a file value */ /* Color-map processing: after libpng has run on the PNG image further * processing may be needed to convert the data to color-map indices. */ #define PNG_CMAP_NONE 0 #define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */ #define PNG_CMAP_TRANS 2 /* Process GA data to a background index */ #define PNG_CMAP_RGB 3 /* Process RGB data */ #define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */ /* The following document where the background is for each processing case. */ #define PNG_CMAP_NONE_BACKGROUND 256 #define PNG_CMAP_GA_BACKGROUND 231 #define PNG_CMAP_TRANS_BACKGROUND 254 #define PNG_CMAP_RGB_BACKGROUND 256 #define PNG_CMAP_RGB_ALPHA_BACKGROUND 216 typedef struct { /* Arguments: */ png_imagep image; png_voidp buffer; png_int_32 row_stride; png_voidp colormap; png_const_colorp background; /* Local variables: */ png_voidp local_row; png_voidp first_row; ptrdiff_t row_bytes; /* step between rows */ int file_encoding; /* E_ values above */ png_fixed_point gamma_to_linear; /* For P_FILE, reciprocal of gamma */ int colormap_processing; /* PNG_CMAP_ values above */ } png_image_read_control; /* Do all the *safe* initialization - 'safe' means that png_error won't be * called, so setting up the jmp_buf is not required. This means that anything * called from here must *not* call png_malloc - it has to call png_malloc_warn * instead so that control is returned safely back to this routine. */ static int png_image_read_init(png_imagep image) { if (image->opaque == NULL) { png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image, png_safe_error, png_safe_warning); /* And set the rest of the structure to NULL to ensure that the various * fields are consistent. */ memset(image, 0, (sizeof *image)); image->version = PNG_IMAGE_VERSION; if (png_ptr != NULL) { png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr != NULL) { png_controlp control = png_voidcast(png_controlp, png_malloc_warn(png_ptr, (sizeof *control))); if (control != NULL) { memset(control, 0, (sizeof *control)); control->png_ptr = png_ptr; control->info_ptr = info_ptr; control->for_write = 0; image->opaque = control; return 1; } /* Error clean up */ png_destroy_info_struct(png_ptr, &info_ptr); } png_destroy_read_struct(&png_ptr, NULL, NULL); } return png_image_error(image, "png_image_read: out of memory"); } return png_image_error(image, "png_image_read: opaque pointer not NULL"); } /* Utility to find the base format of a PNG file from a png_struct. */ static png_uint_32 png_image_format(png_structrp png_ptr) { png_uint_32 format = 0; if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) format |= PNG_FORMAT_FLAG_COLOR; if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) format |= PNG_FORMAT_FLAG_ALPHA; /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS * sets the png_struct fields; that's all we are interested in here. The * precise interaction with an app call to png_set_tRNS and PNG file reading * is unclear. */ else if (png_ptr->num_trans > 0) format |= PNG_FORMAT_FLAG_ALPHA; if (png_ptr->bit_depth == 16) format |= PNG_FORMAT_FLAG_LINEAR; if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0) format |= PNG_FORMAT_FLAG_COLORMAP; return format; } /* Is the given gamma significantly different from sRGB? The test is the same * one used in pngrtran.c when deciding whether to do gamma correction. The * arithmetic optimizes the division by using the fact that the inverse of the * file sRGB gamma is 2.2 */ static int png_gamma_not_sRGB(png_fixed_point g) { if (g < PNG_FP_1) { /* An uninitialized gamma is assumed to be sRGB for the simplified API. */ if (g == 0) return 0; return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); } return 1; } /* Do the main body of a 'png_image_begin_read' function; read the PNG file * header and fill in all the information. This is executed in a safe context, * unlike the init routine above. */ static int png_image_read_header(png_voidp argument) { png_imagep image = png_voidcast(png_imagep, argument); png_structrp png_ptr = image->opaque->png_ptr; png_inforp info_ptr = image->opaque->info_ptr; #ifdef PNG_BENIGN_ERRORS_SUPPORTED png_set_benign_errors(png_ptr, 1/*warn*/); #endif png_read_info(png_ptr, info_ptr); /* Do this the fast way; just read directly out of png_struct. */ image->width = png_ptr->width; image->height = png_ptr->height; { png_uint_32 format = png_image_format(png_ptr); image->format = format; #ifdef PNG_COLORSPACE_SUPPORTED /* Does the colorspace match sRGB? If there is no color endpoint * (colorant) information assume yes, otherwise require the * 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set. If the * colorspace has been determined to be invalid ignore it. */ if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB| PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS)) image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB; #endif } /* We need the maximum number of entries regardless of the format the * application sets here. */ { png_uint_32 cmap_entries; switch (png_ptr->color_type) { case PNG_COLOR_TYPE_GRAY: cmap_entries = 1U << png_ptr->bit_depth; break; case PNG_COLOR_TYPE_PALETTE: cmap_entries = (png_uint_32)png_ptr->num_palette; break; default: cmap_entries = 256; break; } if (cmap_entries > 256) cmap_entries = 256; image->colormap_entries = cmap_entries; } return 1; } #ifdef PNG_STDIO_SUPPORTED int PNGAPI png_image_begin_read_from_stdio(png_imagep image, FILE* file) { if (image != NULL && image->version == PNG_IMAGE_VERSION) { if (file != NULL) { if (png_image_read_init(image) != 0) { /* This is slightly evil, but png_init_io doesn't do anything other * than this and we haven't changed the standard IO functions so * this saves a 'safe' function. */ image->opaque->png_ptr->io_ptr = file; return png_safe_execute(image, png_image_read_header, image); } } else return png_image_error(image, "png_image_begin_read_from_stdio: invalid argument"); } else if (image != NULL) return png_image_error(image, "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); return 0; } int PNGAPI png_image_begin_read_from_file(png_imagep image, const char *file_name) { if (image != NULL && image->version == PNG_IMAGE_VERSION) { if (file_name != NULL) { FILE *fp = fopen(file_name, "rb"); if (fp != NULL) { if (png_image_read_init(image) != 0) { image->opaque->png_ptr->io_ptr = fp; image->opaque->owned_file = 1; return png_safe_execute(image, png_image_read_header, image); } /* Clean up: just the opened file. */ (void)fclose(fp); } else return png_image_error(image, strerror(errno)); } else return png_image_error(image, "png_image_begin_read_from_file: invalid argument"); } else if (image != NULL) return png_image_error(image, "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); return 0; } #endif /* STDIO */ static void PNGCBAPI png_image_memory_read(png_structp png_ptr, png_bytep out, png_size_t need) { if (png_ptr != NULL) { png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr); if (image != NULL) { png_controlp cp = image->opaque; if (cp != NULL) { png_const_bytep memory = cp->memory; png_size_t size = cp->size; if (memory != NULL && size >= need) { memcpy(out, memory, need); cp->memory = memory + need; cp->size = size - need; return; } png_error(png_ptr, "read beyond end of data"); } } png_error(png_ptr, "invalid memory read"); } } int PNGAPI png_image_begin_read_from_memory(png_imagep image, png_const_voidp memory, png_size_t size) { if (image != NULL && image->version == PNG_IMAGE_VERSION) { if (memory != NULL && size > 0) { if (png_image_read_init(image) != 0) { /* Now set the IO functions to read from the memory buffer and * store it into io_ptr. Again do this in-place to avoid calling a * libpng function that requires error handling. */ image->opaque->memory = png_voidcast(png_const_bytep, memory); image->opaque->size = size; image->opaque->png_ptr->io_ptr = image; image->opaque->png_ptr->read_data_fn = png_image_memory_read; return png_safe_execute(image, png_image_read_header, image); } } else return png_image_error(image, "png_image_begin_read_from_memory: invalid argument"); } else if (image != NULL) return png_image_error(image, "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); return 0; } /* Utility function to skip chunks that are not used by the simplified image * read functions and an appropriate macro to call it. */ #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED static void png_image_skip_unused_chunks(png_structrp png_ptr) { /* Prepare the reader to ignore all recognized chunks whose data will not * be used, i.e., all chunks recognized by libpng except for those * involved in basic image reading: * * IHDR, PLTE, IDAT, IEND * * Or image data handling: * * tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT. * * This provides a small performance improvement and eliminates any * potential vulnerability to security problems in the unused chunks. * * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored * too. This allows the simplified API to be compiled without iCCP support, * however if the support is there the chunk is still checked to detect * errors (which are unfortunately quite common.) */ { static PNG_CONST png_byte chunks_to_process[] = { 98, 75, 71, 68, '\0', /* bKGD */ 99, 72, 82, 77, '\0', /* cHRM */ 103, 65, 77, 65, '\0', /* gAMA */ # ifdef PNG_READ_iCCP_SUPPORTED 105, 67, 67, 80, '\0', /* iCCP */ # endif 115, 66, 73, 84, '\0', /* sBIT */ 115, 82, 71, 66, '\0', /* sRGB */ }; /* Ignore unknown chunks and all other chunks except for the * IHDR, PLTE, tRNS, IDAT, and IEND chunks. */ png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, NULL, -1); /* But do not ignore image data handling chunks */ png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT, chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5); } } # define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p) #else # define PNG_SKIP_CHUNKS(p) ((void)0) #endif /* HANDLE_AS_UNKNOWN */ /* The following macro gives the exact rounded answer for all values in the * range 0..255 (it actually divides by 51.2, but the rounding still generates * the correct numbers 0..5 */ #define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8) /* Utility functions to make particular color-maps */ static void set_file_encoding(png_image_read_control *display) { png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma; if (png_gamma_significant(g) != 0) { if (png_gamma_not_sRGB(g) != 0) { display->file_encoding = P_FILE; display->gamma_to_linear = png_reciprocal(g); } else display->file_encoding = P_sRGB; } else display->file_encoding = P_LINEAR8; } static unsigned int decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) { if (encoding == P_FILE) /* double check */ encoding = display->file_encoding; if (encoding == P_NOTSET) /* must be the file encoding */ { set_file_encoding(display); encoding = display->file_encoding; } switch (encoding) { case P_FILE: value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); break; case P_sRGB: value = png_sRGB_table[value]; break; case P_LINEAR: break; case P_LINEAR8: value *= 257; break; #ifdef __GNUC__ default: png_error(display->image->opaque->png_ptr, "unexpected encoding (internal error)"); #endif } return value; } static png_uint_32 png_colormap_compose(png_image_read_control *display, png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, png_uint_32 background, int encoding) { /* The file value is composed on the background, the background has the given * encoding and so does the result, the file is encoded with P_FILE and the * file and alpha are 8-bit values. The (output) encoding will always be * P_LINEAR or P_sRGB. */ png_uint_32 f = decode_gamma(display, foreground, foreground_encoding); png_uint_32 b = decode_gamma(display, background, encoding); /* The alpha is always an 8-bit value (it comes from the palette), the value * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires. */ f = f * alpha + b * (255-alpha); if (encoding == P_LINEAR) { /* Scale to 65535; divide by 255, approximately (in fact this is extremely * accurate, it divides by 255.00000005937181414556, with no overflow.) */ f *= 257; /* Now scaled by 65535 */ f += f >> 16; f = (f+32768) >> 16; } else /* P_sRGB */ f = PNG_sRGB_FROM_LINEAR(f); return f; } /* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must * be 8-bit. */ static void png_create_colormap_entry(png_image_read_control *display, png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, png_uint_32 alpha, int encoding) { png_imagep image = display->image; const int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ? P_LINEAR : P_sRGB; const int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && (red != green || green != blue); if (ip > 255) png_error(image->opaque->png_ptr, "color-map index out of range"); /* Update the cache with whether the file gamma is significantly different * from sRGB. */ if (encoding == P_FILE) { if (display->file_encoding == P_NOTSET) set_file_encoding(display); /* Note that the cached value may be P_FILE too, but if it is then the * gamma_to_linear member has been set. */ encoding = display->file_encoding; } if (encoding == P_FILE) { png_fixed_point g = display->gamma_to_linear; red = png_gamma_16bit_correct(red*257, g); green = png_gamma_16bit_correct(green*257, g); blue = png_gamma_16bit_correct(blue*257, g); if (convert_to_Y != 0 || output_encoding == P_LINEAR) { alpha *= 257; encoding = P_LINEAR; } else { red = PNG_sRGB_FROM_LINEAR(red * 255); green = PNG_sRGB_FROM_LINEAR(green * 255); blue = PNG_sRGB_FROM_LINEAR(blue * 255); encoding = P_sRGB; } } else if (encoding == P_LINEAR8) { /* This encoding occurs quite frequently in test cases because PngSuite * includes a gAMA 1.0 chunk with most images. */ red *= 257; green *= 257; blue *= 257; alpha *= 257; encoding = P_LINEAR; } else if (encoding == P_sRGB && (convert_to_Y != 0 || output_encoding == P_LINEAR)) { /* The values are 8-bit sRGB values, but must be converted to 16-bit * linear. */ red = png_sRGB_table[red]; green = png_sRGB_table[green]; blue = png_sRGB_table[blue]; alpha *= 257; encoding = P_LINEAR; } /* This is set if the color isn't gray but the output is. */ if (encoding == P_LINEAR) { if (convert_to_Y != 0) { /* NOTE: these values are copied from png_do_rgb_to_gray */ png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green + (png_uint_32)2366 * blue; if (output_encoding == P_LINEAR) y = (y + 16384) >> 15; else { /* y is scaled by 32768, we need it scaled by 255: */ y = (y + 128) >> 8; y *= 255; y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); alpha = PNG_DIV257(alpha); encoding = P_sRGB; } blue = red = green = y; } else if (output_encoding == P_sRGB) { red = PNG_sRGB_FROM_LINEAR(red * 255); green = PNG_sRGB_FROM_LINEAR(green * 255); blue = PNG_sRGB_FROM_LINEAR(blue * 255); alpha = PNG_DIV257(alpha); encoding = P_sRGB; } } if (encoding != output_encoding) png_error(image->opaque->png_ptr, "bad encoding (internal error)"); /* Store the value. */ { # ifdef PNG_FORMAT_AFIRST_SUPPORTED const int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; # else # define afirst 0 # endif # ifdef PNG_FORMAT_BGR_SUPPORTED const int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; # else # define bgr 0 # endif if (output_encoding == P_LINEAR) { png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap); entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); /* The linear 16-bit values must be pre-multiplied by the alpha channel * value, if less than 65535 (this is, effectively, composite on black * if the alpha channel is removed.) */ switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) { case 4: entry[afirst ? 0 : 3] = (png_uint_16)alpha; /* FALLTHROUGH */ case 3: if (alpha < 65535) { if (alpha > 0) { blue = (blue * alpha + 32767U)/65535U; green = (green * alpha + 32767U)/65535U; red = (red * alpha + 32767U)/65535U; } else red = green = blue = 0; } entry[afirst + (2 ^ bgr)] = (png_uint_16)blue; entry[afirst + 1] = (png_uint_16)green; entry[afirst + bgr] = (png_uint_16)red; break; case 2: entry[1 ^ afirst] = (png_uint_16)alpha; /* FALLTHROUGH */ case 1: if (alpha < 65535) { if (alpha > 0) green = (green * alpha + 32767U)/65535U; else green = 0; } entry[afirst] = (png_uint_16)green; break; default: break; } } else /* output encoding is P_sRGB */ { png_bytep entry = png_voidcast(png_bytep, display->colormap); entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format); switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format)) { case 4: entry[afirst ? 0 : 3] = (png_byte)alpha; /* FALLTHROUGH */ case 3: entry[afirst + (2 ^ bgr)] = (png_byte)blue; entry[afirst + 1] = (png_byte)green; entry[afirst + bgr] = (png_byte)red; break; case 2: entry[1 ^ afirst] = (png_byte)alpha; /* FALLTHROUGH */ case 1: entry[afirst] = (png_byte)green; break; default: break; } } # ifdef afirst # undef afirst # endif # ifdef bgr # undef bgr # endif } } static int make_gray_file_colormap(png_image_read_control *display) { unsigned int i; for (i=0; i<256; ++i) png_create_colormap_entry(display, i, i, i, i, 255, P_FILE); return (int)i; } static int make_gray_colormap(png_image_read_control *display) { unsigned int i; for (i=0; i<256; ++i) png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB); return (int)i; } #define PNG_GRAY_COLORMAP_ENTRIES 256 static int make_ga_colormap(png_image_read_control *display) { unsigned int i, a; /* Alpha is retained, the output will be a color-map with entries * selected by six levels of alpha. One transparent entry, 6 gray * levels for all the intermediate alpha values, leaving 230 entries * for the opaque grays. The color-map entries are the six values * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the * relevant entry. * * if (alpha > 229) // opaque * { * // The 231 entries are selected to make the math below work: * base = 0; * entry = (231 * gray + 128) >> 8; * } * else if (alpha < 26) // transparent * { * base = 231; * entry = 0; * } * else // partially opaque * { * base = 226 + 6 * PNG_DIV51(alpha); * entry = PNG_DIV51(gray); * } */ i = 0; while (i < 231) { unsigned int gray = (i * 256 + 115) / 231; png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB); } /* 255 is used here for the component values for consistency with the code * that undoes premultiplication in pngwrite.c. */ png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB); for (a=1; a<5; ++a) { unsigned int g; for (g=0; g<6; ++g) png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51, P_sRGB); } return (int)i; } #define PNG_GA_COLORMAP_ENTRIES 256 static int make_rgb_colormap(png_image_read_control *display) { unsigned int i, r; /* Build a 6x6x6 opaque RGB cube */ for (i=r=0; r<6; ++r) { unsigned int g; for (g=0; g<6; ++g) { unsigned int b; for (b=0; b<6; ++b) png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255, P_sRGB); } } return (int)i; } #define PNG_RGB_COLORMAP_ENTRIES 216 /* Return a palette index to the above palette given three 8-bit sRGB values. */ #define PNG_RGB_INDEX(r,g,b) \ ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b))) static int png_image_read_colormap(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, argument); const png_imagep image = display->image; const png_structrp png_ptr = image->opaque->png_ptr; const png_uint_32 output_format = image->format; const int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ? P_LINEAR : P_sRGB; unsigned int cmap_entries; unsigned int output_processing; /* Output processing option */ unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */ /* Background information; the background color and the index of this color * in the color-map if it exists (else 256). */ unsigned int background_index = 256; png_uint_32 back_r, back_g, back_b; /* Flags to accumulate things that need to be done to the input. */ int expand_tRNS = 0; /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is * very difficult to do, the results look awful, and it is difficult to see * what possible use it is because the application can't control the * color-map. */ if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 || png_ptr->num_trans > 0) /* alpha in input */ && ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */) { if (output_encoding == P_LINEAR) /* compose on black */ back_b = back_g = back_r = 0; else if (display->background == NULL /* no way to remove it */) png_error(png_ptr, "background color must be supplied to remove alpha/transparency"); /* Get a copy of the background color (this avoids repeating the checks * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the * output format. */ else { back_g = display->background->green; if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0) { back_r = display->background->red; back_b = display->background->blue; } else back_b = back_r = back_g; } } else if (output_encoding == P_LINEAR) back_b = back_r = back_g = 65535; else back_b = back_r = back_g = 255; /* Default the input file gamma if required - this is necessary because * libpng assumes that if no gamma information is present the data is in the * output format, but the simplified API deduces the gamma from the input * format. */ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0) { /* Do this directly, not using the png_colorspace functions, to ensure * that it happens even if the colorspace is invalid (though probably if * it is the setting will be ignored) Note that the same thing can be * achieved at the application interface with png_set_gAMA. */ if (png_ptr->bit_depth == 16 && (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR; else png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE; png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; } /* Decide what to do based on the PNG color type of the input data. The * utility function png_create_colormap_entry deals with most aspects of the * output transformations; this code works out how to produce bytes of * color-map entries from the original format. */ switch (png_ptr->color_type) { case PNG_COLOR_TYPE_GRAY: if (png_ptr->bit_depth <= 8) { /* There at most 256 colors in the output, regardless of * transparency. */ unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0; cmap_entries = 1U << png_ptr->bit_depth; if (cmap_entries > image->colormap_entries) png_error(png_ptr, "gray[8] color-map: too few entries"); step = 255 / (cmap_entries - 1); output_processing = PNG_CMAP_NONE; /* If there is a tRNS chunk then this either selects a transparent * value or, if the output has no alpha, the background color. */ if (png_ptr->num_trans > 0) { trans = png_ptr->trans_color.gray; if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) back_alpha = output_encoding == P_LINEAR ? 65535 : 255; } /* png_create_colormap_entry just takes an RGBA and writes the * corresponding color-map entry using the format from 'image', * including the required conversion to sRGB or linear as * appropriate. The input values are always either sRGB (if the * gamma correction flag is 0) or 0..255 scaled file encoded values * (if the function must gamma correct them). */ for (i=val=0; ibit_depth < 8) png_set_packing(png_ptr); } else /* bit depth is 16 */ { /* The 16-bit input values can be converted directly to 8-bit gamma * encoded values; however, if a tRNS chunk is present 257 color-map * entries are required. This means that the extra entry requires * special processing; add an alpha channel, sacrifice gray level * 254 and convert transparent (alpha==0) entries to that. * * Use libpng to chop the data to 8 bits. Convert it to sRGB at the * same time to minimize quality loss. If a tRNS chunk is present * this means libpng must handle it too; otherwise it is impossible * to do the exact match on the 16-bit value. * * If the output has no alpha channel *and* the background color is * gray then it is possible to let libpng handle the substitution by * ensuring that the corresponding gray level matches the background * color exactly. */ data_encoding = P_sRGB; if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "gray[16] color-map: too few entries"); cmap_entries = (unsigned int)make_gray_colormap(display); if (png_ptr->num_trans > 0) { unsigned int back_alpha; if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) back_alpha = 0; else { if (back_r == back_g && back_g == back_b) { /* Background is gray; no special processing will be * required. */ png_color_16 c; png_uint_32 gray = back_g; if (output_encoding == P_LINEAR) { gray = PNG_sRGB_FROM_LINEAR(gray * 255); /* And make sure the corresponding palette entry * matches. */ png_create_colormap_entry(display, gray, back_g, back_g, back_g, 65535, P_LINEAR); } /* The background passed to libpng, however, must be the * sRGB value. */ c.index = 0; /*unused*/ c.gray = c.red = c.green = c.blue = (png_uint_16)gray; /* NOTE: does this work without expanding tRNS to alpha? * It should be the color->gray case below apparently * doesn't. */ png_set_background_fixed(png_ptr, &c, PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, 0/*gamma: not used*/); output_processing = PNG_CMAP_NONE; break; } #ifdef __COVERITY__ /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) * here. */ back_alpha = 255; #else back_alpha = output_encoding == P_LINEAR ? 65535 : 255; #endif } /* output_processing means that the libpng-processed row will be * 8-bit GA and it has to be processing to single byte color-map * values. Entry 254 is replaced by either a completely * transparent entry or by the background color at full * precision (and the background color is not a simple gray * level in this case.) */ expand_tRNS = 1; output_processing = PNG_CMAP_TRANS; background_index = 254; /* And set (overwrite) color-map entry 254 to the actual * background color at full precision. */ png_create_colormap_entry(display, 254, back_r, back_g, back_b, back_alpha, output_encoding); } else output_processing = PNG_CMAP_NONE; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: /* 8-bit or 16-bit PNG with two channels - gray and alpha. A minimum * of 65536 combinations. If, however, the alpha channel is to be * removed there are only 256 possibilities if the background is gray. * (Otherwise there is a subset of the 65536 possibilities defined by * the triangle between black, white and the background color.) * * Reduce 16-bit files to 8-bit and sRGB encode the result. No need to * worry about tRNS matching - tRNS is ignored if there is an alpha * channel. */ data_encoding = P_sRGB; if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) { if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "gray+alpha color-map: too few entries"); cmap_entries = (unsigned int)make_ga_colormap(display); background_index = PNG_CMAP_GA_BACKGROUND; output_processing = PNG_CMAP_GA; } else /* alpha is removed */ { /* Alpha must be removed as the PNG data is processed when the * background is a color because the G and A channels are * independent and the vector addition (non-parallel vectors) is a * 2-D problem. * * This can be reduced to the same algorithm as above by making a * colormap containing gray levels (for the opaque grays), a * background entry (for a transparent pixel) and a set of four six * level color values, one set for each intermediate alpha value. * See the comments in make_ga_colormap for how this works in the * per-pixel processing. * * If the background is gray, however, we only need a 256 entry gray * level color map. It is sufficient to make the entry generated * for the background color be exactly the color specified. */ if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 || (back_r == back_g && back_g == back_b)) { /* Background is gray; no special processing will be required. */ png_color_16 c; png_uint_32 gray = back_g; if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "gray-alpha color-map: too few entries"); cmap_entries = (unsigned int)make_gray_colormap(display); if (output_encoding == P_LINEAR) { gray = PNG_sRGB_FROM_LINEAR(gray * 255); /* And make sure the corresponding palette entry matches. */ png_create_colormap_entry(display, gray, back_g, back_g, back_g, 65535, P_LINEAR); } /* The background passed to libpng, however, must be the sRGB * value. */ c.index = 0; /*unused*/ c.gray = c.red = c.green = c.blue = (png_uint_16)gray; png_set_background_fixed(png_ptr, &c, PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, 0/*gamma: not used*/); output_processing = PNG_CMAP_NONE; } else { png_uint_32 i, a; /* This is the same as png_make_ga_colormap, above, except that * the entries are all opaque. */ if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "ga-alpha color-map: too few entries"); i = 0; while (i < 231) { png_uint_32 gray = (i * 256 + 115) / 231; png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB); } /* NOTE: this preserves the full precision of the application * background color. */ background_index = i; png_create_colormap_entry(display, i++, back_r, back_g, back_b, #ifdef __COVERITY__ /* Coverity claims that output_encoding * cannot be 2 (P_LINEAR) here. */ 255U, #else output_encoding == P_LINEAR ? 65535U : 255U, #endif output_encoding); /* For non-opaque input composite on the sRGB background - this * requires inverting the encoding for each component. The input * is still converted to the sRGB encoding because this is a * reasonable approximate to the logarithmic curve of human * visual sensitivity, at least over the narrow range which PNG * represents. Consequently 'G' is always sRGB encoded, while * 'A' is linear. We need the linear background colors. */ if (output_encoding == P_sRGB) /* else already linear */ { /* This may produce a value not exactly matching the * background, but that's ok because these numbers are only * used when alpha != 0 */ back_r = png_sRGB_table[back_r]; back_g = png_sRGB_table[back_g]; back_b = png_sRGB_table[back_b]; } for (a=1; a<5; ++a) { unsigned int g; /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled * by an 8-bit alpha value (0..255). */ png_uint_32 alpha = 51 * a; png_uint_32 back_rx = (255-alpha) * back_r; png_uint_32 back_gx = (255-alpha) * back_g; png_uint_32 back_bx = (255-alpha) * back_b; for (g=0; g<6; ++g) { png_uint_32 gray = png_sRGB_table[g*51] * alpha; png_create_colormap_entry(display, i++, PNG_sRGB_FROM_LINEAR(gray + back_rx), PNG_sRGB_FROM_LINEAR(gray + back_gx), PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB); } } cmap_entries = i; output_processing = PNG_CMAP_GA; } } break; case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: /* Exclude the case where the output is gray; we can always handle this * with the cases above. */ if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0) { /* The color-map will be grayscale, so we may as well convert the * input RGB values to a simple grayscale and use the grayscale * code above. * * NOTE: calling this apparently damages the recognition of the * transparent color in background color handling; call * png_set_tRNS_to_alpha before png_set_background_fixed. */ png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1, -1); data_encoding = P_sRGB; /* The output will now be one or two 8-bit gray or gray+alpha * channels. The more complex case arises when the input has alpha. */ if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_ptr->num_trans > 0) && (output_format & PNG_FORMAT_FLAG_ALPHA) != 0) { /* Both input and output have an alpha channel, so no background * processing is required; just map the GA bytes to the right * color-map entry. */ expand_tRNS = 1; if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "rgb[ga] color-map: too few entries"); cmap_entries = (unsigned int)make_ga_colormap(display); background_index = PNG_CMAP_GA_BACKGROUND; output_processing = PNG_CMAP_GA; } else { /* Either the input or the output has no alpha channel, so there * will be no non-opaque pixels in the color-map; it will just be * grayscale. */ if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "rgb[gray] color-map: too few entries"); /* Ideally this code would use libpng to do the gamma correction, * but if an input alpha channel is to be removed we will hit the * libpng bug in gamma+compose+rgb-to-gray (the double gamma * correction bug). Fix this by dropping the gamma correction in * this case and doing it in the palette; this will result in * duplicate palette entries, but that's better than the * alternative of double gamma correction. */ if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_ptr->num_trans > 0) && png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0) { cmap_entries = (unsigned int)make_gray_file_colormap(display); data_encoding = P_FILE; } else cmap_entries = (unsigned int)make_gray_colormap(display); /* But if the input has alpha or transparency it must be removed */ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_ptr->num_trans > 0) { png_color_16 c; png_uint_32 gray = back_g; /* We need to ensure that the application background exists in * the colormap and that completely transparent pixels map to * it. Achieve this simply by ensuring that the entry * selected for the background really is the background color. */ if (data_encoding == P_FILE) /* from the fixup above */ { /* The app supplied a gray which is in output_encoding, we * need to convert it to a value of the input (P_FILE) * encoding then set this palette entry to the required * output encoding. */ if (output_encoding == P_sRGB) gray = png_sRGB_table[gray]; /* now P_LINEAR */ gray = PNG_DIV257(png_gamma_16bit_correct(gray, png_ptr->colorspace.gamma)); /* now P_FILE */ /* And make sure the corresponding palette entry contains * exactly the required sRGB value. */ png_create_colormap_entry(display, gray, back_g, back_g, back_g, 0/*unused*/, output_encoding); } else if (output_encoding == P_LINEAR) { gray = PNG_sRGB_FROM_LINEAR(gray * 255); /* And make sure the corresponding palette entry matches. */ png_create_colormap_entry(display, gray, back_g, back_g, back_g, 0/*unused*/, P_LINEAR); } /* The background passed to libpng, however, must be the * output (normally sRGB) value. */ c.index = 0; /*unused*/ c.gray = c.red = c.green = c.blue = (png_uint_16)gray; /* NOTE: the following is apparently a bug in libpng. Without * it the transparent color recognition in * png_set_background_fixed seems to go wrong. */ expand_tRNS = 1; png_set_background_fixed(png_ptr, &c, PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, 0/*gamma: not used*/); } output_processing = PNG_CMAP_NONE; } } else /* output is color */ { /* We could use png_quantize here so long as there is no transparent * color or alpha; png_quantize ignores alpha. Easier overall just * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube. * Consequently we always want libpng to produce sRGB data. */ data_encoding = P_sRGB; /* Is there any transparency or alpha? */ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_ptr->num_trans > 0) { /* Is there alpha in the output too? If so all four channels are * processed into a special RGB cube with alpha support. */ if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) { png_uint_32 r; if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) png_error(png_ptr, "rgb+alpha color-map: too few entries"); cmap_entries = (unsigned int)make_rgb_colormap(display); /* Add a transparent entry. */ png_create_colormap_entry(display, cmap_entries, 255, 255, 255, 0, P_sRGB); /* This is stored as the background index for the processing * algorithm. */ background_index = cmap_entries++; /* Add 27 r,g,b entries each with alpha 0.5. */ for (r=0; r<256; r = (r << 1) | 0x7f) { png_uint_32 g; for (g=0; g<256; g = (g << 1) | 0x7f) { png_uint_32 b; /* This generates components with the values 0, 127 and * 255 */ for (b=0; b<256; b = (b << 1) | 0x7f) png_create_colormap_entry(display, cmap_entries++, r, g, b, 128, P_sRGB); } } expand_tRNS = 1; output_processing = PNG_CMAP_RGB_ALPHA; } else { /* Alpha/transparency must be removed. The background must * exist in the color map (achieved by setting adding it after * the 666 color-map). If the standard processing code will * pick up this entry automatically that's all that is * required; libpng can be called to do the background * processing. */ unsigned int sample_size = PNG_IMAGE_SAMPLE_SIZE(output_format); png_uint_32 r, g, b; /* sRGB background */ if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) png_error(png_ptr, "rgb-alpha color-map: too few entries"); cmap_entries = (unsigned int)make_rgb_colormap(display); png_create_colormap_entry(display, cmap_entries, back_r, back_g, back_b, 0/*unused*/, output_encoding); if (output_encoding == P_LINEAR) { r = PNG_sRGB_FROM_LINEAR(back_r * 255); g = PNG_sRGB_FROM_LINEAR(back_g * 255); b = PNG_sRGB_FROM_LINEAR(back_b * 255); } else { r = back_r; g = back_g; b = back_g; } /* Compare the newly-created color-map entry with the one the * PNG_CMAP_RGB algorithm will use. If the two entries don't * match, add the new one and set this as the background * index. */ if (memcmp((png_const_bytep)display->colormap + sample_size * cmap_entries, (png_const_bytep)display->colormap + sample_size * PNG_RGB_INDEX(r,g,b), sample_size) != 0) { /* The background color must be added. */ background_index = cmap_entries++; /* Add 27 r,g,b entries each with created by composing with * the background at alpha 0.5. */ for (r=0; r<256; r = (r << 1) | 0x7f) { for (g=0; g<256; g = (g << 1) | 0x7f) { /* This generates components with the values 0, 127 * and 255 */ for (b=0; b<256; b = (b << 1) | 0x7f) png_create_colormap_entry(display, cmap_entries++, png_colormap_compose(display, r, P_sRGB, 128, back_r, output_encoding), png_colormap_compose(display, g, P_sRGB, 128, back_g, output_encoding), png_colormap_compose(display, b, P_sRGB, 128, back_b, output_encoding), 0/*unused*/, output_encoding); } } expand_tRNS = 1; output_processing = PNG_CMAP_RGB_ALPHA; } else /* background color is in the standard color-map */ { png_color_16 c; c.index = 0; /*unused*/ c.red = (png_uint_16)back_r; c.gray = c.green = (png_uint_16)back_g; c.blue = (png_uint_16)back_b; png_set_background_fixed(png_ptr, &c, PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, 0/*gamma: not used*/); output_processing = PNG_CMAP_RGB; } } } else /* no alpha or transparency in the input */ { /* Alpha in the output is irrelevant, simply map the opaque input * pixels to the 6x6x6 color-map. */ if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "rgb color-map: too few entries"); cmap_entries = (unsigned int)make_rgb_colormap(display); output_processing = PNG_CMAP_RGB; } } break; case PNG_COLOR_TYPE_PALETTE: /* It's already got a color-map. It may be necessary to eliminate the * tRNS entries though. */ { unsigned int num_trans = png_ptr->num_trans; png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL; png_const_colorp colormap = png_ptr->palette; const int do_background = trans != NULL && (output_format & PNG_FORMAT_FLAG_ALPHA) == 0; unsigned int i; /* Just in case: */ if (trans == NULL) num_trans = 0; output_processing = PNG_CMAP_NONE; data_encoding = P_FILE; /* Don't change from color-map indices */ cmap_entries = (unsigned int)png_ptr->num_palette; if (cmap_entries > 256) cmap_entries = 256; if (cmap_entries > (unsigned int)image->colormap_entries) png_error(png_ptr, "palette color-map: too few entries"); for (i=0; i < cmap_entries; ++i) { if (do_background != 0 && i < num_trans && trans[i] < 255) { if (trans[i] == 0) png_create_colormap_entry(display, i, back_r, back_g, back_b, 0, output_encoding); else { /* Must compose the PNG file color in the color-map entry * on the sRGB color in 'back'. */ png_create_colormap_entry(display, i, png_colormap_compose(display, colormap[i].red, P_FILE, trans[i], back_r, output_encoding), png_colormap_compose(display, colormap[i].green, P_FILE, trans[i], back_g, output_encoding), png_colormap_compose(display, colormap[i].blue, P_FILE, trans[i], back_b, output_encoding), output_encoding == P_LINEAR ? trans[i] * 257U : trans[i], output_encoding); } } else png_create_colormap_entry(display, i, colormap[i].red, colormap[i].green, colormap[i].blue, i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/); } /* The PNG data may have indices packed in fewer than 8 bits, it * must be expanded if so. */ if (png_ptr->bit_depth < 8) png_set_packing(png_ptr); } break; default: png_error(png_ptr, "invalid PNG color type"); /*NOT REACHED*/ } /* Now deal with the output processing */ if (expand_tRNS != 0 && png_ptr->num_trans > 0 && (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) png_set_tRNS_to_alpha(png_ptr); switch (data_encoding) { case P_sRGB: /* Change to 8-bit sRGB */ png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); /* FALLTHROUGH */ case P_FILE: if (png_ptr->bit_depth > 8) png_set_scale_16(png_ptr); break; #ifdef __GNUC__ default: png_error(png_ptr, "bad data option (internal error)"); #endif } if (cmap_entries > 256 || cmap_entries > image->colormap_entries) png_error(png_ptr, "color map overflow (BAD internal error)"); image->colormap_entries = cmap_entries; /* Double check using the recorded background index */ switch (output_processing) { case PNG_CMAP_NONE: if (background_index != PNG_CMAP_NONE_BACKGROUND) goto bad_background; break; case PNG_CMAP_GA: if (background_index != PNG_CMAP_GA_BACKGROUND) goto bad_background; break; case PNG_CMAP_TRANS: if (background_index >= cmap_entries || background_index != PNG_CMAP_TRANS_BACKGROUND) goto bad_background; break; case PNG_CMAP_RGB: if (background_index != PNG_CMAP_RGB_BACKGROUND) goto bad_background; break; case PNG_CMAP_RGB_ALPHA: if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND) goto bad_background; break; default: png_error(png_ptr, "bad processing option (internal error)"); bad_background: png_error(png_ptr, "bad background index (internal error)"); } display->colormap_processing = (int)output_processing; return 1/*ok*/; } /* The final part of the color-map read called from png_image_finish_read. */ static int png_image_read_and_map(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; int passes; /* Called when the libpng data must be transformed into the color-mapped * form. There is a local row buffer in display->local and this routine must * do the interlace handling. */ switch (png_ptr->interlaced) { case PNG_INTERLACE_NONE: passes = 1; break; case PNG_INTERLACE_ADAM7: passes = PNG_INTERLACE_ADAM7_PASSES; break; default: png_error(png_ptr, "unknown interlace type"); } { png_uint_32 height = image->height; png_uint_32 width = image->width; int proc = display->colormap_processing; png_bytep first_row = png_voidcast(png_bytep, display->first_row); ptrdiff_t step_row = display->row_bytes; int pass; for (pass = 0; pass < passes; ++pass) { unsigned int startx, stepx, stepy; png_uint_32 y; if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) { /* The row may be empty for a short image: */ if (PNG_PASS_COLS(width, pass) == 0) continue; startx = PNG_PASS_START_COL(pass); stepx = PNG_PASS_COL_OFFSET(pass); y = PNG_PASS_START_ROW(pass); stepy = PNG_PASS_ROW_OFFSET(pass); } else { y = 0; startx = 0; stepx = stepy = 1; } for (; ylocal_row); png_bytep outrow = first_row + y * step_row; png_const_bytep end_row = outrow + width; /* Read read the libpng data into the temporary buffer. */ png_read_row(png_ptr, inrow, NULL); /* Now process the row according to the processing option, note * that the caller verifies that the format of the libpng output * data is as required. */ outrow += startx; switch (proc) { case PNG_CMAP_GA: for (; outrow < end_row; outrow += stepx) { /* The data is always in the PNG order */ unsigned int gray = *inrow++; unsigned int alpha = *inrow++; unsigned int entry; /* NOTE: this code is copied as a comment in * make_ga_colormap above. Please update the * comment if you change this code! */ if (alpha > 229) /* opaque */ { entry = (231 * gray + 128) >> 8; } else if (alpha < 26) /* transparent */ { entry = 231; } else /* partially opaque */ { entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray); } *outrow = (png_byte)entry; } break; case PNG_CMAP_TRANS: for (; outrow < end_row; outrow += stepx) { png_byte gray = *inrow++; png_byte alpha = *inrow++; if (alpha == 0) *outrow = PNG_CMAP_TRANS_BACKGROUND; else if (gray != PNG_CMAP_TRANS_BACKGROUND) *outrow = gray; else *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1); } break; case PNG_CMAP_RGB: for (; outrow < end_row; outrow += stepx) { *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); inrow += 3; } break; case PNG_CMAP_RGB_ALPHA: for (; outrow < end_row; outrow += stepx) { unsigned int alpha = inrow[3]; /* Because the alpha entries only hold alpha==0.5 values * split the processing at alpha==0.25 (64) and 0.75 * (196). */ if (alpha >= 196) *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]); else if (alpha < 64) *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND; else { /* Likewise there are three entries for each of r, g * and b. We could select the entry by popcount on * the top two bits on those architectures that * support it, this is what the code below does, * crudely. */ unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1; /* Here are how the values map: * * 0x00 .. 0x3f -> 0 * 0x40 .. 0xbf -> 1 * 0xc0 .. 0xff -> 2 * * So, as above with the explicit alpha checks, the * breakpoints are at 64 and 196. */ if (inrow[0] & 0x80) back_i += 9; /* red */ if (inrow[0] & 0x40) back_i += 9; if (inrow[0] & 0x80) back_i += 3; /* green */ if (inrow[0] & 0x40) back_i += 3; if (inrow[0] & 0x80) back_i += 1; /* blue */ if (inrow[0] & 0x40) back_i += 1; *outrow = (png_byte)back_i; } inrow += 4; } break; default: break; } } } } return 1; } static int png_image_read_colormapped(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, argument); png_imagep image = display->image; png_controlp control = image->opaque; png_structrp png_ptr = control->png_ptr; png_inforp info_ptr = control->info_ptr; int passes = 0; /* As a flag */ PNG_SKIP_CHUNKS(png_ptr); /* Update the 'info' structure and make sure the result is as required; first * make sure to turn on the interlace handling if it will be required * (because it can't be turned on *after* the call to png_read_update_info!) */ if (display->colormap_processing == PNG_CMAP_NONE) passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); /* The expected output can be deduced from the colormap_processing option. */ switch (display->colormap_processing) { case PNG_CMAP_NONE: /* Output must be one channel and one byte per pixel, the output * encoding can be anything. */ if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE || info_ptr->color_type == PNG_COLOR_TYPE_GRAY) && info_ptr->bit_depth == 8) break; goto bad_output; case PNG_CMAP_TRANS: case PNG_CMAP_GA: /* Output must be two channels and the 'G' one must be sRGB, the latter * can be checked with an exact number because it should have been set * to this number above! */ if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && info_ptr->bit_depth == 8 && png_ptr->screen_gamma == PNG_GAMMA_sRGB && image->colormap_entries == 256) break; goto bad_output; case PNG_CMAP_RGB: /* Output must be 8-bit sRGB encoded RGB */ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB && info_ptr->bit_depth == 8 && png_ptr->screen_gamma == PNG_GAMMA_sRGB && image->colormap_entries == 216) break; goto bad_output; case PNG_CMAP_RGB_ALPHA: /* Output must be 8-bit sRGB encoded RGBA */ if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA && info_ptr->bit_depth == 8 && png_ptr->screen_gamma == PNG_GAMMA_sRGB && image->colormap_entries == 244 /* 216 + 1 + 27 */) break; goto bad_output; default: bad_output: png_error(png_ptr, "bad color-map processing (internal error)"); } /* Now read the rows. Do this here if it is possible to read directly into * the output buffer, otherwise allocate a local row buffer of the maximum * size libpng requires and call the relevant processing routine safely. */ { png_voidp first_row = display->buffer; ptrdiff_t row_bytes = display->row_stride; /* The following expression is designed to work correctly whether it gives * a signed or an unsigned result. */ if (row_bytes < 0) { char *ptr = png_voidcast(char*, first_row); ptr += (image->height-1) * (-row_bytes); first_row = png_voidcast(png_voidp, ptr); } display->first_row = first_row; display->row_bytes = row_bytes; } if (passes == 0) { int result; png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); display->local_row = row; result = png_safe_execute(image, png_image_read_and_map, display); display->local_row = NULL; png_free(png_ptr, row); return result; } else { png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes; while (--passes >= 0) { png_uint_32 y = image->height; png_bytep row = png_voidcast(png_bytep, display->first_row); for (; y > 0; --y) { png_read_row(png_ptr, row, NULL); row += row_bytes; } } return 1; } } /* Just the row reading part of png_image_read. */ static int png_image_read_composite(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; int passes; switch (png_ptr->interlaced) { case PNG_INTERLACE_NONE: passes = 1; break; case PNG_INTERLACE_ADAM7: passes = PNG_INTERLACE_ADAM7_PASSES; break; default: png_error(png_ptr, "unknown interlace type"); } { png_uint_32 height = image->height; png_uint_32 width = image->width; ptrdiff_t step_row = display->row_bytes; unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; int pass; for (pass = 0; pass < passes; ++pass) { unsigned int startx, stepx, stepy; png_uint_32 y; if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) { /* The row may be empty for a short image: */ if (PNG_PASS_COLS(width, pass) == 0) continue; startx = PNG_PASS_START_COL(pass) * channels; stepx = PNG_PASS_COL_OFFSET(pass) * channels; y = PNG_PASS_START_ROW(pass); stepy = PNG_PASS_ROW_OFFSET(pass); } else { y = 0; startx = 0; stepx = channels; stepy = 1; } for (; ylocal_row); png_bytep outrow; png_const_bytep end_row; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); outrow = png_voidcast(png_bytep, display->first_row); outrow += y * step_row; end_row = outrow + width * channels; /* Now do the composition on each pixel in this row. */ outrow += startx; for (; outrow < end_row; outrow += stepx) { png_byte alpha = inrow[channels]; if (alpha > 0) /* else no change to the output */ { unsigned int c; for (c=0; cimage; png_structrp png_ptr = image->opaque->png_ptr; png_inforp info_ptr = image->opaque->info_ptr; png_uint_32 height = image->height; png_uint_32 width = image->width; int pass, passes; /* Double check the convoluted logic below. We expect to get here with * libpng doing rgb to gray and gamma correction but background processing * left to the png_image_read_background function. The rows libpng produce * might be 8 or 16-bit but should always have two channels; gray plus alpha. */ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) png_error(png_ptr, "lost rgb to gray"); if ((png_ptr->transformations & PNG_COMPOSE) != 0) png_error(png_ptr, "unexpected compose"); if (png_get_channels(png_ptr, info_ptr) != 2) png_error(png_ptr, "lost/gained channels"); /* Expect the 8-bit case to always remove the alpha channel */ if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 && (image->format & PNG_FORMAT_FLAG_ALPHA) != 0) png_error(png_ptr, "unexpected 8-bit transformation"); switch (png_ptr->interlaced) { case PNG_INTERLACE_NONE: passes = 1; break; case PNG_INTERLACE_ADAM7: passes = PNG_INTERLACE_ADAM7_PASSES; break; default: png_error(png_ptr, "unknown interlace type"); } /* Use direct access to info_ptr here because otherwise the simplified API * would require PNG_EASY_ACCESS_SUPPORTED (just for this.) Note this is * checking the value after libpng expansions, not the original value in the * PNG. */ switch (info_ptr->bit_depth) { case 8: /* 8-bit sRGB gray values with an alpha channel; the alpha channel is * to be removed by composing on a background: either the row if * display->background is NULL or display->background->green if not. * Unlike the code above ALPHA_OPTIMIZED has *not* been done. */ { png_bytep first_row = png_voidcast(png_bytep, display->first_row); ptrdiff_t step_row = display->row_bytes; for (pass = 0; pass < passes; ++pass) { png_bytep row = png_voidcast(png_bytep, display->first_row); unsigned int startx, stepx, stepy; png_uint_32 y; if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) { /* The row may be empty for a short image: */ if (PNG_PASS_COLS(width, pass) == 0) continue; startx = PNG_PASS_START_COL(pass); stepx = PNG_PASS_COL_OFFSET(pass); y = PNG_PASS_START_ROW(pass); stepy = PNG_PASS_ROW_OFFSET(pass); } else { y = 0; startx = 0; stepx = stepy = 1; } if (display->background == NULL) { for (; ylocal_row); png_bytep outrow = first_row + y * step_row; png_const_bytep end_row = outrow + width; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); /* Now do the composition on each pixel in this row. */ outrow += startx; for (; outrow < end_row; outrow += stepx) { png_byte alpha = inrow[1]; if (alpha > 0) /* else no change to the output */ { png_uint_32 component = inrow[0]; if (alpha < 255) /* else just use component */ { /* Since PNG_OPTIMIZED_ALPHA was not set it is * necessary to invert the sRGB transfer * function and multiply the alpha out. */ component = png_sRGB_table[component] * alpha; component += png_sRGB_table[outrow[0]] * (255-alpha); component = PNG_sRGB_FROM_LINEAR(component); } outrow[0] = (png_byte)component; } inrow += 2; /* gray and alpha channel */ } } } else /* constant background value */ { png_byte background8 = display->background->green; png_uint_16 background = png_sRGB_table[background8]; for (; ylocal_row); png_bytep outrow = first_row + y * step_row; png_const_bytep end_row = outrow + width; /* Read the row, which is packed: */ png_read_row(png_ptr, inrow, NULL); /* Now do the composition on each pixel in this row. */ outrow += startx; for (; outrow < end_row; outrow += stepx) { png_byte alpha = inrow[1]; if (alpha > 0) /* else use background */ { png_uint_32 component = inrow[0]; if (alpha < 255) /* else just use component */ { component = png_sRGB_table[component] * alpha; component += background * (255-alpha); component = PNG_sRGB_FROM_LINEAR(component); } outrow[0] = (png_byte)component; } else outrow[0] = background8; inrow += 2; /* gray and alpha channel */ } row += display->row_bytes; } } } } break; case 16: /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must * still be done and, maybe, the alpha channel removed. This code also * handles the alpha-first option. */ { png_uint_16p first_row = png_voidcast(png_uint_16p, display->first_row); /* The division by two is safe because the caller passed in a * stride which was multiplied by 2 (below) to get row_bytes. */ ptrdiff_t step_row = display->row_bytes / 2; unsigned int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; unsigned int outchannels = 1U+preserve_alpha; int swap_alpha = 0; # ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED if (preserve_alpha != 0 && (image->format & PNG_FORMAT_FLAG_AFIRST) != 0) swap_alpha = 1; # endif for (pass = 0; pass < passes; ++pass) { unsigned int startx, stepx, stepy; png_uint_32 y; /* The 'x' start and step are adjusted to output components here. */ if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) { /* The row may be empty for a short image: */ if (PNG_PASS_COLS(width, pass) == 0) continue; startx = PNG_PASS_START_COL(pass) * outchannels; stepx = PNG_PASS_COL_OFFSET(pass) * outchannels; y = PNG_PASS_START_ROW(pass); stepy = PNG_PASS_ROW_OFFSET(pass); } else { y = 0; startx = 0; stepx = outchannels; stepy = 1; } for (; ylocal_row), NULL); inrow = png_voidcast(png_const_uint_16p, display->local_row); /* Now do the pre-multiplication on each pixel in this row. */ outrow += startx; for (; outrow < end_row; outrow += stepx) { png_uint_32 component = inrow[0]; png_uint_16 alpha = inrow[1]; if (alpha > 0) /* else 0 */ { if (alpha < 65535) /* else just use component */ { component *= alpha; component += 32767; component /= 65535; } } else component = 0; outrow[swap_alpha] = (png_uint_16)component; if (preserve_alpha != 0) outrow[1 ^ swap_alpha] = alpha; inrow += 2; /* components and alpha channel */ } } } } break; #ifdef __GNUC__ default: png_error(png_ptr, "unexpected bit depth"); #endif } return 1; } /* The guts of png_image_finish_read as a png_safe_execute callback. */ static int png_image_read_direct(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_inforp info_ptr = image->opaque->info_ptr; png_uint_32 format = image->format; int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; int do_local_compose = 0; int do_local_background = 0; /* to avoid double gamma correction bug */ int passes = 0; /* Add transforms to ensure the correct output format is produced then check * that the required implementation support is there. Always expand; always * need 8 bits minimum, no palette and expanded tRNS. */ png_set_expand(png_ptr); /* Now check the format to see if it was modified. */ { png_uint_32 base_format = png_image_format(png_ptr) & ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */; png_uint_32 change = format ^ base_format; png_fixed_point output_gamma; int mode; /* alpha mode */ /* Do this first so that we have a record if rgb to gray is happening. */ if ((change & PNG_FORMAT_FLAG_COLOR) != 0) { /* gray<->color transformation required. */ if ((format & PNG_FORMAT_FLAG_COLOR) != 0) png_set_gray_to_rgb(png_ptr); else { /* libpng can't do both rgb to gray and * background/pre-multiplication if there is also significant gamma * correction, because both operations require linear colors and * the code only supports one transform doing the gamma correction. * Handle this by doing the pre-multiplication or background * operation in this code, if necessary. * * TODO: fix this by rewriting pngrtran.c (!) * * For the moment (given that fixing this in pngrtran.c is an * enormous change) 'do_local_background' is used to indicate that * the problem exists. */ if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) do_local_background = 1/*maybe*/; png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); } change &= ~PNG_FORMAT_FLAG_COLOR; } /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise. */ { png_fixed_point input_gamma_default; if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 && (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) input_gamma_default = PNG_GAMMA_LINEAR; else input_gamma_default = PNG_DEFAULT_sRGB; /* Call png_set_alpha_mode to set the default for the input gamma; the * output gamma is set by a second call below. */ png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default); } if (linear != 0) { /* If there *is* an alpha channel in the input it must be multiplied * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG. */ if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) mode = PNG_ALPHA_STANDARD; /* associated alpha */ else mode = PNG_ALPHA_PNG; output_gamma = PNG_GAMMA_LINEAR; } else { mode = PNG_ALPHA_PNG; output_gamma = PNG_DEFAULT_sRGB; } if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) { mode = PNG_ALPHA_OPTIMIZED; change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA; } /* If 'do_local_background' is set check for the presence of gamma * correction; this is part of the work-round for the libpng bug * described above. * * TODO: fix libpng and remove this. */ if (do_local_background != 0) { png_fixed_point gtest; /* This is 'png_gamma_threshold' from pngrtran.c; the test used for * gamma correction, the screen gamma hasn't been set on png_struct * yet; it's set below. png_struct::gamma, however, is set to the * final value. */ if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma, PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0) do_local_background = 0; else if (mode == PNG_ALPHA_STANDARD) { do_local_background = 2/*required*/; mode = PNG_ALPHA_PNG; /* prevent libpng doing it */ } /* else leave as 1 for the checks below */ } /* If the bit-depth changes then handle that here. */ if ((change & PNG_FORMAT_FLAG_LINEAR) != 0) { if (linear != 0 /*16-bit output*/) png_set_expand_16(png_ptr); else /* 8-bit output */ png_set_scale_16(png_ptr); change &= ~PNG_FORMAT_FLAG_LINEAR; } /* Now the background/alpha channel changes. */ if ((change & PNG_FORMAT_FLAG_ALPHA) != 0) { /* Removing an alpha channel requires composition for the 8-bit * formats; for the 16-bit it is already done, above, by the * pre-multiplication and the channel just needs to be stripped. */ if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) { /* If RGB->gray is happening the alpha channel must be left and the * operation completed locally. * * TODO: fix libpng and remove this. */ if (do_local_background != 0) do_local_background = 2/*required*/; /* 16-bit output: just remove the channel */ else if (linear != 0) /* compose on black (well, pre-multiply) */ png_set_strip_alpha(png_ptr); /* 8-bit output: do an appropriate compose */ else if (display->background != NULL) { png_color_16 c; c.index = 0; /*unused*/ c.red = display->background->red; c.green = display->background->green; c.blue = display->background->blue; c.gray = display->background->green; /* This is always an 8-bit sRGB value, using the 'green' channel * for gray is much better than calculating the luminance here; * we can get off-by-one errors in that calculation relative to * the app expectations and that will show up in transparent * pixels. */ png_set_background_fixed(png_ptr, &c, PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, 0/*gamma: not used*/); } else /* compose on row: implemented below. */ { do_local_compose = 1; /* This leaves the alpha channel in the output, so it has to be * removed by the code below. Set the encoding to the 'OPTIMIZE' * one so the code only has to hack on the pixels that require * composition. */ mode = PNG_ALPHA_OPTIMIZED; } } else /* output needs an alpha channel */ { /* This is tricky because it happens before the swap operation has * been accomplished; however, the swap does *not* swap the added * alpha channel (weird API), so it must be added in the correct * place. */ png_uint_32 filler; /* opaque filler */ int where; if (linear != 0) filler = 65535; else filler = 255; #ifdef PNG_FORMAT_AFIRST_SUPPORTED if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) { where = PNG_FILLER_BEFORE; change &= ~PNG_FORMAT_FLAG_AFIRST; } else #endif where = PNG_FILLER_AFTER; png_set_add_alpha(png_ptr, filler, where); } /* This stops the (irrelevant) call to swap_alpha below. */ change &= ~PNG_FORMAT_FLAG_ALPHA; } /* Now set the alpha mode correctly; this is always done, even if there is * no alpha channel in either the input or the output because it correctly * sets the output gamma. */ png_set_alpha_mode_fixed(png_ptr, mode, output_gamma); # ifdef PNG_FORMAT_BGR_SUPPORTED if ((change & PNG_FORMAT_FLAG_BGR) != 0) { /* Check only the output format; PNG is never BGR; don't do this if * the output is gray, but fix up the 'format' value in that case. */ if ((format & PNG_FORMAT_FLAG_COLOR) != 0) png_set_bgr(png_ptr); else format &= ~PNG_FORMAT_FLAG_BGR; change &= ~PNG_FORMAT_FLAG_BGR; } # endif # ifdef PNG_FORMAT_AFIRST_SUPPORTED if ((change & PNG_FORMAT_FLAG_AFIRST) != 0) { /* Only relevant if there is an alpha channel - it's particularly * important to handle this correctly because do_local_compose may * be set above and then libpng will keep the alpha channel for this * code to remove. */ if ((format & PNG_FORMAT_FLAG_ALPHA) != 0) { /* Disable this if doing a local background, * TODO: remove this when local background is no longer required. */ if (do_local_background != 2) png_set_swap_alpha(png_ptr); } else format &= ~PNG_FORMAT_FLAG_AFIRST; change &= ~PNG_FORMAT_FLAG_AFIRST; } # endif /* If the *output* is 16-bit then we need to check for a byte-swap on this * architecture. */ if (linear != 0) { PNG_CONST png_uint_16 le = 0x0001; if ((*(png_const_bytep) & le) != 0) png_set_swap(png_ptr); } /* If change is not now 0 some transformation is missing - error out. */ if (change != 0) png_error(png_ptr, "png_read_image: unsupported transformation"); } PNG_SKIP_CHUNKS(png_ptr); /* Update the 'info' structure and make sure the result is as required; first * make sure to turn on the interlace handling if it will be required * (because it can't be turned on *after* the call to png_read_update_info!) * * TODO: remove the do_local_background fixup below. */ if (do_local_compose == 0 && do_local_background != 2) passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); { png_uint_32 info_format = 0; if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_format |= PNG_FORMAT_FLAG_COLOR; if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) { /* do_local_compose removes this channel below. */ if (do_local_compose == 0) { /* do_local_background does the same if required. */ if (do_local_background != 2 || (format & PNG_FORMAT_FLAG_ALPHA) != 0) info_format |= PNG_FORMAT_FLAG_ALPHA; } } else if (do_local_compose != 0) /* internal error */ png_error(png_ptr, "png_image_read: alpha channel lost"); if ((format & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) { info_format |= PNG_FORMAT_FLAG_ASSOCIATED_ALPHA; } if (info_ptr->bit_depth == 16) info_format |= PNG_FORMAT_FLAG_LINEAR; #ifdef PNG_FORMAT_BGR_SUPPORTED if ((png_ptr->transformations & PNG_BGR) != 0) info_format |= PNG_FORMAT_FLAG_BGR; #endif #ifdef PNG_FORMAT_AFIRST_SUPPORTED if (do_local_background == 2) { if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) info_format |= PNG_FORMAT_FLAG_AFIRST; } if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 || ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 && (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0)) { if (do_local_background == 2) png_error(png_ptr, "unexpected alpha swap transformation"); info_format |= PNG_FORMAT_FLAG_AFIRST; } # endif /* This is actually an internal error. */ if (info_format != format) png_error(png_ptr, "png_read_image: invalid transformations"); } /* Now read the rows. If do_local_compose is set then it is necessary to use * a local row buffer. The output will be GA, RGBA or BGRA and must be * converted to G, RGB or BGR as appropriate. The 'local_row' member of the * display acts as a flag. */ { png_voidp first_row = display->buffer; ptrdiff_t row_bytes = display->row_stride; if (linear != 0) row_bytes *= 2; /* The following expression is designed to work correctly whether it gives * a signed or an unsigned result. */ if (row_bytes < 0) { char *ptr = png_voidcast(char*, first_row); ptr += (image->height-1) * (-row_bytes); first_row = png_voidcast(png_voidp, ptr); } display->first_row = first_row; display->row_bytes = row_bytes; } if (do_local_compose != 0) { int result; png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); display->local_row = row; result = png_safe_execute(image, png_image_read_composite, display); display->local_row = NULL; png_free(png_ptr, row); return result; } else if (do_local_background == 2) { int result; png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); display->local_row = row; result = png_safe_execute(image, png_image_read_background, display); display->local_row = NULL; png_free(png_ptr, row); return result; } else { png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes; while (--passes >= 0) { png_uint_32 y = image->height; png_bytep row = png_voidcast(png_bytep, display->first_row); for (; y > 0; --y) { png_read_row(png_ptr, row, NULL); row += row_bytes; } } return 1; } } int PNGAPI png_image_finish_read(png_imagep image, png_const_colorp background, void *buffer, png_int_32 row_stride, void *colormap) { if (image != NULL && image->version == PNG_IMAGE_VERSION) { /* Check for row_stride overflow. This check is not performed on the * original PNG format because it may not occur in the output PNG format * and libpng deals with the issues of reading the original. */ const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); /* The following checks just the 'row_stride' calculation to ensure it * fits in a signed 32-bit value. Because channels/components can be * either 1 or 2 bytes in size the length of a row can still overflow 32 * bits; this is just to verify that the 'row_stride' argument can be * represented. */ if (image->width <= 0x7fffffffU/channels) /* no overflow */ { png_uint_32 check; const png_uint_32 png_row_stride = image->width * channels; if (row_stride == 0) row_stride = (png_int_32)/*SAFE*/png_row_stride; if (row_stride < 0) check = (png_uint_32)(-row_stride); else check = (png_uint_32)row_stride; /* This verifies 'check', the absolute value of the actual stride * passed in and detects overflow in the application calculation (i.e. * if the app did actually pass in a non-zero 'row_stride'. */ if (image->opaque != NULL && buffer != NULL && check >= png_row_stride) { /* Now check for overflow of the image buffer calculation; this * limits the whole image size to 32 bits for API compatibility with * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. * * The PNG_IMAGE_BUFFER_SIZE macro is: * * (PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)*height*(row_stride)) * * And the component size is always 1 or 2, so make sure that the * number of *bytes* that the application is saying are available * does actually fit into a 32-bit number. * * NOTE: this will be changed in 1.7 because PNG_IMAGE_BUFFER_SIZE * will be changed to use png_alloc_size_t; bigger images can be * accomodated on 64-bit systems. */ if (image->height <= 0xffffffffU/PNG_IMAGE_PIXEL_COMPONENT_SIZE(image->format)/check) { if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || (image->colormap_entries > 0 && colormap != NULL)) { int result; png_image_read_control display; memset(&display, 0, (sizeof display)); display.image = image; display.buffer = buffer; display.row_stride = row_stride; display.colormap = colormap; display.background = background; display.local_row = NULL; /* Choose the correct 'end' routine; for the color-map case * all the setup has already been done. */ if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) result = png_safe_execute(image, png_image_read_colormap, &display) && png_safe_execute(image, png_image_read_colormapped, &display); else result = png_safe_execute(image, png_image_read_direct, &display); png_image_free(image); return result; } else return png_image_error(image, "png_image_finish_read[color-map]: no color-map"); } else return png_image_error(image, "png_image_finish_read: image too large"); } else return png_image_error(image, "png_image_finish_read: invalid argument"); } else return png_image_error(image, "png_image_finish_read: row_stride too large"); } else if (image != NULL) return png_image_error(image, "png_image_finish_read: damaged PNG_IMAGE_VERSION"); return 0; } #endif /* SIMPLIFIED_READ */ #endif /* READ */ stella-5.1.1/src/libpng/pngrio.c000066400000000000000000000075641324334165500165300ustar00rootroot00000000000000 /* pngrio.c - functions for data input * * Last changed in libpng 1.6.24 [August 4, 2016] * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * This file provides a location for all input. Users who need * special handling are expected to write a function that has the same * arguments as this and performs a similar function, but that possibly * has a different input method. Note that you shouldn't change this * function, but rather write a replacement function and then make * libpng use it at run time with png_set_read_fn(...). */ #include "pngpriv.h" #ifdef PNG_READ_SUPPORTED /* Read the data from whatever input you are using. The default routine * reads from a file pointer. Note that this routine sometimes gets called * with very small lengths, so you should implement some kind of simple * buffering if you are using unbuffered reads. This should never be asked * to read more than 64K on a 16-bit machine. */ void /* PRIVATE */ png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length) { png_debug1(4, "reading %d bytes", (int)length); if (png_ptr->read_data_fn != NULL) (*(png_ptr->read_data_fn))(png_ptr, data, length); else png_error(png_ptr, "Call to NULL read function"); } #ifdef PNG_STDIO_SUPPORTED /* This is the function that does the actual reading of data. If you are * not reading from a standard C stream, you should create a replacement * read_data function and use it at run time with png_set_read_fn(), rather * than changing the library. */ void PNGCBAPI png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { png_size_t check; if (png_ptr == NULL) return; /* fread() returns 0 on error, so it is OK to store this in a png_size_t * instead of an int, which is what fread() actually returns. */ check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr)); if (check != length) png_error(png_ptr, "Read Error"); } #endif /* This function allows the application to supply a new input function * for libpng if standard C streams aren't being used. * * This function takes as its arguments: * * png_ptr - pointer to a png input data structure * * io_ptr - pointer to user supplied structure containing info about * the input functions. May be NULL. * * read_data_fn - pointer to a new input function that takes as its * arguments a pointer to a png_struct, a pointer to * a location where input data can be stored, and a 32-bit * unsigned int that is the number of bytes to be read. * To exit and output any fatal error messages the new write * function should call png_error(png_ptr, "Error msg"). * May be NULL, in which case libpng's default function will * be used. */ void PNGAPI png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn) { if (png_ptr == NULL) return; png_ptr->io_ptr = io_ptr; #ifdef PNG_STDIO_SUPPORTED if (read_data_fn != NULL) png_ptr->read_data_fn = read_data_fn; else png_ptr->read_data_fn = png_default_read_data; #else png_ptr->read_data_fn = read_data_fn; #endif #ifdef PNG_WRITE_SUPPORTED /* It is an error to write to a read device */ if (png_ptr->write_data_fn != NULL) { png_ptr->write_data_fn = NULL; png_warning(png_ptr, "Can't set both read_data_fn and write_data_fn in the" " same structure"); } #endif #ifdef PNG_WRITE_FLUSH_SUPPORTED png_ptr->output_flush_fn = NULL; #endif } #endif /* READ */ stella-5.1.1/src/libpng/pngrtran.c000066400000000000000000005120321324334165500170540ustar00rootroot00000000000000 /* pngrtran.c - transforms the data in a row for PNG readers * * Last changed in libpng 1.6.33 [September 28, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * This file contains functions optionally called by an application * in order to tell libpng how to handle data when reading a PNG. * Transformations that are used in both reading and writing are * in pngtrans.c. */ #include "pngpriv.h" #ifdef PNG_READ_SUPPORTED /* Set the action on getting a CRC error for an ancillary or critical chunk. */ void PNGAPI png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) { png_debug(1, "in png_set_crc_action"); if (png_ptr == NULL) return; /* Tell libpng how we react to CRC errors in critical chunks */ switch (crit_action) { case PNG_CRC_NO_CHANGE: /* Leave setting as is */ break; case PNG_CRC_WARN_USE: /* Warn/use data */ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; break; case PNG_CRC_QUIET_USE: /* Quiet/use data */ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | PNG_FLAG_CRC_CRITICAL_IGNORE; break; case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ png_warning(png_ptr, "Can't discard critical data on CRC error"); /* FALLTHROUGH */ case PNG_CRC_ERROR_QUIT: /* Error/quit */ case PNG_CRC_DEFAULT: default: png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK; break; } /* Tell libpng how we react to CRC errors in ancillary chunks */ switch (ancil_action) { case PNG_CRC_NO_CHANGE: /* Leave setting as is */ break; case PNG_CRC_WARN_USE: /* Warn/use data */ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; break; case PNG_CRC_QUIET_USE: /* Quiet/use data */ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN; break; case PNG_CRC_ERROR_QUIT: /* Error/quit */ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; break; case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ case PNG_CRC_DEFAULT: default: png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK; break; } } #ifdef PNG_READ_TRANSFORMS_SUPPORTED /* Is it OK to set a transformation now? Only if png_start_read_image or * png_read_update_info have not been called. It is not necessary for the IHDR * to have been read in all cases; the need_IHDR parameter allows for this * check too. */ static int png_rtran_ok(png_structrp png_ptr, int need_IHDR) { if (png_ptr != NULL) { if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) png_app_error(png_ptr, "invalid after png_start_read_image or png_read_update_info"); else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0) png_app_error(png_ptr, "invalid before the PNG header has been read"); else { /* Turn on failure to initialize correctly for all transforms. */ png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; return 1; /* Ok */ } } return 0; /* no png_error possible! */ } #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED /* Handle alpha and tRNS via a background color */ void PNGFAPI png_set_background_fixed(png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, png_fixed_point background_gamma) { png_debug(1, "in png_set_background_fixed"); if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL) return; if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) { png_warning(png_ptr, "Application must supply a known background gamma"); return; } png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA; png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; png_ptr->background = *background_color; png_ptr->background_gamma = background_gamma; png_ptr->background_gamma_type = (png_byte)(background_gamma_code); if (need_expand != 0) png_ptr->transformations |= PNG_BACKGROUND_EXPAND; else png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_background(png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma) { png_set_background_fixed(png_ptr, background_color, background_gamma_code, need_expand, png_fixed(png_ptr, background_gamma, "png_set_background")); } # endif /* FLOATING_POINT */ #endif /* READ_BACKGROUND */ /* Scale 16-bit depth files to 8-bit depth. If both of these are set then the * one that pngrtran does first (scale) happens. This is necessary to allow the * TRANSFORM and API behavior to be somewhat consistent, and it's simpler. */ #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED void PNGAPI png_set_scale_16(png_structrp png_ptr) { png_debug(1, "in png_set_scale_16"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_SCALE_16_TO_8; } #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* Chop 16-bit depth files to 8-bit depth */ void PNGAPI png_set_strip_16(png_structrp png_ptr) { png_debug(1, "in png_set_strip_16"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_16_TO_8; } #endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED void PNGAPI png_set_strip_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_strip_alpha"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_STRIP_ALPHA; } #endif #if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) static png_fixed_point translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma, int is_screen) { /* Check for flag values. The main reason for having the old Mac value as a * flag is that it is pretty near impossible to work out what the correct * value is from Apple documentation - a working Mac system is needed to * discover the value! */ if (output_gamma == PNG_DEFAULT_sRGB || output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB) { /* If there is no sRGB support this just sets the gamma to the standard * sRGB value. (This is a side effect of using this function!) */ # ifdef PNG_READ_sRGB_SUPPORTED png_ptr->flags |= PNG_FLAG_ASSUME_sRGB; # else PNG_UNUSED(png_ptr) # endif if (is_screen != 0) output_gamma = PNG_GAMMA_sRGB; else output_gamma = PNG_GAMMA_sRGB_INVERSE; } else if (output_gamma == PNG_GAMMA_MAC_18 || output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) { if (is_screen != 0) output_gamma = PNG_GAMMA_MAC_OLD; else output_gamma = PNG_GAMMA_MAC_INVERSE; } return output_gamma; } # ifdef PNG_FLOATING_POINT_SUPPORTED static png_fixed_point convert_gamma_value(png_structrp png_ptr, double output_gamma) { /* The following silently ignores cases where fixed point (times 100,000) * gamma values are passed to the floating point API. This is safe and it * means the fixed point constants work just fine with the floating point * API. The alternative would just lead to undetected errors and spurious * bug reports. Negative values fail inside the _fixed API unless they * correspond to the flag values. */ if (output_gamma > 0 && output_gamma < 128) output_gamma *= PNG_FP_1; /* This preserves -1 and -2 exactly: */ output_gamma = floor(output_gamma + .5); if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN) png_fixed_error(png_ptr, "gamma value"); return (png_fixed_point)output_gamma; } # endif #endif /* READ_ALPHA_MODE || READ_GAMMA */ #ifdef PNG_READ_ALPHA_MODE_SUPPORTED void PNGFAPI png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, png_fixed_point output_gamma) { int compose = 0; png_fixed_point file_gamma; png_debug(1, "in png_set_alpha_mode"); if (png_rtran_ok(png_ptr, 0) == 0) return; output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); /* Validate the value to ensure it is in a reasonable range. The value * is expected to be 1 or greater, but this range test allows for some * viewing correction values. The intent is to weed out users of this API * who use the inverse of the gamma value accidentally! Since some of these * values are reasonable this may have to be changed: * * 1.6.x: changed from 0.07..3 to 0.01..100 (to accomodate the optimal 16-bit * gamma of 36, and its reciprocal.) */ if (output_gamma < 1000 || output_gamma > 10000000) png_error(png_ptr, "output gamma out of expected range"); /* The default file gamma is the inverse of the output gamma; the output * gamma may be changed below so get the file value first: */ file_gamma = png_reciprocal(output_gamma); /* There are really 8 possibilities here, composed of any combination * of: * * premultiply the color channels * do not encode non-opaque pixels * encode the alpha as well as the color channels * * The differences disappear if the input/output ('screen') gamma is 1.0, * because then the encoding is a no-op and there is only the choice of * premultiplying the color channels or not. * * png_set_alpha_mode and png_set_background interact because both use * png_compose to do the work. Calling both is only useful when * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along * with a default gamma value. Otherwise PNG_COMPOSE must not be set. */ switch (mode) { case PNG_ALPHA_PNG: /* default: png standard */ /* No compose, but it may be set by png_set_background! */ png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; break; case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ compose = 1; png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; /* The output is linear: */ output_gamma = PNG_FP_1; break; case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */ compose = 1; png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA; /* output_gamma records the encoding of opaque pixels! */ break; case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */ compose = 1; png_ptr->transformations |= PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; break; default: png_error(png_ptr, "invalid alpha mode"); } /* Only set the default gamma if the file gamma has not been set (this has * the side effect that the gamma in a second call to png_set_alpha_mode will * be ignored.) */ if (png_ptr->colorspace.gamma == 0) { png_ptr->colorspace.gamma = file_gamma; png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; } /* But always set the output gamma: */ png_ptr->screen_gamma = output_gamma; /* Finally, if pre-multiplying, set the background fields to achieve the * desired result. */ if (compose != 0) { /* And obtain alpha pre-multiplication by composing on black: */ memset(&png_ptr->background, 0, (sizeof png_ptr->background)); png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */ png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; if ((png_ptr->transformations & PNG_COMPOSE) != 0) png_error(png_ptr, "conflicting calls to set alpha mode and background"); png_ptr->transformations |= PNG_COMPOSE; } } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) { png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, output_gamma)); } # endif #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED /* Dither file to 8-bit. Supply a palette, the current number * of elements in the palette, the maximum number of elements * allowed, and a histogram if possible. If the current number * of colors is greater than the maximum number, the palette will be * modified to fit in the maximum number. "full_quantize" indicates * whether we need a quantizing cube set up for RGB images, or if we * simply are reducing the number of colors in a paletted image. */ typedef struct png_dsort_struct { struct png_dsort_struct * next; png_byte left; png_byte right; } png_dsort; typedef png_dsort * png_dsortp; typedef png_dsort * * png_dsortpp; void PNGAPI png_set_quantize(png_structrp png_ptr, png_colorp palette, int num_palette, int maximum_colors, png_const_uint_16p histogram, int full_quantize) { png_debug(1, "in png_set_quantize"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_QUANTIZE; if (full_quantize == 0) { int i; png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte)))); for (i = 0; i < num_palette; i++) png_ptr->quantize_index[i] = (png_byte)i; } if (num_palette > maximum_colors) { if (histogram != NULL) { /* This is easy enough, just throw out the least used colors. * Perhaps not the best solution, but good enough. */ int i; /* Initialize an array to sort colors */ png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte)))); /* Initialize the quantize_sort array */ for (i = 0; i < num_palette; i++) png_ptr->quantize_sort[i] = (png_byte)i; /* Find the least used palette entries by starting a * bubble sort, and running it until we have sorted * out enough colors. Note that we don't care about * sorting all the colors, just finding which are * least used. */ for (i = num_palette - 1; i >= maximum_colors; i--) { int done; /* To stop early if the list is pre-sorted */ int j; done = 1; for (j = 0; j < i; j++) { if (histogram[png_ptr->quantize_sort[j]] < histogram[png_ptr->quantize_sort[j + 1]]) { png_byte t; t = png_ptr->quantize_sort[j]; png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1]; png_ptr->quantize_sort[j + 1] = t; done = 0; } } if (done != 0) break; } /* Swap the palette around, and set up a table, if necessary */ if (full_quantize != 0) { int j = num_palette; /* Put all the useful colors within the max, but don't * move the others. */ for (i = 0; i < maximum_colors; i++) { if ((int)png_ptr->quantize_sort[i] >= maximum_colors) { do j--; while ((int)png_ptr->quantize_sort[j] >= maximum_colors); palette[i] = palette[j]; } } } else { int j = num_palette; /* Move all the used colors inside the max limit, and * develop a translation table. */ for (i = 0; i < maximum_colors; i++) { /* Only move the colors we need to */ if ((int)png_ptr->quantize_sort[i] >= maximum_colors) { png_color tmp_color; do j--; while ((int)png_ptr->quantize_sort[j] >= maximum_colors); tmp_color = palette[j]; palette[j] = palette[i]; palette[i] = tmp_color; /* Indicate where the color went */ png_ptr->quantize_index[j] = (png_byte)i; png_ptr->quantize_index[i] = (png_byte)j; } } /* Find closest color for those colors we are not using */ for (i = 0; i < num_palette; i++) { if ((int)png_ptr->quantize_index[i] >= maximum_colors) { int min_d, k, min_k, d_index; /* Find the closest color to one we threw out */ d_index = png_ptr->quantize_index[i]; min_d = PNG_COLOR_DIST(palette[d_index], palette[0]); for (k = 1, min_k = 0; k < maximum_colors; k++) { int d; d = PNG_COLOR_DIST(palette[d_index], palette[k]); if (d < min_d) { min_d = d; min_k = k; } } /* Point to closest color */ png_ptr->quantize_index[i] = (png_byte)min_k; } } } png_free(png_ptr, png_ptr->quantize_sort); png_ptr->quantize_sort = NULL; } else { /* This is much harder to do simply (and quickly). Perhaps * we need to go through a median cut routine, but those * don't always behave themselves with only a few colors * as input. So we will just find the closest two colors, * and throw out one of them (chosen somewhat randomly). * [We don't understand this at all, so if someone wants to * work on improving it, be our guest - AED, GRP] */ int i; int max_d; int num_new_palette; png_dsortp t; png_dsortpp hash; t = NULL; /* Initialize palette index arrays */ png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte)))); png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)((png_uint_32)num_palette * (sizeof (png_byte)))); /* Initialize the sort array */ for (i = 0; i < num_palette; i++) { png_ptr->index_to_palette[i] = (png_byte)i; png_ptr->palette_to_index[i] = (png_byte)i; } hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 * (sizeof (png_dsortp)))); num_new_palette = num_palette; /* Initial wild guess at how far apart the farthest pixel * pair we will be eliminating will be. Larger * numbers mean more areas will be allocated, Smaller * numbers run the risk of not saving enough data, and * having to do this all over again. * * I have not done extensive checking on this number. */ max_d = 96; while (num_new_palette > maximum_colors) { for (i = 0; i < num_new_palette - 1; i++) { int j; for (j = i + 1; j < num_new_palette; j++) { int d; d = PNG_COLOR_DIST(palette[i], palette[j]); if (d <= max_d) { t = (png_dsortp)png_malloc_warn(png_ptr, (png_alloc_size_t)(sizeof (png_dsort))); if (t == NULL) break; t->next = hash[d]; t->left = (png_byte)i; t->right = (png_byte)j; hash[d] = t; } } if (t == NULL) break; } if (t != NULL) for (i = 0; i <= max_d; i++) { if (hash[i] != NULL) { png_dsortp p; for (p = hash[i]; p; p = p->next) { if ((int)png_ptr->index_to_palette[p->left] < num_new_palette && (int)png_ptr->index_to_palette[p->right] < num_new_palette) { int j, next_j; if (num_new_palette & 0x01) { j = p->left; next_j = p->right; } else { j = p->right; next_j = p->left; } num_new_palette--; palette[png_ptr->index_to_palette[j]] = palette[num_new_palette]; if (full_quantize == 0) { int k; for (k = 0; k < num_palette; k++) { if (png_ptr->quantize_index[k] == png_ptr->index_to_palette[j]) png_ptr->quantize_index[k] = png_ptr->index_to_palette[next_j]; if ((int)png_ptr->quantize_index[k] == num_new_palette) png_ptr->quantize_index[k] = png_ptr->index_to_palette[j]; } } png_ptr->index_to_palette[png_ptr->palette_to_index [num_new_palette]] = png_ptr->index_to_palette[j]; png_ptr->palette_to_index[png_ptr->index_to_palette[j]] = png_ptr->palette_to_index[num_new_palette]; png_ptr->index_to_palette[j] = (png_byte)num_new_palette; png_ptr->palette_to_index[num_new_palette] = (png_byte)j; } if (num_new_palette <= maximum_colors) break; } if (num_new_palette <= maximum_colors) break; } } for (i = 0; i < 769; i++) { if (hash[i] != NULL) { png_dsortp p = hash[i]; while (p) { t = p->next; png_free(png_ptr, p); p = t; } } hash[i] = 0; } max_d += 96; } png_free(png_ptr, hash); png_free(png_ptr, png_ptr->palette_to_index); png_free(png_ptr, png_ptr->index_to_palette); png_ptr->palette_to_index = NULL; png_ptr->index_to_palette = NULL; } num_palette = maximum_colors; } if (png_ptr->palette == NULL) { png_ptr->palette = palette; } png_ptr->num_palette = (png_uint_16)num_palette; if (full_quantize != 0) { int i; png_bytep distance; int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS; int num_red = (1 << PNG_QUANTIZE_RED_BITS); int num_green = (1 << PNG_QUANTIZE_GREEN_BITS); int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS); png_size_t num_entries = ((png_size_t)1 << total_bits); png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr, (png_alloc_size_t)(num_entries * (sizeof (png_byte)))); distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)(num_entries * (sizeof (png_byte)))); memset(distance, 0xff, num_entries * (sizeof (png_byte))); for (i = 0; i < num_palette; i++) { int ir, ig, ib; int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS)); int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS)); int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS)); for (ir = 0; ir < num_red; ir++) { /* int dr = abs(ir - r); */ int dr = ((ir > r) ? ir - r : r - ir); int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS + PNG_QUANTIZE_GREEN_BITS)); for (ig = 0; ig < num_green; ig++) { /* int dg = abs(ig - g); */ int dg = ((ig > g) ? ig - g : g - ig); int dt = dr + dg; int dm = ((dr > dg) ? dr : dg); int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS); for (ib = 0; ib < num_blue; ib++) { int d_index = index_g | ib; /* int db = abs(ib - b); */ int db = ((ib > b) ? ib - b : b - ib); int dmax = ((dm > db) ? dm : db); int d = dmax + dt + db; if (d < (int)distance[d_index]) { distance[d_index] = (png_byte)d; png_ptr->palette_lookup[d_index] = (png_byte)i; } } } } } png_free(png_ptr, distance); } } #endif /* READ_QUANTIZE */ #ifdef PNG_READ_GAMMA_SUPPORTED void PNGFAPI png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, png_fixed_point file_gamma) { png_debug(1, "in png_set_gamma_fixed"); if (png_rtran_ok(png_ptr, 0) == 0) return; /* New in libpng-1.5.4 - reserve particular negative values as flags. */ scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); /* Checking the gamma values for being >0 was added in 1.5.4 along with the * premultiplied alpha support; this actually hides an undocumented feature * of the previous implementation which allowed gamma processing to be * disabled in background handling. There is no evidence (so far) that this * was being used; however, png_set_background itself accepted and must still * accept '0' for the gamma value it takes, because it isn't always used. * * Since this is an API change (albeit a very minor one that removes an * undocumented API feature) the following checks were only enabled in * libpng-1.6.0. */ if (file_gamma <= 0) png_error(png_ptr, "invalid file gamma in png_set_gamma"); if (scrn_gamma <= 0) png_error(png_ptr, "invalid screen gamma in png_set_gamma"); /* Set the gamma values unconditionally - this overrides the value in the PNG * file if a gAMA chunk was present. png_set_alpha_mode provides a * different, easier, way to default the file gamma. */ png_ptr->colorspace.gamma = file_gamma; png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; png_ptr->screen_gamma = scrn_gamma; } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) { png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), convert_gamma_value(png_ptr, file_gamma)); } # endif /* FLOATING_POINT */ #endif /* READ_GAMMA */ #ifdef PNG_READ_EXPAND_SUPPORTED /* Expand paletted images to RGB, expand grayscale images of * less than 8-bit depth to 8-bit depth, and expand tRNS chunks * to alpha channels. */ void PNGAPI png_set_expand(png_structrp png_ptr) { png_debug(1, "in png_set_expand"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); } /* GRR 19990627: the following three functions currently are identical * to png_set_expand(). However, it is entirely reasonable that someone * might wish to expand an indexed image to RGB but *not* expand a single, * fully transparent palette entry to a full alpha channel--perhaps instead * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace * the transparent color with a particular RGB value, or drop tRNS entirely. * IOW, a future version of the library may make the transformations flag * a bit more fine-grained, with separate bits for each of these three * functions. * * More to the point, these functions make it obvious what libpng will be * doing, whereas "expand" can (and does) mean any number of things. * * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified * to expand only the sample depth but not to expand the tRNS to alpha * and its name was changed to png_set_expand_gray_1_2_4_to_8(). */ /* Expand paletted images to RGB. */ void PNGAPI png_set_palette_to_rgb(png_structrp png_ptr) { png_debug(1, "in png_set_palette_to_rgb"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); } /* Expand grayscale images of less than 8-bit depth to 8 bits. */ void PNGAPI png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) { png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= PNG_EXPAND; } /* Expand tRNS chunks to alpha channels. */ void PNGAPI png_set_tRNS_to_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_tRNS_to_alpha"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); } #endif /* READ_EXPAND */ #ifdef PNG_READ_EXPAND_16_SUPPORTED /* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise * it may not work correctly.) */ void PNGAPI png_set_expand_16(png_structrp png_ptr) { png_debug(1, "in png_set_expand_16"); if (png_rtran_ok(png_ptr, 0) == 0) return; png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); } #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED void PNGAPI png_set_gray_to_rgb(png_structrp png_ptr) { png_debug(1, "in png_set_gray_to_rgb"); if (png_rtran_ok(png_ptr, 0) == 0) return; /* Because rgb must be 8 bits or more: */ png_set_expand_gray_1_2_4_to_8(png_ptr); png_ptr->transformations |= PNG_GRAY_TO_RGB; } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED void PNGFAPI png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, png_fixed_point red, png_fixed_point green) { png_debug(1, "in png_set_rgb_to_gray"); /* Need the IHDR here because of the check on color_type below. */ /* TODO: fix this */ if (png_rtran_ok(png_ptr, 1) == 0) return; switch (error_action) { case PNG_ERROR_ACTION_NONE: png_ptr->transformations |= PNG_RGB_TO_GRAY; break; case PNG_ERROR_ACTION_WARN: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN; break; case PNG_ERROR_ACTION_ERROR: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR; break; default: png_error(png_ptr, "invalid error action to rgb_to_gray"); } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) #ifdef PNG_READ_EXPAND_SUPPORTED png_ptr->transformations |= PNG_EXPAND; #else { /* Make this an error in 1.6 because otherwise the application may assume * that it just worked and get a memory overwrite. */ png_error(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */ } #endif { if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) { png_uint_16 red_int, green_int; /* NOTE: this calculation does not round, but this behavior is retained * for consistency; the inaccuracy is very small. The code here always * overwrites the coefficients, regardless of whether they have been * defaulted or set already. */ red_int = (png_uint_16)(((png_uint_32)red*32768)/100000); green_int = (png_uint_16)(((png_uint_32)green*32768)/100000); png_ptr->rgb_to_gray_red_coeff = red_int; png_ptr->rgb_to_gray_green_coeff = green_int; png_ptr->rgb_to_gray_coefficients_set = 1; } else { if (red >= 0 && green >= 0) png_app_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); /* Use the defaults, from the cHRM chunk if set, else the historical * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See * png_do_rgb_to_gray for more discussion of the values. In this case * the coefficients are not marked as 'set' and are not overwritten if * something has already provided a default. */ if (png_ptr->rgb_to_gray_red_coeff == 0 && png_ptr->rgb_to_gray_green_coeff == 0) { png_ptr->rgb_to_gray_red_coeff = 6968; png_ptr->rgb_to_gray_green_coeff = 23434; /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ } } } } #ifdef PNG_FLOATING_POINT_SUPPORTED /* Convert a RGB image to a grayscale of the same width. This allows us, * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. */ void PNGAPI png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, double green) { png_set_rgb_to_gray_fixed(png_ptr, error_action, png_fixed(png_ptr, red, "rgb to gray red coefficient"), png_fixed(png_ptr, green, "rgb to gray green coefficient")); } #endif /* FLOATING POINT */ #endif /* RGB_TO_GRAY */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) void PNGAPI png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr read_user_transform_fn) { png_debug(1, "in png_set_read_user_transform_fn"); #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED png_ptr->transformations |= PNG_USER_TRANSFORM; png_ptr->read_user_transform_fn = read_user_transform_fn; #endif } #endif #ifdef PNG_READ_TRANSFORMS_SUPPORTED #ifdef PNG_READ_GAMMA_SUPPORTED /* In the case of gamma transformations only do transformations on images where * the [file] gamma and screen_gamma are not close reciprocals, otherwise it * slows things down slightly, and also needlessly introduces small errors. */ static int /* PRIVATE */ png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) { /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma * correction as a difference of the overall transform from 1.0 * * We want to compare the threshold with s*f - 1, if we get * overflow here it is because of wacky gamma values so we * turn on processing anyway. */ png_fixed_point gtest; return !png_muldiv(>est, screen_gamma, file_gamma, PNG_FP_1) || png_gamma_significant(gtest); } #endif /* Initialize everything needed for the read. This includes modifying * the palette. */ /* For the moment 'png_init_palette_transformations' and * 'png_init_rgb_transformations' only do some flag canceling optimizations. * The intent is that these two routines should have palette or rgb operations * extracted from 'png_init_read_transformations'. */ static void /* PRIVATE */ png_init_palette_transformations(png_structrp png_ptr) { /* Called to handle the (input) palette case. In png_do_read_transformations * the first step is to expand the palette if requested, so this code must * take care to only make changes that are invariant with respect to the * palette expansion, or only do them if there is no expansion. * * STRIP_ALPHA has already been handled in the caller (by setting num_trans * to 0.) */ int input_has_alpha = 0; int input_has_transparency = 0; if (png_ptr->num_trans > 0) { int i; /* Ignore if all the entries are opaque (unlikely!) */ for (i=0; inum_trans; ++i) { if (png_ptr->trans_alpha[i] == 255) continue; else if (png_ptr->trans_alpha[i] == 0) input_has_transparency = 1; else { input_has_transparency = 1; input_has_alpha = 1; break; } } } /* If no alpha we can optimize. */ if (input_has_alpha == 0) { /* Any alpha means background and associative alpha processing is * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA * and ENCODE_ALPHA are irrelevant. */ png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; if (input_has_transparency == 0) png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); } #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) /* png_set_background handling - deals with the complexity of whether the * background color is in the file format or the screen format in the case * where an 'expand' will happen. */ /* The following code cannot be entered in the alpha pre-multiplication case * because PNG_BACKGROUND_EXPAND is cancelled below. */ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && (png_ptr->transformations & PNG_EXPAND) != 0) { { png_ptr->background.red = png_ptr->palette[png_ptr->background.index].red; png_ptr->background.green = png_ptr->palette[png_ptr->background.index].green; png_ptr->background.blue = png_ptr->palette[png_ptr->background.index].blue; #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) { if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) { /* Invert the alpha channel (in tRNS) unless the pixels are * going to be expanded, in which case leave it for later */ int i, istop = png_ptr->num_trans; for (i=0; itrans_alpha[i] = (png_byte)(255 - png_ptr->trans_alpha[i]); } } #endif /* READ_INVERT_ALPHA */ } } /* background expand and (therefore) no alpha association. */ #endif /* READ_EXPAND && READ_BACKGROUND */ } static void /* PRIVATE */ png_init_rgb_transformations(png_structrp png_ptr) { /* Added to libpng-1.5.4: check the color type to determine whether there * is any alpha or transparency in the image and simply cancel the * background and alpha mode stuff if there isn't. */ int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0; int input_has_transparency = png_ptr->num_trans > 0; /* If no alpha we can optimize. */ if (input_has_alpha == 0) { /* Any alpha means background and associative alpha processing is * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA * and ENCODE_ALPHA are irrelevant. */ # ifdef PNG_READ_ALPHA_MODE_SUPPORTED png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; # endif if (input_has_transparency == 0) png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); } #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) /* png_set_background handling - deals with the complexity of whether the * background color is in the file format or the screen format in the case * where an 'expand' will happen. */ /* The following code cannot be entered in the alpha pre-multiplication case * because PNG_BACKGROUND_EXPAND is cancelled below. */ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && (png_ptr->transformations & PNG_EXPAND) != 0 && (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* i.e., GRAY or GRAY_ALPHA */ { { /* Expand background and tRNS chunks */ int gray = png_ptr->background.gray; int trans_gray = png_ptr->trans_color.gray; switch (png_ptr->bit_depth) { case 1: gray *= 0xff; trans_gray *= 0xff; break; case 2: gray *= 0x55; trans_gray *= 0x55; break; case 4: gray *= 0x11; trans_gray *= 0x11; break; default: case 8: /* FALLTHROUGH */ /* (Already 8 bits) */ case 16: /* Already a full 16 bits */ break; } png_ptr->background.red = png_ptr->background.green = png_ptr->background.blue = (png_uint_16)gray; if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) { png_ptr->trans_color.red = png_ptr->trans_color.green = png_ptr->trans_color.blue = (png_uint_16)trans_gray; } } } /* background expand and (therefore) no alpha association. */ #endif /* READ_EXPAND && READ_BACKGROUND */ } void /* PRIVATE */ png_init_read_transformations(png_structrp png_ptr) { png_debug(1, "in png_init_read_transformations"); /* This internal function is called from png_read_start_row in pngrutil.c * and it is called before the 'rowbytes' calculation is done, so the code * in here can change or update the transformations flags. * * First do updates that do not depend on the details of the PNG image data * being processed. */ #ifdef PNG_READ_GAMMA_SUPPORTED /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds * png_set_alpha_mode and this is another source for a default file gamma so * the test needs to be performed later - here. In addition prior to 1.5.4 * the tests were repeated for the PALETTE color type here - this is no * longer necessary (and doesn't seem to have been necessary before.) */ { /* The following temporary indicates if overall gamma correction is * required. */ int gamma_correction = 0; if (png_ptr->colorspace.gamma != 0) /* has been set */ { if (png_ptr->screen_gamma != 0) /* screen set too */ gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma, png_ptr->screen_gamma); else /* Assume the output matches the input; a long time default behavior * of libpng, although the standard has nothing to say about this. */ png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma); } else if (png_ptr->screen_gamma != 0) /* The converse - assume the file matches the screen, note that this * perhaps undesireable default can (from 1.5.4) be changed by calling * png_set_alpha_mode (even if the alpha handling mode isn't required * or isn't changed from the default.) */ png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma); else /* neither are set */ /* Just in case the following prevents any processing - file and screen * are both assumed to be linear and there is no way to introduce a * third gamma value other than png_set_background with 'UNIQUE', and, * prior to 1.5.4 */ png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1; /* We have a gamma value now. */ png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; /* Now turn the gamma transformation on or off as appropriate. Notice * that PNG_GAMMA just refers to the file->screen correction. Alpha * composition may independently cause gamma correction because it needs * linear data (e.g. if the file has a gAMA chunk but the screen gamma * hasn't been specified.) In any case this flag may get turned off in * the code immediately below if the transform can be handled outside the * row loop. */ if (gamma_correction != 0) png_ptr->transformations |= PNG_GAMMA; else png_ptr->transformations &= ~PNG_GAMMA; } #endif /* Certain transformations have the effect of preventing other * transformations that happen afterward in png_do_read_transformations; * resolve the interdependencies here. From the code of * png_do_read_transformations the order is: * * 1) PNG_EXPAND (including PNG_EXPAND_tRNS) * 2) PNG_STRIP_ALPHA (if no compose) * 3) PNG_RGB_TO_GRAY * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY * 5) PNG_COMPOSE * 6) PNG_GAMMA * 7) PNG_STRIP_ALPHA (if compose) * 8) PNG_ENCODE_ALPHA * 9) PNG_SCALE_16_TO_8 * 10) PNG_16_TO_8 * 11) PNG_QUANTIZE (converts to palette) * 12) PNG_EXPAND_16 * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY * 14) PNG_INVERT_MONO * 15) PNG_INVERT_ALPHA * 16) PNG_SHIFT * 17) PNG_PACK * 18) PNG_BGR * 19) PNG_PACKSWAP * 20) PNG_FILLER (includes PNG_ADD_ALPHA) * 21) PNG_SWAP_ALPHA * 22) PNG_SWAP_BYTES * 23) PNG_USER_TRANSFORM [must be last] */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && (png_ptr->transformations & PNG_COMPOSE) == 0) { /* Stripping the alpha channel happens immediately after the 'expand' * transformations, before all other transformation, so it cancels out * the alpha handling. It has the side effect negating the effect of * PNG_EXPAND_tRNS too: */ png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA | PNG_EXPAND_tRNS); png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen * so transparency information would remain just so long as it wasn't * expanded. This produces unexpected API changes if the set of things * that do PNG_EXPAND_tRNS changes (perfectly possible given the * documentation - which says ask for what you want, accept what you * get.) This makes the behavior consistent from 1.5.4: */ png_ptr->num_trans = 0; } #endif /* STRIP_ALPHA supported, no COMPOSE */ #ifdef PNG_READ_ALPHA_MODE_SUPPORTED /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA * settings will have no effect. */ if (png_gamma_significant(png_ptr->screen_gamma) == 0) { png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Make sure the coefficients for the rgb to gray conversion are set * appropriately. */ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) png_colorspace_set_rgb_coefficients(png_ptr); #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) /* Detect gray background and attempt to enable optimization for * gray --> RGB case. * * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or * RGB_ALPHA (in which case need_expand is superfluous anyway), the * background color might actually be gray yet not be flagged as such. * This is not a problem for the current code, which uses * PNG_BACKGROUND_IS_GRAY only to decide when to do the * png_do_gray_to_rgb() transformation. * * TODO: this code needs to be revised to avoid the complexity and * interdependencies. The color type of the background should be recorded in * png_set_background, along with the bit depth, then the code has a record * of exactly what color space the background is currently in. */ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0) { /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if * the file was grayscale the background value is gray. */ if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; } else if ((png_ptr->transformations & PNG_COMPOSE) != 0) { /* PNG_COMPOSE: png_set_background was called with need_expand false, * so the color is in the color space of the output or png_set_alpha_mode * was called and the color is black. Ignore RGB_TO_GRAY because that * happens before GRAY_TO_RGB. */ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) { if (png_ptr->background.red == png_ptr->background.green && png_ptr->background.red == png_ptr->background.blue) { png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; png_ptr->background.gray = png_ptr->background.red; } } } #endif /* READ_EXPAND && READ_BACKGROUND */ #endif /* READ_GRAY_TO_RGB */ /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations * can be performed directly on the palette, and some (such as rgb to gray) * can be optimized inside the palette. This is particularly true of the * composite (background and alpha) stuff, which can be pretty much all done * in the palette even if the result is expanded to RGB or gray afterward. * * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and * earlier and the palette stuff is actually handled on the first row. This * leads to the reported bug that the palette returned by png_get_PLTE is not * updated. */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_init_palette_transformations(png_ptr); else png_init_rgb_transformations(png_ptr); #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ defined(PNG_READ_EXPAND_16_SUPPORTED) if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && (png_ptr->transformations & PNG_COMPOSE) != 0 && (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && png_ptr->bit_depth != 16) { /* TODO: fix this. Because the expand_16 operation is after the compose * handling the background color must be 8, not 16, bits deep, but the * application will supply a 16-bit value so reduce it here. * * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at * present, so that case is ok (until do_expand_16 is moved.) * * NOTE: this discards the low 16 bits of the user supplied background * color, but until expand_16 works properly there is no choice! */ # define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x)) CHOP(png_ptr->background.red); CHOP(png_ptr->background.green); CHOP(png_ptr->background.blue); CHOP(png_ptr->background.gray); # undef CHOP } #endif /* READ_BACKGROUND && READ_EXPAND_16 */ #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 && (png_ptr->transformations & PNG_COMPOSE) != 0 && (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && png_ptr->bit_depth == 16) { /* On the other hand, if a 16-bit file is to be reduced to 8-bits per * component this will also happen after PNG_COMPOSE and so the background * color must be pre-expanded here. * * TODO: fix this too. */ png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257); png_ptr->background.green = (png_uint_16)(png_ptr->background.green * 257); png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257); png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257); } #endif /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the * background support (see the comments in scripts/pnglibconf.dfa), this * allows pre-multiplication of the alpha channel to be implemented as * compositing on black. This is probably sub-optimal and has been done in * 1.5.4 betas simply to enable external critique and testing (i.e. to * implement the new API quickly, without lots of internal changes.) */ #ifdef PNG_READ_GAMMA_SUPPORTED # ifdef PNG_READ_BACKGROUND_SUPPORTED /* Includes ALPHA_MODE */ png_ptr->background_1 = png_ptr->background; # endif /* This needs to change - in the palette image case a whole set of tables are * built when it would be quicker to just calculate the correct value for * each palette entry directly. Also, the test is too tricky - why check * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction * the gamma tables will not be built even if composition is required on a * gamma encoded value. * * In 1.5.4 this is addressed below by an additional check on the individual * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the * tables. */ if ((png_ptr->transformations & PNG_GAMMA) != 0 || ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 && (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || png_gamma_significant(png_ptr->screen_gamma) != 0)) || ((png_ptr->transformations & PNG_COMPOSE) != 0 && (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || png_gamma_significant(png_ptr->screen_gamma) != 0 # ifdef PNG_READ_BACKGROUND_SUPPORTED || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE && png_gamma_significant(png_ptr->background_gamma) != 0) # endif )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && png_gamma_significant(png_ptr->screen_gamma) != 0)) { png_build_gamma_table(png_ptr, png_ptr->bit_depth); #ifdef PNG_READ_BACKGROUND_SUPPORTED if ((png_ptr->transformations & PNG_COMPOSE) != 0) { /* Issue a warning about this combination: because RGB_TO_GRAY is * optimized to do the gamma transform if present yet do_background has * to do the same thing if both options are set a * double-gamma-correction happens. This is true in all versions of * libpng to date. */ if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) png_warning(png_ptr, "libpng does not support gamma+background+rgb_to_gray"); if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0) { /* We don't get to here unless there is a tRNS chunk with non-opaque * entries - see the checking code at the start of this function. */ png_color back, back_1; png_colorp palette = png_ptr->palette; int num_palette = png_ptr->num_palette; int i; if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE) { back.red = png_ptr->gamma_table[png_ptr->background.red]; back.green = png_ptr->gamma_table[png_ptr->background.green]; back.blue = png_ptr->gamma_table[png_ptr->background.blue]; back_1.red = png_ptr->gamma_to_1[png_ptr->background.red]; back_1.green = png_ptr->gamma_to_1[png_ptr->background.green]; back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue]; } else { png_fixed_point g, gs; switch (png_ptr->background_gamma_type) { case PNG_BACKGROUND_GAMMA_SCREEN: g = (png_ptr->screen_gamma); gs = PNG_FP_1; break; case PNG_BACKGROUND_GAMMA_FILE: g = png_reciprocal(png_ptr->colorspace.gamma); gs = png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma); break; case PNG_BACKGROUND_GAMMA_UNIQUE: g = png_reciprocal(png_ptr->background_gamma); gs = png_reciprocal2(png_ptr->background_gamma, png_ptr->screen_gamma); break; default: g = PNG_FP_1; /* back_1 */ gs = PNG_FP_1; /* back */ break; } if (png_gamma_significant(gs) != 0) { back.red = png_gamma_8bit_correct(png_ptr->background.red, gs); back.green = png_gamma_8bit_correct(png_ptr->background.green, gs); back.blue = png_gamma_8bit_correct(png_ptr->background.blue, gs); } else { back.red = (png_byte)png_ptr->background.red; back.green = (png_byte)png_ptr->background.green; back.blue = (png_byte)png_ptr->background.blue; } if (png_gamma_significant(g) != 0) { back_1.red = png_gamma_8bit_correct(png_ptr->background.red, g); back_1.green = png_gamma_8bit_correct( png_ptr->background.green, g); back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, g); } else { back_1.red = (png_byte)png_ptr->background.red; back_1.green = (png_byte)png_ptr->background.green; back_1.blue = (png_byte)png_ptr->background.blue; } } for (i = 0; i < num_palette; i++) { if (i < (int)png_ptr->num_trans && png_ptr->trans_alpha[i] != 0xff) { if (png_ptr->trans_alpha[i] == 0) { palette[i] = back; } else /* if (png_ptr->trans_alpha[i] != 0xff) */ { png_byte v, w; v = png_ptr->gamma_to_1[palette[i].red]; png_composite(w, v, png_ptr->trans_alpha[i], back_1.red); palette[i].red = png_ptr->gamma_from_1[w]; v = png_ptr->gamma_to_1[palette[i].green]; png_composite(w, v, png_ptr->trans_alpha[i], back_1.green); palette[i].green = png_ptr->gamma_from_1[w]; v = png_ptr->gamma_to_1[palette[i].blue]; png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue); palette[i].blue = png_ptr->gamma_from_1[w]; } } else { palette[i].red = png_ptr->gamma_table[palette[i].red]; palette[i].green = png_ptr->gamma_table[palette[i].green]; palette[i].blue = png_ptr->gamma_table[palette[i].blue]; } } /* Prevent the transformations being done again. * * NOTE: this is highly dubious; it removes the transformations in * place. This seems inconsistent with the general treatment of the * transformations elsewhere. */ png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); } /* color_type == PNG_COLOR_TYPE_PALETTE */ /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ else /* color_type != PNG_COLOR_TYPE_PALETTE */ { int gs_sig, g_sig; png_fixed_point g = PNG_FP_1; /* Correction to linear */ png_fixed_point gs = PNG_FP_1; /* Correction to screen */ switch (png_ptr->background_gamma_type) { case PNG_BACKGROUND_GAMMA_SCREEN: g = png_ptr->screen_gamma; /* gs = PNG_FP_1; */ break; case PNG_BACKGROUND_GAMMA_FILE: g = png_reciprocal(png_ptr->colorspace.gamma); gs = png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma); break; case PNG_BACKGROUND_GAMMA_UNIQUE: g = png_reciprocal(png_ptr->background_gamma); gs = png_reciprocal2(png_ptr->background_gamma, png_ptr->screen_gamma); break; default: png_error(png_ptr, "invalid background gamma type"); } g_sig = png_gamma_significant(g); gs_sig = png_gamma_significant(gs); if (g_sig != 0) png_ptr->background_1.gray = png_gamma_correct(png_ptr, png_ptr->background.gray, g); if (gs_sig != 0) png_ptr->background.gray = png_gamma_correct(png_ptr, png_ptr->background.gray, gs); if ((png_ptr->background.red != png_ptr->background.green) || (png_ptr->background.red != png_ptr->background.blue) || (png_ptr->background.red != png_ptr->background.gray)) { /* RGB or RGBA with color background */ if (g_sig != 0) { png_ptr->background_1.red = png_gamma_correct(png_ptr, png_ptr->background.red, g); png_ptr->background_1.green = png_gamma_correct(png_ptr, png_ptr->background.green, g); png_ptr->background_1.blue = png_gamma_correct(png_ptr, png_ptr->background.blue, g); } if (gs_sig != 0) { png_ptr->background.red = png_gamma_correct(png_ptr, png_ptr->background.red, gs); png_ptr->background.green = png_gamma_correct(png_ptr, png_ptr->background.green, gs); png_ptr->background.blue = png_gamma_correct(png_ptr, png_ptr->background.blue, gs); } } else { /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */ png_ptr->background_1.red = png_ptr->background_1.green = png_ptr->background_1.blue = png_ptr->background_1.gray; png_ptr->background.red = png_ptr->background.green = png_ptr->background.blue = png_ptr->background.gray; } /* The background is now in screen gamma: */ png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN; } /* color_type != PNG_COLOR_TYPE_PALETTE */ }/* png_ptr->transformations & PNG_BACKGROUND */ else /* Transformation does not include PNG_BACKGROUND */ #endif /* READ_BACKGROUND */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ && ((png_ptr->transformations & PNG_EXPAND) == 0 || (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) #endif ) { png_colorp palette = png_ptr->palette; int num_palette = png_ptr->num_palette; int i; /* NOTE: there are other transformations that should probably be in * here too. */ for (i = 0; i < num_palette; i++) { palette[i].red = png_ptr->gamma_table[palette[i].red]; palette[i].green = png_ptr->gamma_table[palette[i].green]; palette[i].blue = png_ptr->gamma_table[palette[i].blue]; } /* Done the gamma correction. */ png_ptr->transformations &= ~PNG_GAMMA; } /* color_type == PALETTE && !PNG_BACKGROUND transformation */ } #ifdef PNG_READ_BACKGROUND_SUPPORTED else #endif #endif /* READ_GAMMA */ #ifdef PNG_READ_BACKGROUND_SUPPORTED /* No GAMMA transformation (see the hanging else 4 lines above) */ if ((png_ptr->transformations & PNG_COMPOSE) != 0 && (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; int istop = (int)png_ptr->num_trans; png_color back; png_colorp palette = png_ptr->palette; back.red = (png_byte)png_ptr->background.red; back.green = (png_byte)png_ptr->background.green; back.blue = (png_byte)png_ptr->background.blue; for (i = 0; i < istop; i++) { if (png_ptr->trans_alpha[i] == 0) { palette[i] = back; } else if (png_ptr->trans_alpha[i] != 0xff) { /* The png_composite() macro is defined in png.h */ png_composite(palette[i].red, palette[i].red, png_ptr->trans_alpha[i], back.red); png_composite(palette[i].green, palette[i].green, png_ptr->trans_alpha[i], back.green); png_composite(palette[i].blue, palette[i].blue, png_ptr->trans_alpha[i], back.blue); } } png_ptr->transformations &= ~PNG_COMPOSE; } #endif /* READ_BACKGROUND */ #ifdef PNG_READ_SHIFT_SUPPORTED if ((png_ptr->transformations & PNG_SHIFT) != 0 && (png_ptr->transformations & PNG_EXPAND) == 0 && (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; int istop = png_ptr->num_palette; int shift = 8 - png_ptr->sig_bit.red; png_ptr->transformations &= ~PNG_SHIFT; /* significant bits can be in the range 1 to 7 for a meaninful result, if * the number of significant bits is 0 then no shift is done (this is an * error condition which is silently ignored.) */ if (shift > 0 && shift < 8) for (i=0; ipalette[i].red; component >>= shift; png_ptr->palette[i].red = (png_byte)component; } shift = 8 - png_ptr->sig_bit.green; if (shift > 0 && shift < 8) for (i=0; ipalette[i].green; component >>= shift; png_ptr->palette[i].green = (png_byte)component; } shift = 8 - png_ptr->sig_bit.blue; if (shift > 0 && shift < 8) for (i=0; ipalette[i].blue; component >>= shift; png_ptr->palette[i].blue = (png_byte)component; } } #endif /* READ_SHIFT */ } /* Modify the info structure to reflect the transformations. The * info should be updated so a PNG file could be written with it, * assuming the transformations result in valid PNG data. */ void /* PRIVATE */ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_read_transform_info"); #ifdef PNG_READ_EXPAND_SUPPORTED if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { /* This check must match what actually happens in * png_do_expand_palette; if it ever checks the tRNS chunk to see if * it is all opaque we must do the same (at present it does not.) */ if (png_ptr->num_trans > 0) info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; else info_ptr->color_type = PNG_COLOR_TYPE_RGB; info_ptr->bit_depth = 8; info_ptr->num_trans = 0; if (png_ptr->palette == NULL) png_error (png_ptr, "Palette is NULL in indexed image"); } else { if (png_ptr->num_trans != 0) { if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0) info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } if (info_ptr->bit_depth < 8) info_ptr->bit_depth = 8; info_ptr->num_trans = 0; } } #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* The following is almost certainly wrong unless the background value is in * the screen space! */ if ((png_ptr->transformations & PNG_COMPOSE) != 0) info_ptr->background = png_ptr->background; #endif #ifdef PNG_READ_GAMMA_SUPPORTED /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4), * however it seems that the code in png_init_read_transformations, which has * been called before this from png_read_update_info->png_read_start_row * sometimes does the gamma transform and cancels the flag. * * TODO: this looks wrong; the info_ptr should end up with a gamma equal to * the screen_gamma value. The following probably results in weirdness if * the info_ptr is used by the app after the rows have been read. */ info_ptr->colorspace.gamma = png_ptr->colorspace.gamma; #endif if (info_ptr->bit_depth == 16) { # ifdef PNG_READ_16BIT_SUPPORTED # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) info_ptr->bit_depth = 8; # endif # ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED if ((png_ptr->transformations & PNG_16_TO_8) != 0) info_ptr->bit_depth = 8; # endif # else /* No 16-bit support: force chopping 16-bit input down to 8, in this case * the app program can chose if both APIs are available by setting the * correct scaling to use. */ # ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* For compatibility with previous versions use the strip method by * default. This code works because if PNG_SCALE_16_TO_8 is already * set the code below will do that in preference to the chop. */ png_ptr->transformations |= PNG_16_TO_8; info_ptr->bit_depth = 8; # else # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_ptr->transformations |= PNG_SCALE_16_TO_8; info_ptr->bit_depth = 8; # else CONFIGURATION ERROR: you must enable at least one 16 to 8 method # endif # endif #endif /* !READ_16BIT */ } #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) info_ptr->color_type = (png_byte)(info_ptr->color_type | PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) info_ptr->color_type = (png_byte)(info_ptr->color_type & ~PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED if ((png_ptr->transformations & PNG_QUANTIZE) != 0) { if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8) { info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; } } #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && info_ptr->bit_depth == 8 && info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { info_ptr->bit_depth = 16; } #endif #ifdef PNG_READ_PACK_SUPPORTED if ((png_ptr->transformations & PNG_PACK) != 0 && (info_ptr->bit_depth < 8)) info_ptr->bit_depth = 8; #endif if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_ptr->channels = 3; else info_ptr->channels = 1; #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0) { info_ptr->color_type = (png_byte)(info_ptr->color_type & ~PNG_COLOR_MASK_ALPHA); info_ptr->num_trans = 0; } #endif if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) info_ptr->channels++; #ifdef PNG_READ_FILLER_SUPPORTED /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ if ((png_ptr->transformations & PNG_FILLER) != 0 && (info_ptr->color_type == PNG_COLOR_TYPE_RGB || info_ptr->color_type == PNG_COLOR_TYPE_GRAY)) { info_ptr->channels++; /* If adding a true alpha channel not just filler */ if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0) info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } #endif #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) { if (png_ptr->user_transform_depth != 0) info_ptr->bit_depth = png_ptr->user_transform_depth; if (png_ptr->user_transform_channels != 0) info_ptr->channels = png_ptr->user_transform_channels; } #endif info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); /* Adding in 1.5.4: cache the above value in png_struct so that we can later * check in png_rowbytes that the user buffer won't get overwritten. Note * that the field is not always set - if png_read_update_info isn't called * the application has to either not do any transforms or get the calculation * right itself. */ png_ptr->info_rowbytes = info_ptr->rowbytes; #ifndef PNG_READ_EXPAND_SUPPORTED if (png_ptr != NULL) return; #endif } #ifdef PNG_READ_PACK_SUPPORTED /* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, * without changing the actual values. Thus, if you had a row with * a bit depth of 1, you would end up with bytes that only contained * the numbers 0 or 1. If you would rather they contain 0 and 255, use * png_do_shift() after this. */ static void png_do_unpack(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_unpack"); if (row_info->bit_depth < 8) { png_uint_32 i; png_uint_32 row_width=row_info->width; switch (row_info->bit_depth) { case 1: { png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); png_bytep dp = row + (png_size_t)row_width - 1; png_uint_32 shift = 7U - ((row_width + 7U) & 0x07); for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x01); if (shift == 7) { shift = 0; sp--; } else shift++; dp--; } break; } case 2: { png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); png_bytep dp = row + (png_size_t)row_width - 1; png_uint_32 shift = ((3U - ((row_width + 3U) & 0x03)) << 1); for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x03); if (shift == 6) { shift = 0; sp--; } else shift += 2; dp--; } break; } case 4: { png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); png_bytep dp = row + (png_size_t)row_width - 1; png_uint_32 shift = ((1U - ((row_width + 1U) & 0x01)) << 2); for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x0f); if (shift == 4) { shift = 0; sp--; } else shift = 4; dp--; } break; } default: break; } row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); row_info->rowbytes = row_width * row_info->channels; } } #endif #ifdef PNG_READ_SHIFT_SUPPORTED /* Reverse the effects of png_do_shift. This routine merely shifts the * pixels back to their significant bits values. Thus, if you have * a row of bit depth 8, but only 5 are significant, this will shift * the values back to 0 through 31. */ static void png_do_unshift(png_row_infop row_info, png_bytep row, png_const_color_8p sig_bits) { int color_type; png_debug(1, "in png_do_unshift"); /* The palette case has already been handled in the _init routine. */ color_type = row_info->color_type; if (color_type != PNG_COLOR_TYPE_PALETTE) { int shift[4]; int channels = 0; int bit_depth = row_info->bit_depth; if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { shift[channels++] = bit_depth - sig_bits->red; shift[channels++] = bit_depth - sig_bits->green; shift[channels++] = bit_depth - sig_bits->blue; } else { shift[channels++] = bit_depth - sig_bits->gray; } if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) { shift[channels++] = bit_depth - sig_bits->alpha; } { int c, have_shift; for (c = have_shift = 0; c < channels; ++c) { /* A shift of more than the bit depth is an error condition but it * gets ignored here. */ if (shift[c] <= 0 || shift[c] >= bit_depth) shift[c] = 0; else have_shift = 1; } if (have_shift == 0) return; } switch (bit_depth) { default: /* Must be 1bpp gray: should not be here! */ /* NOTREACHED */ break; case 2: /* Must be 2bpp gray */ /* assert(channels == 1 && shift[0] == 1) */ { png_bytep bp = row; png_bytep bp_end = bp + row_info->rowbytes; while (bp < bp_end) { int b = (*bp >> 1) & 0x55; *bp++ = (png_byte)b; } break; } case 4: /* Must be 4bpp gray */ /* assert(channels == 1) */ { png_bytep bp = row; png_bytep bp_end = bp + row_info->rowbytes; int gray_shift = shift[0]; int mask = 0xf >> gray_shift; mask |= mask << 4; while (bp < bp_end) { int b = (*bp >> gray_shift) & mask; *bp++ = (png_byte)b; } break; } case 8: /* Single byte components, G, GA, RGB, RGBA */ { png_bytep bp = row; png_bytep bp_end = bp + row_info->rowbytes; int channel = 0; while (bp < bp_end) { int b = *bp >> shift[channel]; if (++channel >= channels) channel = 0; *bp++ = (png_byte)b; } break; } #ifdef PNG_READ_16BIT_SUPPORTED case 16: /* Double byte components, G, GA, RGB, RGBA */ { png_bytep bp = row; png_bytep bp_end = bp + row_info->rowbytes; int channel = 0; while (bp < bp_end) { int value = (bp[0] << 8) + bp[1]; value >>= shift[channel]; if (++channel >= channels) channel = 0; *bp++ = (png_byte)(value >> 8); *bp++ = (png_byte)value; } break; } #endif } } } #endif #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale rows of bit depth 16 down to 8 accurately */ static void png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_scale_16_to_8"); if (row_info->bit_depth == 16) { png_bytep sp = row; /* source */ png_bytep dp = row; /* destination */ png_bytep ep = sp + row_info->rowbytes; /* end+1 */ while (sp < ep) { /* The input is an array of 16-bit components, these must be scaled to * 8 bits each. For a 16-bit value V the required value (from the PNG * specification) is: * * (V * 255) / 65535 * * This reduces to round(V / 257), or floor((V + 128.5)/257) * * Represent V as the two byte value vhi.vlo. Make a guess that the * result is the top byte of V, vhi, then the correction to this value * is: * * error = floor(((V-vhi.vhi) + 128.5) / 257) * = floor(((vlo-vhi) + 128.5) / 257) * * This can be approximated using integer arithmetic (and a signed * shift): * * error = (vlo-vhi+128) >> 8; * * The approximate differs from the exact answer only when (vlo-vhi) is * 128; it then gives a correction of +1 when the exact correction is * 0. This gives 128 errors. The exact answer (correct for all 16-bit * input values) is: * * error = (vlo-vhi+128)*65535 >> 24; * * An alternative arithmetic calculation which also gives no errors is: * * (V * 255 + 32895) >> 16 */ png_int_32 tmp = *sp++; /* must be signed! */ tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24; *dp++ = (png_byte)tmp; } row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); row_info->rowbytes = row_info->width * row_info->channels; } } #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED static void /* Simply discard the low byte. This was the default behavior prior * to libpng-1.5.4. */ png_do_chop(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_chop"); if (row_info->bit_depth == 16) { png_bytep sp = row; /* source */ png_bytep dp = row; /* destination */ png_bytep ep = sp + row_info->rowbytes; /* end+1 */ while (sp < ep) { *dp++ = *sp; sp += 2; /* skip low byte */ } row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); row_info->rowbytes = row_info->width * row_info->channels; } } #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED static void png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_read_swap_alpha"); { png_uint_32 row_width = row_info->width; if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { /* This converts from RGBA to ARGB */ if (row_info->bit_depth == 8) { png_bytep sp = row + row_info->rowbytes; png_bytep dp = sp; png_byte save; png_uint_32 i; for (i = 0; i < row_width; i++) { save = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = save; } } #ifdef PNG_READ_16BIT_SUPPORTED /* This converts from RRGGBBAA to AARRGGBB */ else { png_bytep sp = row + row_info->rowbytes; png_bytep dp = sp; png_byte save[2]; png_uint_32 i; for (i = 0; i < row_width; i++) { save[0] = *(--sp); save[1] = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = save[0]; *(--dp) = save[1]; } } #endif } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { /* This converts from GA to AG */ if (row_info->bit_depth == 8) { png_bytep sp = row + row_info->rowbytes; png_bytep dp = sp; png_byte save; png_uint_32 i; for (i = 0; i < row_width; i++) { save = *(--sp); *(--dp) = *(--sp); *(--dp) = save; } } #ifdef PNG_READ_16BIT_SUPPORTED /* This converts from GGAA to AAGG */ else { png_bytep sp = row + row_info->rowbytes; png_bytep dp = sp; png_byte save[2]; png_uint_32 i; for (i = 0; i < row_width; i++) { save[0] = *(--sp); save[1] = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = save[0]; *(--dp) = save[1]; } } #endif } } } #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED static void png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) { png_uint_32 row_width; png_debug(1, "in png_do_read_invert_alpha"); row_width = row_info->width; if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { if (row_info->bit_depth == 8) { /* This inverts the alpha channel in RGBA */ png_bytep sp = row + row_info->rowbytes; png_bytep dp = sp; png_uint_32 i; for (i = 0; i < row_width; i++) { *(--dp) = (png_byte)(255 - *(--sp)); /* This does nothing: *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); We can replace it with: */ sp-=3; dp=sp; } } #ifdef PNG_READ_16BIT_SUPPORTED /* This inverts the alpha channel in RRGGBBAA */ else { png_bytep sp = row + row_info->rowbytes; png_bytep dp = sp; png_uint_32 i; for (i = 0; i < row_width; i++) { *(--dp) = (png_byte)(255 - *(--sp)); *(--dp) = (png_byte)(255 - *(--sp)); /* This does nothing: *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); We can replace it with: */ sp-=6; dp=sp; } } #endif } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (row_info->bit_depth == 8) { /* This inverts the alpha channel in GA */ png_bytep sp = row + row_info->rowbytes; png_bytep dp = sp; png_uint_32 i; for (i = 0; i < row_width; i++) { *(--dp) = (png_byte)(255 - *(--sp)); *(--dp) = *(--sp); } } #ifdef PNG_READ_16BIT_SUPPORTED else { /* This inverts the alpha channel in GGAA */ png_bytep sp = row + row_info->rowbytes; png_bytep dp = sp; png_uint_32 i; for (i = 0; i < row_width; i++) { *(--dp) = (png_byte)(255 - *(--sp)); *(--dp) = (png_byte)(255 - *(--sp)); /* *(--dp) = *(--sp); *(--dp) = *(--sp); */ sp-=2; dp=sp; } } #endif } } #endif #ifdef PNG_READ_FILLER_SUPPORTED /* Add filler channel if we have RGB color */ static void png_do_read_filler(png_row_infop row_info, png_bytep row, png_uint_32 filler, png_uint_32 flags) { png_uint_32 i; png_uint_32 row_width = row_info->width; #ifdef PNG_READ_16BIT_SUPPORTED png_byte hi_filler = (png_byte)(filler>>8); #endif png_byte lo_filler = (png_byte)filler; png_debug(1, "in png_do_read_filler"); if ( row_info->color_type == PNG_COLOR_TYPE_GRAY) { if (row_info->bit_depth == 8) { if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from G to GX */ png_bytep sp = row + (png_size_t)row_width; png_bytep dp = sp + (png_size_t)row_width; for (i = 1; i < row_width; i++) { *(--dp) = lo_filler; *(--dp) = *(--sp); } *(--dp) = lo_filler; row_info->channels = 2; row_info->pixel_depth = 16; row_info->rowbytes = row_width * 2; } else { /* This changes the data from G to XG */ png_bytep sp = row + (png_size_t)row_width; png_bytep dp = sp + (png_size_t)row_width; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); *(--dp) = lo_filler; } row_info->channels = 2; row_info->pixel_depth = 16; row_info->rowbytes = row_width * 2; } } #ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from GG to GGXX */ png_bytep sp = row + (png_size_t)row_width * 2; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { *(--dp) = lo_filler; *(--dp) = hi_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); } *(--dp) = lo_filler; *(--dp) = hi_filler; row_info->channels = 2; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; } else { /* This changes the data from GG to XXGG */ png_bytep sp = row + (png_size_t)row_width * 2; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = lo_filler; *(--dp) = hi_filler; } row_info->channels = 2; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; } } #endif } /* COLOR_TYPE == GRAY */ else if (row_info->color_type == PNG_COLOR_TYPE_RGB) { if (row_info->bit_depth == 8) { if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from RGB to RGBX */ png_bytep sp = row + (png_size_t)row_width * 3; png_bytep dp = sp + (png_size_t)row_width; for (i = 1; i < row_width; i++) { *(--dp) = lo_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); } *(--dp) = lo_filler; row_info->channels = 4; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; } else { /* This changes the data from RGB to XRGB */ png_bytep sp = row + (png_size_t)row_width * 3; png_bytep dp = sp + (png_size_t)row_width; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = lo_filler; } row_info->channels = 4; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; } } #ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from RRGGBB to RRGGBBXX */ png_bytep sp = row + (png_size_t)row_width * 6; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { *(--dp) = lo_filler; *(--dp) = hi_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); } *(--dp) = lo_filler; *(--dp) = hi_filler; row_info->channels = 4; row_info->pixel_depth = 64; row_info->rowbytes = row_width * 8; } else { /* This changes the data from RRGGBB to XXRRGGBB */ png_bytep sp = row + (png_size_t)row_width * 6; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = lo_filler; *(--dp) = hi_filler; } row_info->channels = 4; row_info->pixel_depth = 64; row_info->rowbytes = row_width * 8; } } #endif } /* COLOR_TYPE == RGB */ } #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale files to RGB, with or without alpha */ static void png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) { png_uint_32 i; png_uint_32 row_width = row_info->width; png_debug(1, "in png_do_gray_to_rgb"); if (row_info->bit_depth >= 8 && (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0) { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { if (row_info->bit_depth == 8) { /* This changes G to RGB */ png_bytep sp = row + (png_size_t)row_width - 1; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(dp--) = *sp; *(dp--) = *sp; *(dp--) = *(sp--); } } else { /* This changes GG to RRGGBB */ png_bytep sp = row + (png_size_t)row_width * 2 - 1; png_bytep dp = sp + (png_size_t)row_width * 4; for (i = 0; i < row_width; i++) { *(dp--) = *sp; *(dp--) = *(sp - 1); *(dp--) = *sp; *(dp--) = *(sp - 1); *(dp--) = *(sp--); *(dp--) = *(sp--); } } } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (row_info->bit_depth == 8) { /* This changes GA to RGBA */ png_bytep sp = row + (png_size_t)row_width * 2 - 1; png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(dp--) = *(sp--); *(dp--) = *sp; *(dp--) = *sp; *(dp--) = *(sp--); } } else { /* This changes GGAA to RRGGBBAA */ png_bytep sp = row + (png_size_t)row_width * 4 - 1; png_bytep dp = sp + (png_size_t)row_width * 4; for (i = 0; i < row_width; i++) { *(dp--) = *(sp--); *(dp--) = *(sp--); *(dp--) = *sp; *(dp--) = *(sp - 1); *(dp--) = *sp; *(dp--) = *(sp - 1); *(dp--) = *(sp--); *(dp--) = *(sp--); } } } row_info->channels = (png_byte)(row_info->channels + 2); row_info->color_type |= PNG_COLOR_MASK_COLOR; row_info->pixel_depth = (png_byte)(row_info->channels * row_info->bit_depth); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Reduce RGB files to grayscale, with or without alpha * using the equation given in Poynton's ColorFAQ of 1998-01-04 at * (THIS LINK IS DEAD June 2008 but * versions dated 1998 through November 2002 have been archived at * https://web.archive.org/web/20000816232553/www.inforamp.net/ * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) * Charles Poynton poynton at poynton.com * * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B * * which can be expressed with integers as * * Y = (6969 * R + 23434 * G + 2365 * B)/32768 * * Poynton's current link (as of January 2003 through July 2011): * * has changed the numbers slightly: * * Y = 0.2126*R + 0.7152*G + 0.0722*B * * which can be expressed with integers as * * Y = (6966 * R + 23436 * G + 2366 * B)/32768 * * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 * end point chromaticities and the D65 white point. Depending on the * precision used for the D65 white point this produces a variety of different * numbers, however if the four decimal place value used in ITU-R Rec 709 is * used (0.3127,0.3290) the Y calculation would be: * * Y = (6968 * R + 23435 * G + 2366 * B)/32768 * * While this is correct the rounding results in an overflow for white, because * the sum of the rounded coefficients is 32769, not 32768. Consequently * libpng uses, instead, the closest non-overflowing approximation: * * Y = (6968 * R + 23434 * G + 2366 * B)/32768 * * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk * (including an sRGB chunk) then the chromaticities are used to calculate the * coefficients. See the chunk handling in pngrutil.c for more information. * * In all cases the calculation is to be done in a linear colorspace. If no * gamma information is available to correct the encoding of the original RGB * values this results in an implicit assumption that the original PNG RGB * values were linear. * * Other integer coefficents can be used via png_set_rgb_to_gray(). Because * the API takes just red and green coefficients the blue coefficient is * calculated to make the sum 32768. This will result in different rounding * to that used above. */ static int png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) { int rgb_error = 0; png_debug(1, "in png_do_rgb_to_gray"); if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 && (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; PNG_CONST png_uint_32 bc = 32768 - rc - gc; PNG_CONST png_uint_32 row_width = row_info->width; PNG_CONST int have_alpha = (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; if (row_info->bit_depth == 8) { #ifdef PNG_READ_GAMMA_SUPPORTED /* Notice that gamma to/from 1 are not necessarily inverses (if * there is an overall gamma correction). Prior to 1.5.5 this code * checked the linearized values for equality; this doesn't match * the documentation, the original values must be checked. */ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) { png_bytep sp = row; png_bytep dp = row; png_uint_32 i; for (i = 0; i < row_width; i++) { png_byte red = *(sp++); png_byte green = *(sp++); png_byte blue = *(sp++); if (red != green || red != blue) { red = png_ptr->gamma_to_1[red]; green = png_ptr->gamma_to_1[green]; blue = png_ptr->gamma_to_1[blue]; rgb_error |= 1; *(dp++) = png_ptr->gamma_from_1[ (rc*red + gc*green + bc*blue + 16384)>>15]; } else { /* If there is no overall correction the table will not be * set. */ if (png_ptr->gamma_table != NULL) red = png_ptr->gamma_table[red]; *(dp++) = red; } if (have_alpha != 0) *(dp++) = *(sp++); } } else #endif { png_bytep sp = row; png_bytep dp = row; png_uint_32 i; for (i = 0; i < row_width; i++) { png_byte red = *(sp++); png_byte green = *(sp++); png_byte blue = *(sp++); if (red != green || red != blue) { rgb_error |= 1; /* NOTE: this is the historical approach which simply * truncates the results. */ *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); } else *(dp++) = red; if (have_alpha != 0) *(dp++) = *(sp++); } } } else /* RGB bit_depth == 16 */ { #ifdef PNG_READ_GAMMA_SUPPORTED if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) { png_bytep sp = row; png_bytep dp = row; png_uint_32 i; for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, w; png_byte hi,lo; hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); if (red == green && red == blue) { if (png_ptr->gamma_16_table != NULL) w = png_ptr->gamma_16_table[(red & 0xff) >> png_ptr->gamma_shift][red >> 8]; else w = red; } else { png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red & 0xff) >> png_ptr->gamma_shift][red>>8]; png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green & 0xff) >> png_ptr->gamma_shift][green>>8]; png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue & 0xff) >> png_ptr->gamma_shift][blue>>8]; png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + bc*blue_1 + 16384)>>15); w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >> png_ptr->gamma_shift][gray16 >> 8]; rgb_error |= 1; } *(dp++) = (png_byte)((w>>8) & 0xff); *(dp++) = (png_byte)(w & 0xff); if (have_alpha != 0) { *(dp++) = *(sp++); *(dp++) = *(sp++); } } } else #endif { png_bytep sp = row; png_bytep dp = row; png_uint_32 i; for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, gray16; png_byte hi,lo; hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); if (red != green || red != blue) rgb_error |= 1; /* From 1.5.5 in the 16-bit case do the accurate conversion even * in the 'fast' case - this is because this is where the code * ends up when handling linear 16-bit data. */ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> 15); *(dp++) = (png_byte)((gray16 >> 8) & 0xff); *(dp++) = (png_byte)(gray16 & 0xff); if (have_alpha != 0) { *(dp++) = *(sp++); *(dp++) = *(sp++); } } } } row_info->channels = (png_byte)(row_info->channels - 2); row_info->color_type = (png_byte)(row_info->color_type & ~PNG_COLOR_MASK_COLOR); row_info->pixel_depth = (png_byte)(row_info->channels * row_info->bit_depth); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } return rgb_error; } #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* Replace any alpha or transparency with the supplied background color. * "background" is already in the screen gamma, while "background_1" is * at a gamma of 1.0. Paletted files have already been taken care of. */ static void png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { #ifdef PNG_READ_GAMMA_SUPPORTED png_const_bytep gamma_table = png_ptr->gamma_table; png_const_bytep gamma_from_1 = png_ptr->gamma_from_1; png_const_bytep gamma_to_1 = png_ptr->gamma_to_1; png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table; png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; int gamma_shift = png_ptr->gamma_shift; int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; #endif png_bytep sp; png_uint_32 i; png_uint_32 row_width = row_info->width; int shift; png_debug(1, "in png_do_compose"); { switch (row_info->color_type) { case PNG_COLOR_TYPE_GRAY: { switch (row_info->bit_depth) { case 1: { sp = row; shift = 7; for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x01) == png_ptr->trans_color.gray) { unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); tmp |= (unsigned int)(png_ptr->background.gray << shift); *sp = (png_byte)(tmp & 0xff); } if (shift == 0) { shift = 7; sp++; } else shift--; } break; } case 2: { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_table != NULL) { sp = row; shift = 6; for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x03) == png_ptr->trans_color.gray) { unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); tmp |= (unsigned int)png_ptr->background.gray << shift; *sp = (png_byte)(tmp & 0xff); } else { unsigned int p = (*sp >> shift) & 0x03; unsigned int g = (gamma_table [p | (p << 2) | (p << 4) | (p << 6)] >> 6) & 0x03; unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); tmp |= (unsigned int)(g << shift); *sp = (png_byte)(tmp & 0xff); } if (shift == 0) { shift = 6; sp++; } else shift -= 2; } } else #endif { sp = row; shift = 6; for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x03) == png_ptr->trans_color.gray) { unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); tmp |= (unsigned int)png_ptr->background.gray << shift; *sp = (png_byte)(tmp & 0xff); } if (shift == 0) { shift = 6; sp++; } else shift -= 2; } } break; } case 4: { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_table != NULL) { sp = row; shift = 4; for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x0f) == png_ptr->trans_color.gray) { unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); tmp |= (unsigned int)(png_ptr->background.gray << shift); *sp = (png_byte)(tmp & 0xff); } else { unsigned int p = (*sp >> shift) & 0x0f; unsigned int g = (gamma_table[p | (p << 4)] >> 4) & 0x0f; unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); tmp |= (unsigned int)(g << shift); *sp = (png_byte)(tmp & 0xff); } if (shift == 0) { shift = 4; sp++; } else shift -= 4; } } else #endif { sp = row; shift = 4; for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x0f) == png_ptr->trans_color.gray) { unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); tmp |= (unsigned int)(png_ptr->background.gray << shift); *sp = (png_byte)(tmp & 0xff); } if (shift == 0) { shift = 4; sp++; } else shift -= 4; } } break; } case 8: { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_table != NULL) { sp = row; for (i = 0; i < row_width; i++, sp++) { if (*sp == png_ptr->trans_color.gray) *sp = (png_byte)png_ptr->background.gray; else *sp = gamma_table[*sp]; } } else #endif { sp = row; for (i = 0; i < row_width; i++, sp++) { if (*sp == png_ptr->trans_color.gray) *sp = (png_byte)png_ptr->background.gray; } } break; } case 16: { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_16 != NULL) { sp = row; for (i = 0; i < row_width; i++, sp += 2) { png_uint_16 v; v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); if (v == png_ptr->trans_color.gray) { /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } else { v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); } } } else #endif { sp = row; for (i = 0; i < row_width; i++, sp += 2) { png_uint_16 v; v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); if (v == png_ptr->trans_color.gray) { *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } } } break; } default: break; } break; } case PNG_COLOR_TYPE_RGB: { if (row_info->bit_depth == 8) { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_table != NULL) { sp = row; for (i = 0; i < row_width; i++, sp += 3) { if (*sp == png_ptr->trans_color.red && *(sp + 1) == png_ptr->trans_color.green && *(sp + 2) == png_ptr->trans_color.blue) { *sp = (png_byte)png_ptr->background.red; *(sp + 1) = (png_byte)png_ptr->background.green; *(sp + 2) = (png_byte)png_ptr->background.blue; } else { *sp = gamma_table[*sp]; *(sp + 1) = gamma_table[*(sp + 1)]; *(sp + 2) = gamma_table[*(sp + 2)]; } } } else #endif { sp = row; for (i = 0; i < row_width; i++, sp += 3) { if (*sp == png_ptr->trans_color.red && *(sp + 1) == png_ptr->trans_color.green && *(sp + 2) == png_ptr->trans_color.blue) { *sp = (png_byte)png_ptr->background.red; *(sp + 1) = (png_byte)png_ptr->background.green; *(sp + 2) = (png_byte)png_ptr->background.blue; } } } } else /* if (row_info->bit_depth == 16) */ { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_16 != NULL) { sp = row; for (i = 0; i < row_width; i++, sp += 6) { png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + *(sp + 3)); png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + *(sp + 5)); if (r == png_ptr->trans_color.red && g == png_ptr->trans_color.green && b == png_ptr->trans_color.blue) { /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } else { png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; *(sp + 2) = (png_byte)((v >> 8) & 0xff); *(sp + 3) = (png_byte)(v & 0xff); v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; *(sp + 4) = (png_byte)((v >> 8) & 0xff); *(sp + 5) = (png_byte)(v & 0xff); } } } else #endif { sp = row; for (i = 0; i < row_width; i++, sp += 6) { png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + *(sp + 3)); png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + *(sp + 5)); if (r == png_ptr->trans_color.red && g == png_ptr->trans_color.green && b == png_ptr->trans_color.blue) { *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } } } } break; } case PNG_COLOR_TYPE_GRAY_ALPHA: { if (row_info->bit_depth == 8) { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_to_1 != NULL && gamma_from_1 != NULL && gamma_table != NULL) { sp = row; for (i = 0; i < row_width; i++, sp += 2) { png_uint_16 a = *(sp + 1); if (a == 0xff) *sp = gamma_table[*sp]; else if (a == 0) { /* Background is already in screen gamma */ *sp = (png_byte)png_ptr->background.gray; } else { png_byte v, w; v = gamma_to_1[*sp]; png_composite(w, v, a, png_ptr->background_1.gray); if (optimize == 0) w = gamma_from_1[w]; *sp = w; } } } else #endif { sp = row; for (i = 0; i < row_width; i++, sp += 2) { png_byte a = *(sp + 1); if (a == 0) *sp = (png_byte)png_ptr->background.gray; else if (a < 0xff) png_composite(*sp, *sp, a, png_ptr->background.gray); } } } else /* if (png_ptr->bit_depth == 16) */ { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_16 != NULL && gamma_16_from_1 != NULL && gamma_16_to_1 != NULL) { sp = row; for (i = 0; i < row_width; i++, sp += 4) { png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + *(sp + 3)); if (a == (png_uint_16)0xffff) { png_uint_16 v; v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); } else if (a == 0) { /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } else { png_uint_16 g, v, w; g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; png_composite_16(v, g, a, png_ptr->background_1.gray); if (optimize != 0) w = v; else w = gamma_16_from_1[(v & 0xff) >> gamma_shift][v >> 8]; *sp = (png_byte)((w >> 8) & 0xff); *(sp + 1) = (png_byte)(w & 0xff); } } } else #endif { sp = row; for (i = 0; i < row_width; i++, sp += 4) { png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + *(sp + 3)); if (a == 0) { *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } else if (a < 0xffff) { png_uint_16 g, v; g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); png_composite_16(v, g, a, png_ptr->background.gray); *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); } } } } break; } case PNG_COLOR_TYPE_RGB_ALPHA: { if (row_info->bit_depth == 8) { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_to_1 != NULL && gamma_from_1 != NULL && gamma_table != NULL) { sp = row; for (i = 0; i < row_width; i++, sp += 4) { png_byte a = *(sp + 3); if (a == 0xff) { *sp = gamma_table[*sp]; *(sp + 1) = gamma_table[*(sp + 1)]; *(sp + 2) = gamma_table[*(sp + 2)]; } else if (a == 0) { /* Background is already in screen gamma */ *sp = (png_byte)png_ptr->background.red; *(sp + 1) = (png_byte)png_ptr->background.green; *(sp + 2) = (png_byte)png_ptr->background.blue; } else { png_byte v, w; v = gamma_to_1[*sp]; png_composite(w, v, a, png_ptr->background_1.red); if (optimize == 0) w = gamma_from_1[w]; *sp = w; v = gamma_to_1[*(sp + 1)]; png_composite(w, v, a, png_ptr->background_1.green); if (optimize == 0) w = gamma_from_1[w]; *(sp + 1) = w; v = gamma_to_1[*(sp + 2)]; png_composite(w, v, a, png_ptr->background_1.blue); if (optimize == 0) w = gamma_from_1[w]; *(sp + 2) = w; } } } else #endif { sp = row; for (i = 0; i < row_width; i++, sp += 4) { png_byte a = *(sp + 3); if (a == 0) { *sp = (png_byte)png_ptr->background.red; *(sp + 1) = (png_byte)png_ptr->background.green; *(sp + 2) = (png_byte)png_ptr->background.blue; } else if (a < 0xff) { png_composite(*sp, *sp, a, png_ptr->background.red); png_composite(*(sp + 1), *(sp + 1), a, png_ptr->background.green); png_composite(*(sp + 2), *(sp + 2), a, png_ptr->background.blue); } } } } else /* if (row_info->bit_depth == 16) */ { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_16 != NULL && gamma_16_from_1 != NULL && gamma_16_to_1 != NULL) { sp = row; for (i = 0; i < row_width; i++, sp += 8) { png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) << 8) + (png_uint_16)(*(sp + 7))); if (a == (png_uint_16)0xffff) { png_uint_16 v; v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; *(sp + 2) = (png_byte)((v >> 8) & 0xff); *(sp + 3) = (png_byte)(v & 0xff); v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; *(sp + 4) = (png_byte)((v >> 8) & 0xff); *(sp + 5) = (png_byte)(v & 0xff); } else if (a == 0) { /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } else { png_uint_16 v, w; v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; png_composite_16(w, v, a, png_ptr->background_1.red); if (optimize == 0) w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> 8]; *sp = (png_byte)((w >> 8) & 0xff); *(sp + 1) = (png_byte)(w & 0xff); v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; png_composite_16(w, v, a, png_ptr->background_1.green); if (optimize == 0) w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> 8]; *(sp + 2) = (png_byte)((w >> 8) & 0xff); *(sp + 3) = (png_byte)(w & 0xff); v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; png_composite_16(w, v, a, png_ptr->background_1.blue); if (optimize == 0) w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> 8]; *(sp + 4) = (png_byte)((w >> 8) & 0xff); *(sp + 5) = (png_byte)(w & 0xff); } } } else #endif { sp = row; for (i = 0; i < row_width; i++, sp += 8) { png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) << 8) + (png_uint_16)(*(sp + 7))); if (a == 0) { *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } else if (a < 0xffff) { png_uint_16 v; png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + *(sp + 3)); png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + *(sp + 5)); png_composite_16(v, r, a, png_ptr->background.red); *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); png_composite_16(v, g, a, png_ptr->background.green); *(sp + 2) = (png_byte)((v >> 8) & 0xff); *(sp + 3) = (png_byte)(v & 0xff); png_composite_16(v, b, a, png_ptr->background.blue); *(sp + 4) = (png_byte)((v >> 8) & 0xff); *(sp + 5) = (png_byte)(v & 0xff); } } } } break; } default: break; } } } #endif /* READ_BACKGROUND || READ_ALPHA_MODE */ #ifdef PNG_READ_GAMMA_SUPPORTED /* Gamma correct the image, avoiding the alpha channel. Make sure * you do this after you deal with the transparency issue on grayscale * or RGB images. If your bit depth is 8, use gamma_table, if it * is 16, use gamma_16_table and gamma_shift. Build these with * build_gamma_table(). */ static void png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { png_const_bytep gamma_table = png_ptr->gamma_table; png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; int gamma_shift = png_ptr->gamma_shift; png_bytep sp; png_uint_32 i; png_uint_32 row_width=row_info->width; png_debug(1, "in png_do_gamma"); if (((row_info->bit_depth <= 8 && gamma_table != NULL) || (row_info->bit_depth == 16 && gamma_16_table != NULL))) { switch (row_info->color_type) { case PNG_COLOR_TYPE_RGB: { if (row_info->bit_depth == 8) { sp = row; for (i = 0; i < row_width; i++) { *sp = gamma_table[*sp]; sp++; *sp = gamma_table[*sp]; sp++; *sp = gamma_table[*sp]; sp++; } } else /* if (row_info->bit_depth == 16) */ { sp = row; for (i = 0; i < row_width; i++) { png_uint_16 v; v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); sp += 2; v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); sp += 2; v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); sp += 2; } } break; } case PNG_COLOR_TYPE_RGB_ALPHA: { if (row_info->bit_depth == 8) { sp = row; for (i = 0; i < row_width; i++) { *sp = gamma_table[*sp]; sp++; *sp = gamma_table[*sp]; sp++; *sp = gamma_table[*sp]; sp++; sp++; } } else /* if (row_info->bit_depth == 16) */ { sp = row; for (i = 0; i < row_width; i++) { png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); sp += 2; v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); sp += 2; v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); sp += 4; } } break; } case PNG_COLOR_TYPE_GRAY_ALPHA: { if (row_info->bit_depth == 8) { sp = row; for (i = 0; i < row_width; i++) { *sp = gamma_table[*sp]; sp += 2; } } else /* if (row_info->bit_depth == 16) */ { sp = row; for (i = 0; i < row_width; i++) { png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); sp += 4; } } break; } case PNG_COLOR_TYPE_GRAY: { if (row_info->bit_depth == 2) { sp = row; for (i = 0; i < row_width; i += 4) { int a = *sp & 0xc0; int b = *sp & 0x30; int c = *sp & 0x0c; int d = *sp & 0x03; *sp = (png_byte)( ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)| ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)| ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)| ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) )); sp++; } } if (row_info->bit_depth == 4) { sp = row; for (i = 0; i < row_width; i += 2) { int msb = *sp & 0xf0; int lsb = *sp & 0x0f; *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0) | (((int)gamma_table[(lsb << 4) | lsb]) >> 4)); sp++; } } else if (row_info->bit_depth == 8) { sp = row; for (i = 0; i < row_width; i++) { *sp = gamma_table[*sp]; sp++; } } else if (row_info->bit_depth == 16) { sp = row; for (i = 0; i < row_width; i++) { png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); sp += 2; } } break; } default: break; } } } #endif #ifdef PNG_READ_ALPHA_MODE_SUPPORTED /* Encode the alpha channel to the output gamma (the input channel is always * linear.) Called only with color types that have an alpha channel. Needs the * from_1 tables. */ static void png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { png_uint_32 row_width = row_info->width; png_debug(1, "in png_do_encode_alpha"); if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) { if (row_info->bit_depth == 8) { PNG_CONST png_bytep table = png_ptr->gamma_from_1; if (table != NULL) { PNG_CONST int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; /* The alpha channel is the last component: */ row += step - 1; for (; row_width > 0; --row_width, row += step) *row = table[*row]; return; } } else if (row_info->bit_depth == 16) { PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1; PNG_CONST int gamma_shift = png_ptr->gamma_shift; if (table != NULL) { PNG_CONST int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; /* The alpha channel is the last component: */ row += step - 2; for (; row_width > 0; --row_width, row += step) { png_uint_16 v; v = table[*(row + 1) >> gamma_shift][*row]; *row = (png_byte)((v >> 8) & 0xff); *(row + 1) = (png_byte)(v & 0xff); } return; } } } /* Only get to here if called with a weird row_info; no harm has been done, * so just issue a warning. */ png_warning(png_ptr, "png_do_encode_alpha: unexpected call"); } #endif #ifdef PNG_READ_EXPAND_SUPPORTED /* Expands a palette row to an RGB or RGBA row depending * upon whether you supply trans and num_trans. */ static void png_do_expand_palette(png_row_infop row_info, png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) { int shift, value; png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width=row_info->width; png_debug(1, "in png_do_expand_palette"); if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) { if (row_info->bit_depth < 8) { switch (row_info->bit_depth) { case 1: { sp = row + (png_size_t)((row_width - 1) >> 3); dp = row + (png_size_t)row_width - 1; shift = 7 - (int)((row_width + 7) & 0x07); for (i = 0; i < row_width; i++) { if ((*sp >> shift) & 0x01) *dp = 1; else *dp = 0; if (shift == 7) { shift = 0; sp--; } else shift++; dp--; } break; } case 2: { sp = row + (png_size_t)((row_width - 1) >> 2); dp = row + (png_size_t)row_width - 1; shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); for (i = 0; i < row_width; i++) { value = (*sp >> shift) & 0x03; *dp = (png_byte)value; if (shift == 6) { shift = 0; sp--; } else shift += 2; dp--; } break; } case 4: { sp = row + (png_size_t)((row_width - 1) >> 1); dp = row + (png_size_t)row_width - 1; shift = (int)((row_width & 0x01) << 2); for (i = 0; i < row_width; i++) { value = (*sp >> shift) & 0x0f; *dp = (png_byte)value; if (shift == 4) { shift = 0; sp--; } else shift += 4; dp--; } break; } default: break; } row_info->bit_depth = 8; row_info->pixel_depth = 8; row_info->rowbytes = row_width; } if (row_info->bit_depth == 8) { { if (num_trans > 0) { sp = row + (png_size_t)row_width - 1; dp = row + ((png_size_t)row_width << 2) - 1; for (i = 0; i < row_width; i++) { if ((int)(*sp) >= num_trans) *dp-- = 0xff; else *dp-- = trans_alpha[*sp]; *dp-- = palette[*sp].blue; *dp-- = palette[*sp].green; *dp-- = palette[*sp].red; sp--; } row_info->bit_depth = 8; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; row_info->color_type = 6; row_info->channels = 4; } else { sp = row + (png_size_t)row_width - 1; dp = row + (png_size_t)(row_width * 3) - 1; for (i = 0; i < row_width; i++) { *dp-- = palette[*sp].blue; *dp-- = palette[*sp].green; *dp-- = palette[*sp].red; sp--; } row_info->bit_depth = 8; row_info->pixel_depth = 24; row_info->rowbytes = row_width * 3; row_info->color_type = 2; row_info->channels = 3; } } } } } /* If the bit depth < 8, it is expanded to 8. Also, if the already * expanded transparency value is supplied, an alpha channel is built. */ static void png_do_expand(png_row_infop row_info, png_bytep row, png_const_color_16p trans_color) { int shift, value; png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width=row_info->width; png_debug(1, "in png_do_expand"); { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { unsigned int gray = trans_color != NULL ? trans_color->gray : 0; if (row_info->bit_depth < 8) { switch (row_info->bit_depth) { case 1: { gray = (gray & 0x01) * 0xff; sp = row + (png_size_t)((row_width - 1) >> 3); dp = row + (png_size_t)row_width - 1; shift = 7 - (int)((row_width + 7) & 0x07); for (i = 0; i < row_width; i++) { if ((*sp >> shift) & 0x01) *dp = 0xff; else *dp = 0; if (shift == 7) { shift = 0; sp--; } else shift++; dp--; } break; } case 2: { gray = (gray & 0x03) * 0x55; sp = row + (png_size_t)((row_width - 1) >> 2); dp = row + (png_size_t)row_width - 1; shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); for (i = 0; i < row_width; i++) { value = (*sp >> shift) & 0x03; *dp = (png_byte)(value | (value << 2) | (value << 4) | (value << 6)); if (shift == 6) { shift = 0; sp--; } else shift += 2; dp--; } break; } case 4: { gray = (gray & 0x0f) * 0x11; sp = row + (png_size_t)((row_width - 1) >> 1); dp = row + (png_size_t)row_width - 1; shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); for (i = 0; i < row_width; i++) { value = (*sp >> shift) & 0x0f; *dp = (png_byte)(value | (value << 4)); if (shift == 4) { shift = 0; sp--; } else shift = 4; dp--; } break; } default: break; } row_info->bit_depth = 8; row_info->pixel_depth = 8; row_info->rowbytes = row_width; } if (trans_color != NULL) { if (row_info->bit_depth == 8) { gray = gray & 0xff; sp = row + (png_size_t)row_width - 1; dp = row + ((png_size_t)row_width << 1) - 1; for (i = 0; i < row_width; i++) { if ((*sp & 0xffU) == gray) *dp-- = 0; else *dp-- = 0xff; *dp-- = *sp--; } } else if (row_info->bit_depth == 16) { unsigned int gray_high = (gray >> 8) & 0xff; unsigned int gray_low = gray & 0xff; sp = row + row_info->rowbytes - 1; dp = row + (row_info->rowbytes << 1) - 1; for (i = 0; i < row_width; i++) { if ((*(sp - 1) & 0xffU) == gray_high && (*(sp) & 0xffU) == gray_low) { *dp-- = 0; *dp-- = 0; } else { *dp-- = 0xff; *dp-- = 0xff; } *dp-- = *sp--; *dp-- = *sp--; } } row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; row_info->channels = 2; row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } } else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color != NULL) { if (row_info->bit_depth == 8) { png_byte red = (png_byte)(trans_color->red & 0xff); png_byte green = (png_byte)(trans_color->green & 0xff); png_byte blue = (png_byte)(trans_color->blue & 0xff); sp = row + (png_size_t)row_info->rowbytes - 1; dp = row + ((png_size_t)row_width << 2) - 1; for (i = 0; i < row_width; i++) { if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) *dp-- = 0; else *dp-- = 0xff; *dp-- = *sp--; *dp-- = *sp--; *dp-- = *sp--; } } else if (row_info->bit_depth == 16) { png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); png_byte red_low = (png_byte)(trans_color->red & 0xff); png_byte green_low = (png_byte)(trans_color->green & 0xff); png_byte blue_low = (png_byte)(trans_color->blue & 0xff); sp = row + row_info->rowbytes - 1; dp = row + ((png_size_t)row_width << 3) - 1; for (i = 0; i < row_width; i++) { if (*(sp - 5) == red_high && *(sp - 4) == red_low && *(sp - 3) == green_high && *(sp - 2) == green_low && *(sp - 1) == blue_high && *(sp ) == blue_low) { *dp-- = 0; *dp-- = 0; } else { *dp-- = 0xff; *dp-- = 0xff; } *dp-- = *sp--; *dp-- = *sp--; *dp-- = *sp--; *dp-- = *sp--; *dp-- = *sp--; *dp-- = *sp--; } } row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; row_info->channels = 4; row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } } } #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED /* If the bit depth is 8 and the color type is not a palette type expand the * whole row to 16 bits. Has no effect otherwise. */ static void png_do_expand_16(png_row_infop row_info, png_bytep row) { if (row_info->bit_depth == 8 && row_info->color_type != PNG_COLOR_TYPE_PALETTE) { /* The row have a sequence of bytes containing [0..255] and we need * to turn it into another row containing [0..65535], to do this we * calculate: * * (input / 255) * 65535 * * Which happens to be exactly input * 257 and this can be achieved * simply by byte replication in place (copying backwards). */ png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */ png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */ while (dp > sp) { dp[-2] = dp[-1] = *--sp; dp -= 2; } row_info->rowbytes *= 2; row_info->bit_depth = 16; row_info->pixel_depth = (png_byte)(row_info->channels * 16); } } #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED static void png_do_quantize(png_row_infop row_info, png_bytep row, png_const_bytep palette_lookup, png_const_bytep quantize_lookup) { png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width=row_info->width; png_debug(1, "in png_do_quantize"); if (row_info->bit_depth == 8) { if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup) { int r, g, b, p; sp = row; dp = row; for (i = 0; i < row_width; i++) { r = *sp++; g = *sp++; b = *sp++; /* This looks real messy, but the compiler will reduce * it down to a reasonable formula. For example, with * 5 bits per color, we get: * p = (((r >> 3) & 0x1f) << 10) | * (((g >> 3) & 0x1f) << 5) | * ((b >> 3) & 0x1f); */ p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << (PNG_QUANTIZE_BLUE_BITS)) | ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); *dp++ = palette_lookup[p]; } row_info->color_type = PNG_COLOR_TYPE_PALETTE; row_info->channels = 1; row_info->pixel_depth = row_info->bit_depth; row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA && palette_lookup != NULL) { int r, g, b, p; sp = row; dp = row; for (i = 0; i < row_width; i++) { r = *sp++; g = *sp++; b = *sp++; sp++; p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) & ((1 << PNG_QUANTIZE_RED_BITS) - 1)) << (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) | (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) & ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) << (PNG_QUANTIZE_BLUE_BITS)) | ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) & ((1 << PNG_QUANTIZE_BLUE_BITS) - 1)); *dp++ = palette_lookup[p]; } row_info->color_type = PNG_COLOR_TYPE_PALETTE; row_info->channels = 1; row_info->pixel_depth = row_info->bit_depth; row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && quantize_lookup) { sp = row; for (i = 0; i < row_width; i++, sp++) { *sp = quantize_lookup[*sp]; } } } } #endif /* READ_QUANTIZE */ /* Transform the row. The order of transformations is significant, * and is very touchy. If you add a transformation, take care to * decide how it fits in with the other transformations here. */ void /* PRIVATE */ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) { png_debug(1, "in png_do_read_transformations"); if (png_ptr->row_buf == NULL) { /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this * error is incredibly rare and incredibly easy to debug without this * information. */ png_error(png_ptr, "NULL row buffer"); } /* The following is debugging; prior to 1.5.4 the code was never compiled in; * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for * all transformations, however in practice the ROW_INIT always gets done on * demand, if necessary. */ if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) { /* Application has failed to call either png_read_start_image() or * png_read_update_info() after setting transforms that expand pixels. * This check added to libpng-1.2.19 (but not enabled until 1.5.4). */ png_error(png_ptr, "Uninitialized row"); } #ifdef PNG_READ_EXPAND_SUPPORTED if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) { png_do_expand_palette(row_info, png_ptr->row_buf + 1, png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); } else { if (png_ptr->num_trans != 0 && (png_ptr->transformations & PNG_EXPAND_tRNS) != 0) png_do_expand(row_info, png_ptr->row_buf + 1, &(png_ptr->trans_color)); else png_do_expand(row_info, png_ptr->row_buf + 1, NULL); } } #endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && (png_ptr->transformations & PNG_COMPOSE) == 0 && (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_do_strip_channel(row_info, png_ptr->row_buf + 1, 0 /* at_start == false, because SWAP_ALPHA happens later */); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) { int rgb_error = png_do_rgb_to_gray(png_ptr, row_info, png_ptr->row_buf + 1); if (rgb_error != 0) { png_ptr->rgb_to_gray_status=1; if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == PNG_RGB_TO_GRAY_WARN) png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == PNG_RGB_TO_GRAY_ERR) png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); } } #endif /* From Andreas Dilger e-mail to png-implement, 26 March 1998: * * In most cases, the "simple transparency" should be done prior to doing * gray-to-RGB, or you will have to test 3x as many bytes to check if a * pixel is transparent. You would also need to make sure that the * transparency information is upgraded to RGB. * * To summarize, the current flow is: * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite * with background "in place" if transparent, * convert to RGB if necessary * - Gray + alpha -> composite with gray background and remove alpha bytes, * convert to RGB if necessary * * To support RGB backgrounds for gray images we need: * - Gray + simple transparency -> convert to RGB + simple transparency, * compare 3 or 6 bytes and composite with * background "in place" if transparent * (3x compare/pixel compared to doing * composite with gray bkgrnd) * - Gray + alpha -> convert to RGB + alpha, composite with background and * remove alpha bytes (3x float * operations/pixel compared with composite * on gray background) * * Greg's change will do this. The reason it wasn't done before is for * performance, as this increases the per-pixel operations. If we would check * in advance if the background was gray or RGB, and position the gray-to-RGB * transform appropriately, then it would save a lot of work/time. */ #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* If gray -> RGB, do so now only if background is non-gray; else do later * for performance reasons */ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0) png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ defined(PNG_READ_ALPHA_MODE_SUPPORTED) if ((png_ptr->transformations & PNG_COMPOSE) != 0) png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); #endif #ifdef PNG_READ_GAMMA_SUPPORTED if ((png_ptr->transformations & PNG_GAMMA) != 0 && #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Because RGB_TO_GRAY does the gamma transform. */ (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 && #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* Because PNG_COMPOSE does the gamma transform if there is something to * do (if there is an alpha channel or transparency.) */ !((png_ptr->transformations & PNG_COMPOSE) != 0 && ((png_ptr->num_trans != 0) || (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) && #endif /* Because png_init_read_transformations transforms the palette, unless * RGB_TO_GRAY will do the transform. */ (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); #endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && (png_ptr->transformations & PNG_COMPOSE) != 0 && (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_do_strip_channel(row_info, png_ptr->row_buf + 1, 0 /* at_start == false, because SWAP_ALPHA happens later */); #endif #ifdef PNG_READ_ALPHA_MODE_SUPPORTED if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); #endif #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* There is no harm in doing both of these because only one has any effect, * by putting the 'scale' option first if the app asks for scale (either by * calling the API or in a TRANSFORM flag) this is what happens. */ if ((png_ptr->transformations & PNG_16_TO_8) != 0) png_do_chop(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED if ((png_ptr->transformations & PNG_QUANTIZE) != 0) { png_do_quantize(row_info, png_ptr->row_buf + 1, png_ptr->palette_lookup, png_ptr->quantize_index); if (row_info->rowbytes == 0) png_error(png_ptr, "png_do_quantize returned rowbytes=0"); } #endif /* READ_QUANTIZE */ #ifdef PNG_READ_EXPAND_16_SUPPORTED /* Do the expansion now, after all the arithmetic has been done. Notice * that previous transformations can handle the PNG_EXPAND_16 flag if this * is efficient (particularly true in the case of gamma correction, where * better accuracy results faster!) */ if ((png_ptr->transformations & PNG_EXPAND_16) != 0) png_do_expand_16(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* NOTE: moved here in 1.5.4 (from much later in this list.) */ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0) png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_INVERT_SUPPORTED if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) png_do_invert(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_SHIFT_SUPPORTED if ((png_ptr->transformations & PNG_SHIFT) != 0) png_do_unshift(row_info, png_ptr->row_buf + 1, &(png_ptr->shift)); #endif #ifdef PNG_READ_PACK_SUPPORTED if ((png_ptr->transformations & PNG_PACK) != 0) png_do_unpack(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Added at libpng-1.5.10 */ if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_palette_max >= 0) png_do_check_palette_indexes(png_ptr, row_info); #endif #ifdef PNG_READ_BGR_SUPPORTED if ((png_ptr->transformations & PNG_BGR) != 0) png_do_bgr(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_PACKSWAP_SUPPORTED if ((png_ptr->transformations & PNG_PACKSWAP) != 0) png_do_packswap(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_FILLER_SUPPORTED if ((png_ptr->transformations & PNG_FILLER) != 0) png_do_read_filler(row_info, png_ptr->row_buf + 1, (png_uint_32)png_ptr->filler, png_ptr->flags); #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_READ_16BIT_SUPPORTED #ifdef PNG_READ_SWAP_SUPPORTED if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_do_swap(row_info, png_ptr->row_buf + 1); #endif #endif #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) { if (png_ptr->read_user_transform_fn != NULL) (*(png_ptr->read_user_transform_fn)) /* User read transform function */ (png_ptr, /* png_ptr */ row_info, /* row_info: */ /* png_uint_32 width; width of row */ /* png_size_t rowbytes; number of bytes in row */ /* png_byte color_type; color type of pixels */ /* png_byte bit_depth; bit depth of samples */ /* png_byte channels; number of channels (1-4) */ /* png_byte pixel_depth; bits per pixel (depth*channels) */ png_ptr->row_buf + 1); /* start of pixel data for row */ #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED if (png_ptr->user_transform_depth != 0) row_info->bit_depth = png_ptr->user_transform_depth; if (png_ptr->user_transform_channels != 0) row_info->channels = png_ptr->user_transform_channels; #endif row_info->pixel_depth = (png_byte)(row_info->bit_depth * row_info->channels); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); } #endif } #endif /* READ_TRANSFORMS */ #endif /* READ */ stella-5.1.1/src/libpng/pngrutil.c000066400000000000000000004373621324334165500171010ustar00rootroot00000000000000 /* pngrutil.c - utilities to read a PNG file * * Last changed in libpng 1.6.33 [September 28, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * This file contains routines that are only called from within * libpng itself during the course of reading an image. */ #include "pngpriv.h" #ifdef PNG_READ_SUPPORTED png_uint_32 PNGAPI png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); if (uval > PNG_UINT_31_MAX) png_error(png_ptr, "PNG unsigned integer out of range"); return (uval); } #if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED) /* The following is a variation on the above for use with the fixed * point values used for gAMA and cHRM. Instead of png_error it * issues a warning and returns (-1) - an invalid value because both * gAMA and cHRM use *unsigned* integers for fixed point values. */ #define PNG_FIXED_ERROR (-1) static png_fixed_point /* PRIVATE */ png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); if (uval <= PNG_UINT_31_MAX) return (png_fixed_point)uval; /* known to be in range */ /* The caller can turn off the warning by passing NULL. */ if (png_ptr != NULL) png_warning(png_ptr, "PNG fixed point integer out of range"); return PNG_FIXED_ERROR; } #endif #ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED /* NOTE: the read macros will obscure these definitions, so that if * PNG_USE_READ_MACROS is set the library will not use them internally, * but the APIs will still be available externally. * * The parentheses around "PNGAPI function_name" in the following three * functions are necessary because they allow the macros to co-exist with * these (unused but exported) functions. */ /* Grab an unsigned 32-bit integer from a buffer in big-endian format. */ png_uint_32 (PNGAPI png_get_uint_32)(png_const_bytep buf) { png_uint_32 uval = ((png_uint_32)(*(buf )) << 24) + ((png_uint_32)(*(buf + 1)) << 16) + ((png_uint_32)(*(buf + 2)) << 8) + ((png_uint_32)(*(buf + 3)) ) ; return uval; } /* Grab a signed 32-bit integer from a buffer in big-endian format. The * data is stored in the PNG file in two's complement format and there * is no guarantee that a 'png_int_32' is exactly 32 bits, therefore * the following code does a two's complement to native conversion. */ png_int_32 (PNGAPI png_get_int_32)(png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); if ((uval & 0x80000000) == 0) /* non-negative */ return (png_int_32)uval; uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ if ((uval & 0x80000000) == 0) /* no overflow */ return -(png_int_32)uval; /* The following has to be safe; this function only gets called on PNG data * and if we get here that data is invalid. 0 is the most safe value and * if not then an attacker would surely just generate a PNG with 0 instead. */ return 0; } /* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ png_uint_16 (PNGAPI png_get_uint_16)(png_const_bytep buf) { /* ANSI-C requires an int value to accomodate at least 16 bits so this * works and allows the compiler not to worry about possible narrowing * on 32-bit systems. (Pre-ANSI systems did not make integers smaller * than 16 bits either.) */ unsigned int val = ((unsigned int)(*buf) << 8) + ((unsigned int)(*(buf + 1))); return (png_uint_16)val; } #endif /* READ_INT_FUNCTIONS */ /* Read and check the PNG file signature */ void /* PRIVATE */ png_read_sig(png_structrp png_ptr, png_inforp info_ptr) { png_size_t num_checked, num_to_check; /* Exit if the user application does not expect a signature. */ if (png_ptr->sig_bytes >= 8) return; num_checked = png_ptr->sig_bytes; num_to_check = 8 - num_checked; #ifdef PNG_IO_STATE_SUPPORTED png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; #endif /* The signature must be serialized in a single I/O call. */ png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); png_ptr->sig_bytes = 8; if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0) { if (num_checked < 4 && png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) png_error(png_ptr, "Not a PNG file"); else png_error(png_ptr, "PNG file corrupted by ASCII conversion"); } if (num_checked < 3) png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; } /* Read the chunk header (length + type name). * Put the type name into png_ptr->chunk_name, and return the length. */ png_uint_32 /* PRIVATE */ png_read_chunk_header(png_structrp png_ptr) { png_byte buf[8]; png_uint_32 length; #ifdef PNG_IO_STATE_SUPPORTED png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; #endif /* Read the length and the chunk name. * This must be performed in a single I/O call. */ png_read_data(png_ptr, buf, 8); length = png_get_uint_31(png_ptr, buf); /* Put the chunk name into png_ptr->chunk_name. */ png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4); png_debug2(0, "Reading %lx chunk, length = %lu", (unsigned long)png_ptr->chunk_name, (unsigned long)length); /* Reset the crc and run it over the chunk name. */ png_reset_crc(png_ptr); png_calculate_crc(png_ptr, buf + 4, 4); /* Check to see if chunk name is valid. */ png_check_chunk_name(png_ptr, png_ptr->chunk_name); /* Check for too-large chunk length */ png_check_chunk_length(png_ptr, length); #ifdef PNG_IO_STATE_SUPPORTED png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; #endif return length; } /* Read data, and (optionally) run it through the CRC. */ void /* PRIVATE */ png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) { if (png_ptr == NULL) return; png_read_data(png_ptr, buf, length); png_calculate_crc(png_ptr, buf, length); } /* Optionally skip data and then check the CRC. Depending on whether we * are reading an ancillary or critical chunk, and how the program has set * things up, we may calculate the CRC on the data and print a message. * Returns '1' if there was a CRC error, '0' otherwise. */ int /* PRIVATE */ png_crc_finish(png_structrp png_ptr, png_uint_32 skip) { /* The size of the local buffer for inflate is a good guess as to a * reasonable size to use for buffering reads from the application. */ while (skip > 0) { png_uint_32 len; png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; len = (sizeof tmpbuf); if (len > skip) len = skip; skip -= len; png_crc_read(png_ptr, tmpbuf, len); } if (png_crc_error(png_ptr) != 0) { if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ? (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 : (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0) { png_chunk_warning(png_ptr, "CRC error"); } else png_chunk_error(png_ptr, "CRC error"); return (1); } return (0); } /* Compare the CRC stored in the PNG file with that calculated by libpng from * the data it has read thus far. */ int /* PRIVATE */ png_crc_error(png_structrp png_ptr) { png_byte crc_bytes[4]; png_uint_32 crc; int need_crc = 1; if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) need_crc = 0; } else /* critical */ { if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) need_crc = 0; } #ifdef PNG_IO_STATE_SUPPORTED png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; #endif /* The chunk CRC must be serialized in a single I/O call. */ png_read_data(png_ptr, crc_bytes, 4); if (need_crc != 0) { crc = png_get_uint_32(crc_bytes); return ((int)(crc != png_ptr->crc)); } else return (0); } #if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\ defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\ defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED) /* Manage the read buffer; this simply reallocates the buffer if it is not small * enough (or if it is not allocated). The routine returns a pointer to the * buffer; if an error occurs and 'warn' is set the routine returns NULL, else * it will call png_error (via png_malloc) on failure. (warn == 2 means * 'silent'). */ static png_bytep png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) { png_bytep buffer = png_ptr->read_buffer; if (buffer != NULL && new_size > png_ptr->read_buffer_size) { png_ptr->read_buffer = NULL; png_ptr->read_buffer = NULL; png_ptr->read_buffer_size = 0; png_free(png_ptr, buffer); buffer = NULL; } if (buffer == NULL) { buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size)); if (buffer != NULL) { memset(buffer, 0, new_size); /* just in case */ png_ptr->read_buffer = buffer; png_ptr->read_buffer_size = new_size; } else if (warn < 2) /* else silent */ { if (warn != 0) png_chunk_warning(png_ptr, "insufficient memory to read chunk"); else png_chunk_error(png_ptr, "insufficient memory to read chunk"); } } return buffer; } #endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */ /* png_inflate_claim: claim the zstream for some nefarious purpose that involves * decompression. Returns Z_OK on success, else a zlib error code. It checks * the owner but, in final release builds, just issues a warning if some other * chunk apparently owns the stream. Prior to release it does a png_error. */ static int png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) { if (png_ptr->zowner != 0) { char msg[64]; PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); /* So the message that results is " using zstream"; this is an * internal error, but is very useful for debugging. i18n requirements * are minimal. */ (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); #if PNG_RELEASE_BUILD png_chunk_warning(png_ptr, msg); png_ptr->zowner = 0; #else png_chunk_error(png_ptr, msg); #endif } /* Implementation note: unlike 'png_deflate_claim' this internal function * does not take the size of the data as an argument. Some efficiency could * be gained by using this when it is known *if* the zlib stream itself does * not record the number; however, this is an illusion: the original writer * of the PNG may have selected a lower window size, and we really must * follow that because, for systems with with limited capabilities, we * would otherwise reject the application's attempts to use a smaller window * size (zlib doesn't have an interface to say "this or lower"!). * * inflateReset2 was added to zlib 1.2.4; before this the window could not be * reset, therefore it is necessary to always allocate the maximum window * size with earlier zlibs just in case later compressed chunks need it. */ { int ret; /* zlib return code */ #if ZLIB_VERNUM >= 0x1240 int window_bits = 0; # if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW) if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == PNG_OPTION_ON) { window_bits = 15; png_ptr->zstream_start = 0; /* fixed window size */ } else { png_ptr->zstream_start = 1; } # endif #endif /* ZLIB_VERNUM >= 0x1240 */ /* Set this for safety, just in case the previous owner left pointers to * memory allocations. */ png_ptr->zstream.next_in = NULL; png_ptr->zstream.avail_in = 0; png_ptr->zstream.next_out = NULL; png_ptr->zstream.avail_out = 0; if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) { #if ZLIB_VERNUM >= 0x1240 ret = inflateReset2(&png_ptr->zstream, window_bits); #else ret = inflateReset(&png_ptr->zstream); #endif } else { #if ZLIB_VERNUM >= 0x1240 ret = inflateInit2(&png_ptr->zstream, window_bits); #else ret = inflateInit(&png_ptr->zstream); #endif if (ret == Z_OK) png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; } #if ZLIB_VERNUM >= 0x1290 && \ defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_IGNORE_ADLER32) if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON) /* Turn off validation of the ADLER32 checksum in IDAT chunks */ ret = inflateValidate(&png_ptr->zstream, 0); #endif if (ret == Z_OK) png_ptr->zowner = owner; else png_zstream_error(png_ptr, ret); return ret; } #ifdef window_bits # undef window_bits #endif } #if ZLIB_VERNUM >= 0x1240 /* Handle the start of the inflate stream if we called inflateInit2(strm,0); * in this case some zlib versions skip validation of the CINFO field and, in * certain circumstances, libpng may end up displaying an invalid image, in * contrast to implementations that call zlib in the normal way (e.g. libpng * 1.5). */ int /* PRIVATE */ png_zlib_inflate(png_structrp png_ptr, int flush) { if (png_ptr->zstream_start && png_ptr->zstream.avail_in > 0) { if ((*png_ptr->zstream.next_in >> 4) > 7) { png_ptr->zstream.msg = "invalid window size (libpng)"; return Z_DATA_ERROR; } png_ptr->zstream_start = 0; } return inflate(&png_ptr->zstream, flush); } #endif /* Zlib >= 1.2.4 */ #ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED #if defined(PNG_READ_zTXt_SUPPORTED) || defined (PNG_READ_iTXt_SUPPORTED) /* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to * allow the caller to do multiple calls if required. If the 'finish' flag is * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and * Z_OK or Z_STREAM_END will be returned on success. * * The input and output sizes are updated to the actual amounts of data consumed * or written, not the amount available (as in a z_stream). The data pointers * are not changed, so the next input is (data+input_size) and the next * available output is (output+output_size). */ static int png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr, /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr) { if (png_ptr->zowner == owner) /* Else not claimed */ { int ret; png_alloc_size_t avail_out = *output_size_ptr; png_uint_32 avail_in = *input_size_ptr; /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it * can't even necessarily handle 65536 bytes) because the type uInt is * "16 bits or more". Consequently it is necessary to chunk the input to * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the * maximum value that can be stored in a uInt.) It is possible to set * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have * a performance advantage, because it reduces the amount of data accessed * at each step and that may give the OS more time to page it in. */ png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); /* avail_in and avail_out are set below from 'size' */ png_ptr->zstream.avail_in = 0; png_ptr->zstream.avail_out = 0; /* Read directly into the output if it is available (this is set to * a local buffer below if output is NULL). */ if (output != NULL) png_ptr->zstream.next_out = output; do { uInt avail; Byte local_buffer[PNG_INFLATE_BUF_SIZE]; /* zlib INPUT BUFFER */ /* The setting of 'avail_in' used to be outside the loop; by setting it * inside it is possible to chunk the input to zlib and simply rely on * zlib to advance the 'next_in' pointer. This allows arbitrary * amounts of data to be passed through zlib at the unavoidable cost of * requiring a window save (memcpy of up to 32768 output bytes) * every ZLIB_IO_MAX input bytes. */ avail_in += png_ptr->zstream.avail_in; /* not consumed last time */ avail = ZLIB_IO_MAX; if (avail_in < avail) avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */ avail_in -= avail; png_ptr->zstream.avail_in = avail; /* zlib OUTPUT BUFFER */ avail_out += png_ptr->zstream.avail_out; /* not written last time */ avail = ZLIB_IO_MAX; /* maximum zlib can process */ if (output == NULL) { /* Reset the output buffer each time round if output is NULL and * make available the full buffer, up to 'remaining_space' */ png_ptr->zstream.next_out = local_buffer; if ((sizeof local_buffer) < avail) avail = (sizeof local_buffer); } if (avail_out < avail) avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */ png_ptr->zstream.avail_out = avail; avail_out -= avail; /* zlib inflate call */ /* In fact 'avail_out' may be 0 at this point, that happens at the end * of the read when the final LZ end code was not passed at the end of * the previous chunk of input data. Tell zlib if we have reached the * end of the output buffer. */ ret = PNG_INFLATE(png_ptr, avail_out > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); } while (ret == Z_OK); /* For safety kill the local buffer pointer now */ if (output == NULL) png_ptr->zstream.next_out = NULL; /* Claw back the 'size' and 'remaining_space' byte counts. */ avail_in += png_ptr->zstream.avail_in; avail_out += png_ptr->zstream.avail_out; /* Update the input and output sizes; the updated values are the amount * consumed or written, effectively the inverse of what zlib uses. */ if (avail_out > 0) *output_size_ptr -= avail_out; if (avail_in > 0) *input_size_ptr -= avail_in; /* Ensure png_ptr->zstream.msg is set (even in the success case!) */ png_zstream_error(png_ptr, ret); return ret; } else { /* This is a bad internal error. The recovery assigns to the zstream msg * pointer, which is not owned by the caller, but this is safe; it's only * used on errors! */ png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); return Z_STREAM_ERROR; } } /* * Decompress trailing data in a chunk. The assumption is that read_buffer * points at an allocated area holding the contents of a chunk with a * trailing compressed part. What we get back is an allocated area * holding the original prefix part and an uncompressed version of the * trailing part (the malloc area passed in is freed). */ static int png_decompress_chunk(png_structrp png_ptr, png_uint_32 chunklength, png_uint_32 prefix_size, png_alloc_size_t *newlength /* must be initialized to the maximum! */, int terminate /*add a '\0' to the end of the uncompressed data*/) { /* TODO: implement different limits for different types of chunk. * * The caller supplies *newlength set to the maximum length of the * uncompressed data, but this routine allocates space for the prefix and * maybe a '\0' terminator too. We have to assume that 'prefix_size' is * limited only by the maximum chunk size. */ png_alloc_size_t limit = PNG_SIZE_MAX; # ifdef PNG_SET_USER_LIMITS_SUPPORTED if (png_ptr->user_chunk_malloc_max > 0 && png_ptr->user_chunk_malloc_max < limit) limit = png_ptr->user_chunk_malloc_max; # elif PNG_USER_CHUNK_MALLOC_MAX > 0 if (PNG_USER_CHUNK_MALLOC_MAX < limit) limit = PNG_USER_CHUNK_MALLOC_MAX; # endif if (limit >= prefix_size + (terminate != 0)) { int ret; limit -= prefix_size + (terminate != 0); if (limit < *newlength) *newlength = limit; /* Now try to claim the stream. */ ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); if (ret == Z_OK) { png_uint_32 lzsize = chunklength - prefix_size; ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, /* output: */ NULL, newlength); if (ret == Z_STREAM_END) { /* Use 'inflateReset' here, not 'inflateReset2' because this * preserves the previously decided window size (otherwise it would * be necessary to store the previous window size.) In practice * this doesn't matter anyway, because png_inflate will call inflate * with Z_FINISH in almost all cases, so the window will not be * maintained. */ if (inflateReset(&png_ptr->zstream) == Z_OK) { /* Because of the limit checks above we know that the new, * expanded, size will fit in a size_t (let alone an * png_alloc_size_t). Use png_malloc_base here to avoid an * extra OOM message. */ png_alloc_size_t new_size = *newlength; png_alloc_size_t buffer_size = prefix_size + new_size + (terminate != 0); png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, buffer_size)); if (text != NULL) { memset(text, 0, buffer_size); ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, png_ptr->read_buffer + prefix_size, &lzsize, text + prefix_size, newlength); if (ret == Z_STREAM_END) { if (new_size == *newlength) { if (terminate != 0) text[prefix_size + *newlength] = 0; if (prefix_size > 0) memcpy(text, png_ptr->read_buffer, prefix_size); { png_bytep old_ptr = png_ptr->read_buffer; png_ptr->read_buffer = text; png_ptr->read_buffer_size = buffer_size; text = old_ptr; /* freed below */ } } else { /* The size changed on the second read, there can be no * guarantee that anything is correct at this point. * The 'msg' pointer has been set to "unexpected end of * LZ stream", which is fine, but return an error code * that the caller won't accept. */ ret = PNG_UNEXPECTED_ZLIB_RETURN; } } else if (ret == Z_OK) ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */ /* Free the text pointer (this is the old read_buffer on * success) */ png_free(png_ptr, text); /* This really is very benign, but it's still an error because * the extra space may otherwise be used as a Trojan Horse. */ if (ret == Z_STREAM_END && chunklength - prefix_size != lzsize) png_chunk_benign_error(png_ptr, "extra compressed data"); } else { /* Out of memory allocating the buffer */ ret = Z_MEM_ERROR; png_zstream_error(png_ptr, Z_MEM_ERROR); } } else { /* inflateReset failed, store the error message */ png_zstream_error(png_ptr, ret); ret = PNG_UNEXPECTED_ZLIB_RETURN; } } else if (ret == Z_OK) ret = PNG_UNEXPECTED_ZLIB_RETURN; /* Release the claimed stream */ png_ptr->zowner = 0; } else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */ ret = PNG_UNEXPECTED_ZLIB_RETURN; return ret; } else { /* Application/configuration limits exceeded */ png_zstream_error(png_ptr, Z_MEM_ERROR); return Z_MEM_ERROR; } } #endif /* READ_zTXt || READ_iTXt */ #endif /* READ_COMPRESSED_TEXT */ #ifdef PNG_READ_iCCP_SUPPORTED /* Perform a partial read and decompress, producing 'avail_out' bytes and * reading from the current chunk as required. */ static int png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, int finish) { if (png_ptr->zowner == png_ptr->chunk_name) { int ret; /* next_in and avail_in must have been initialized by the caller. */ png_ptr->zstream.next_out = next_out; png_ptr->zstream.avail_out = 0; /* set in the loop */ do { if (png_ptr->zstream.avail_in == 0) { if (read_size > *chunk_bytes) read_size = (uInt)*chunk_bytes; *chunk_bytes -= read_size; if (read_size > 0) png_crc_read(png_ptr, read_buffer, read_size); png_ptr->zstream.next_in = read_buffer; png_ptr->zstream.avail_in = read_size; } if (png_ptr->zstream.avail_out == 0) { uInt avail = ZLIB_IO_MAX; if (avail > *out_size) avail = (uInt)*out_size; *out_size -= avail; png_ptr->zstream.avail_out = avail; } /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all * the available output is produced; this allows reading of truncated * streams. */ ret = PNG_INFLATE(png_ptr, *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); } while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); *out_size += png_ptr->zstream.avail_out; png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ /* Ensure the error message pointer is always set: */ png_zstream_error(png_ptr, ret); return ret; } else { png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); return Z_STREAM_ERROR; } } #endif /* READ_iCCP */ /* Read and check the IDHR chunk */ void /* PRIVATE */ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[13]; png_uint_32 width, height; int bit_depth, color_type, compression_type, filter_type; int interlace_type; png_debug(1, "in png_handle_IHDR"); if ((png_ptr->mode & PNG_HAVE_IHDR) != 0) png_chunk_error(png_ptr, "out of place"); /* Check the length */ if (length != 13) png_chunk_error(png_ptr, "invalid"); png_ptr->mode |= PNG_HAVE_IHDR; png_crc_read(png_ptr, buf, 13); png_crc_finish(png_ptr, 0); width = png_get_uint_31(png_ptr, buf); height = png_get_uint_31(png_ptr, buf + 4); bit_depth = buf[8]; color_type = buf[9]; compression_type = buf[10]; filter_type = buf[11]; interlace_type = buf[12]; /* Set internal variables */ png_ptr->width = width; png_ptr->height = height; png_ptr->bit_depth = (png_byte)bit_depth; png_ptr->interlaced = (png_byte)interlace_type; png_ptr->color_type = (png_byte)color_type; #ifdef PNG_MNG_FEATURES_SUPPORTED png_ptr->filter_type = (png_byte)filter_type; #endif png_ptr->compression_type = (png_byte)compression_type; /* Find number of channels */ switch (png_ptr->color_type) { default: /* invalid, png_set_IHDR calls png_error */ case PNG_COLOR_TYPE_GRAY: case PNG_COLOR_TYPE_PALETTE: png_ptr->channels = 1; break; case PNG_COLOR_TYPE_RGB: png_ptr->channels = 3; break; case PNG_COLOR_TYPE_GRAY_ALPHA: png_ptr->channels = 2; break; case PNG_COLOR_TYPE_RGB_ALPHA: png_ptr->channels = 4; break; } /* Set up other useful info */ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); png_debug1(3, "channels = %d", png_ptr->channels); png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes); png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type); } /* Read and check the palette */ void /* PRIVATE */ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_color palette[PNG_MAX_PALETTE_LENGTH]; int max_palette_length, num, i; #ifdef PNG_POINTER_INDEXING_SUPPORTED png_colorp pal_ptr; #endif png_debug(1, "in png_handle_PLTE"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); /* Moved to before the 'after IDAT' check below because otherwise duplicate * PLTE chunks are potentially ignored (the spec says there shall not be more * than one PLTE, the error is not treated as benign, so this check trumps * the requirement that PLTE appears before IDAT.) */ else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0) png_chunk_error(png_ptr, "duplicate"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { /* This is benign because the non-benign error happened before, when an * IDAT was encountered in a color-mapped image with no PLTE. */ png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } png_ptr->mode |= PNG_HAVE_PLTE; if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); return; } #ifndef PNG_READ_OPT_PLTE_SUPPORTED if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { png_crc_finish(png_ptr, length); return; } #endif if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) { png_crc_finish(png_ptr, length); if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) png_chunk_benign_error(png_ptr, "invalid"); else png_chunk_error(png_ptr, "invalid"); return; } /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ num = (int)length / 3; /* If the palette has 256 or fewer entries but is too large for the bit * depth, we don't issue an error, to preserve the behavior of previous * libpng versions. We silently truncate the unused extra palette entries * here. */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) max_palette_length = (1 << png_ptr->bit_depth); else max_palette_length = PNG_MAX_PALETTE_LENGTH; if (num > max_palette_length) num = max_palette_length; #ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) { png_byte buf[3]; png_crc_read(png_ptr, buf, 3); pal_ptr->red = buf[0]; pal_ptr->green = buf[1]; pal_ptr->blue = buf[2]; } #else for (i = 0; i < num; i++) { png_byte buf[3]; png_crc_read(png_ptr, buf, 3); /* Don't depend upon png_color being any order */ palette[i].red = buf[0]; palette[i].green = buf[1]; palette[i].blue = buf[2]; } #endif /* If we actually need the PLTE chunk (ie for a paletted image), we do * whatever the normal CRC configuration tells us. However, if we * have an RGB image, the PLTE can be considered ancillary, so * we will act as though it is. */ #ifndef PNG_READ_OPT_PLTE_SUPPORTED if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) #endif { png_crc_finish(png_ptr, (png_uint_32) (length - (unsigned int)num * 3)); } #ifndef PNG_READ_OPT_PLTE_SUPPORTED else if (png_crc_error(png_ptr) != 0) /* Only if we have a CRC error */ { /* If we don't want to use the data from an ancillary chunk, * we have two options: an error abort, or a warning and we * ignore the data in this chunk (which should be OK, since * it's considered ancillary for a RGB or RGBA image). * * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the * chunk type to determine whether to check the ancillary or the critical * flags. */ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0) return; else png_chunk_error(png_ptr, "CRC error"); } /* Otherwise, we (optionally) emit a warning and use the chunk. */ else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0) png_chunk_warning(png_ptr, "CRC error"); } #endif /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its * own copy of the palette. This has the side effect that when png_start_row * is called (this happens after any call to png_read_update_info) the * info_ptr palette gets changed. This is extremely unexpected and * confusing. * * Fix this by not sharing the palette in this way. */ png_set_PLTE(png_ptr, info_ptr, palette, num); /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before * IDAT. Prior to 1.6.0 this was not checked; instead the code merely * checked the apparent validity of a tRNS chunk inserted before PLTE on a * palette PNG. 1.6.0 attempts to rigorously follow the standard and * therefore does a benign error if the erroneous condition is detected *and* * cancels the tRNS if the benign error returns. The alternative is to * amend the standard since it would be rather hypocritical of the standards * maintainers to ignore it. */ #ifdef PNG_READ_tRNS_SUPPORTED if (png_ptr->num_trans > 0 || (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)) { /* Cancel this because otherwise it would be used if the transforms * require it. Don't cancel the 'valid' flag because this would prevent * detection of duplicate chunks. */ png_ptr->num_trans = 0; if (info_ptr != NULL) info_ptr->num_trans = 0; png_chunk_benign_error(png_ptr, "tRNS must be after"); } #endif #ifdef PNG_READ_hIST_SUPPORTED if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) png_chunk_benign_error(png_ptr, "hIST must be after"); #endif #ifdef PNG_READ_bKGD_SUPPORTED if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) png_chunk_benign_error(png_ptr, "bKGD must be after"); #endif } void /* PRIVATE */ png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_debug(1, "in png_handle_IEND"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 || (png_ptr->mode & PNG_HAVE_IDAT) == 0) png_chunk_error(png_ptr, "out of place"); png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); png_crc_finish(png_ptr, length); if (length != 0) png_chunk_benign_error(png_ptr, "invalid"); PNG_UNUSED(info_ptr) } #ifdef PNG_READ_gAMA_SUPPORTED void /* PRIVATE */ png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_fixed_point igamma; png_byte buf[4]; png_debug(1, "in png_handle_gAMA"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 4) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 4); if (png_crc_finish(png_ptr, 0) != 0) return; igamma = png_get_fixed_point(NULL, buf); png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma); png_colorspace_sync(png_ptr, info_ptr); } #endif #ifdef PNG_READ_sBIT_SUPPORTED void /* PRIVATE */ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int truelen, i; png_byte sample_depth; png_byte buf[4]; png_debug(1, "in png_handle_sBIT"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { truelen = 3; sample_depth = 8; } else { truelen = png_ptr->channels; sample_depth = png_ptr->bit_depth; } if (length != truelen || length > 4) { png_chunk_benign_error(png_ptr, "invalid"); png_crc_finish(png_ptr, length); return; } buf[0] = buf[1] = buf[2] = buf[3] = sample_depth; png_crc_read(png_ptr, buf, truelen); if (png_crc_finish(png_ptr, 0) != 0) return; for (i=0; i sample_depth) { png_chunk_benign_error(png_ptr, "invalid"); return; } } if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) { png_ptr->sig_bit.red = buf[0]; png_ptr->sig_bit.green = buf[1]; png_ptr->sig_bit.blue = buf[2]; png_ptr->sig_bit.alpha = buf[3]; } else { png_ptr->sig_bit.gray = buf[0]; png_ptr->sig_bit.red = buf[0]; png_ptr->sig_bit.green = buf[0]; png_ptr->sig_bit.blue = buf[0]; png_ptr->sig_bit.alpha = buf[1]; } png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); } #endif #ifdef PNG_READ_cHRM_SUPPORTED void /* PRIVATE */ png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[32]; png_xy xy; png_debug(1, "in png_handle_cHRM"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 32) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 32); if (png_crc_finish(png_ptr, 0) != 0) return; xy.whitex = png_get_fixed_point(NULL, buf); xy.whitey = png_get_fixed_point(NULL, buf + 4); xy.redx = png_get_fixed_point(NULL, buf + 8); xy.redy = png_get_fixed_point(NULL, buf + 12); xy.greenx = png_get_fixed_point(NULL, buf + 16); xy.greeny = png_get_fixed_point(NULL, buf + 20); xy.bluex = png_get_fixed_point(NULL, buf + 24); xy.bluey = png_get_fixed_point(NULL, buf + 28); if (xy.whitex == PNG_FIXED_ERROR || xy.whitey == PNG_FIXED_ERROR || xy.redx == PNG_FIXED_ERROR || xy.redy == PNG_FIXED_ERROR || xy.greenx == PNG_FIXED_ERROR || xy.greeny == PNG_FIXED_ERROR || xy.bluex == PNG_FIXED_ERROR || xy.bluey == PNG_FIXED_ERROR) { png_chunk_benign_error(png_ptr, "invalid values"); return; } /* If a colorspace error has already been output skip this chunk */ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) return; if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0) { png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; png_colorspace_sync(png_ptr, info_ptr); png_chunk_benign_error(png_ptr, "duplicate"); return; } png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy, 1/*prefer cHRM values*/); png_colorspace_sync(png_ptr, info_ptr); } #endif #ifdef PNG_READ_sRGB_SUPPORTED void /* PRIVATE */ png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte intent; png_debug(1, "in png_handle_sRGB"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 1) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, &intent, 1); if (png_crc_finish(png_ptr, 0) != 0) return; /* If a colorspace error has already been output skip this chunk */ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) return; /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect * this. */ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0) { png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; png_colorspace_sync(png_ptr, info_ptr); png_chunk_benign_error(png_ptr, "too many profiles"); return; } (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent); png_colorspace_sync(png_ptr, info_ptr); } #endif /* READ_sRGB */ #ifdef PNG_READ_iCCP_SUPPORTED void /* PRIVATE */ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle profiles that are > 64K under DOS */ { png_const_charp errmsg = NULL; /* error message output, or no error */ int finished = 0; /* crc checked */ png_debug(1, "in png_handle_iCCP"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } /* Consistent with all the above colorspace handling an obviously *invalid* * chunk is just ignored, so does not invalidate the color space. An * alternative is to set the 'invalid' flags at the start of this routine * and only clear them in they were not set before and all the tests pass. */ /* The keyword must be at least one character and there is a * terminator (0) byte and the compression method byte, and the * 'zlib' datastream is at least 11 bytes. */ if (length < 14) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "too short"); return; } /* If a colorspace error has already been output skip this chunk */ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) { png_crc_finish(png_ptr, length); return; } /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect * this. */ if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0) { uInt read_length, keyword_length; char keyword[81]; /* Find the keyword; the keyword plus separator and compression method * bytes can be at most 81 characters long. */ read_length = 81; /* maximum */ if (read_length > length) read_length = (uInt)length; png_crc_read(png_ptr, (png_bytep)keyword, read_length); length -= read_length; /* The minimum 'zlib' stream is assumed to be just the 2 byte header, * 5 bytes minimum 'deflate' stream, and the 4 byte checksum. */ if (length < 11) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "too short"); return; } keyword_length = 0; while (keyword_length < 80 && keyword_length < read_length && keyword[keyword_length] != 0) ++keyword_length; /* TODO: make the keyword checking common */ if (keyword_length >= 1 && keyword_length <= 79) { /* We only understand '0' compression - deflate - so if we get a * different value we can't safely decode the chunk. */ if (keyword_length+1 < read_length && keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE) { read_length -= keyword_length+2; if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) { Byte profile_header[132]={0}; Byte local_buffer[PNG_INFLATE_BUF_SIZE]; png_alloc_size_t size = (sizeof profile_header); png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); png_ptr->zstream.avail_in = read_length; (void)png_inflate_read(png_ptr, local_buffer, (sizeof local_buffer), &length, profile_header, &size, 0/*finish: don't, because the output is too small*/); if (size == 0) { /* We have the ICC profile header; do the basic header checks. */ const png_uint_32 profile_length = png_get_uint_32(profile_header); if (png_icc_check_length(png_ptr, &png_ptr->colorspace, keyword, profile_length) != 0) { /* The length is apparently ok, so we can check the 132 * byte header. */ if (png_icc_check_header(png_ptr, &png_ptr->colorspace, keyword, profile_length, profile_header, png_ptr->color_type) != 0) { /* Now read the tag table; a variable size buffer is * needed at this point, allocate one for the whole * profile. The header check has already validated * that none of this stuff will overflow. */ const png_uint_32 tag_count = png_get_uint_32( profile_header+128); png_bytep profile = png_read_buffer(png_ptr, profile_length, 2/*silent*/); if (profile != NULL) { memcpy(profile, profile_header, (sizeof profile_header)); size = 12 * tag_count; (void)png_inflate_read(png_ptr, local_buffer, (sizeof local_buffer), &length, profile + (sizeof profile_header), &size, 0); /* Still expect a buffer error because we expect * there to be some tag data! */ if (size == 0) { if (png_icc_check_tag_table(png_ptr, &png_ptr->colorspace, keyword, profile_length, profile) != 0) { /* The profile has been validated for basic * security issues, so read the whole thing in. */ size = profile_length - (sizeof profile_header) - 12 * tag_count; (void)png_inflate_read(png_ptr, local_buffer, (sizeof local_buffer), &length, profile + (sizeof profile_header) + 12 * tag_count, &size, 1/*finish*/); if (length > 0 && !(png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)) errmsg = "extra compressed data"; /* But otherwise allow extra data: */ else if (size == 0) { if (length > 0) { /* This can be handled completely, so * keep going. */ png_chunk_warning(png_ptr, "extra compressed data"); } png_crc_finish(png_ptr, length); finished = 1; # if defined(PNG_sRGB_SUPPORTED) && PNG_sRGB_PROFILE_CHECKS >= 0 /* Check for a match against sRGB */ png_icc_set_sRGB(png_ptr, &png_ptr->colorspace, profile, png_ptr->zstream.adler); # endif /* Steal the profile for info_ptr. */ if (info_ptr != NULL) { png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); info_ptr->iccp_name = png_voidcast(char*, png_malloc_base(png_ptr, keyword_length+1)); if (info_ptr->iccp_name != NULL) { memcpy(info_ptr->iccp_name, keyword, keyword_length+1); info_ptr->iccp_proflen = profile_length; info_ptr->iccp_profile = profile; png_ptr->read_buffer = NULL; /*steal*/ info_ptr->free_me |= PNG_FREE_ICCP; info_ptr->valid |= PNG_INFO_iCCP; } else { png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; errmsg = "out of memory"; } } /* else the profile remains in the read * buffer which gets reused for subsequent * chunks. */ if (info_ptr != NULL) png_colorspace_sync(png_ptr, info_ptr); if (errmsg == NULL) { png_ptr->zowner = 0; return; } } if (errmsg == NULL) errmsg = png_ptr->zstream.msg; } /* else png_icc_check_tag_table output an error */ } else /* profile truncated */ errmsg = png_ptr->zstream.msg; } else errmsg = "out of memory"; } /* else png_icc_check_header output an error */ } /* else png_icc_check_length output an error */ } else /* profile truncated */ errmsg = png_ptr->zstream.msg; /* Release the stream */ png_ptr->zowner = 0; } else /* png_inflate_claim failed */ errmsg = png_ptr->zstream.msg; } else errmsg = "bad compression method"; /* or missing */ } else errmsg = "bad keyword"; } else errmsg = "too many profiles"; /* Failure: the reason is in 'errmsg' */ if (finished == 0) png_crc_finish(png_ptr, length); png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; png_colorspace_sync(png_ptr, info_ptr); if (errmsg != NULL) /* else already output */ png_chunk_benign_error(png_ptr, errmsg); } #endif /* READ_iCCP */ #ifdef PNG_READ_sPLT_SUPPORTED void /* PRIVATE */ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { png_bytep entry_start, buffer; png_sPLT_t new_palette; png_sPLT_entryp pp; png_uint_32 data_length; int entry_size, i; png_uint_32 skip = 0; png_uint_32 dl; png_size_t max_dl; png_debug(1, "in png_handle_sPLT"); #ifdef PNG_USER_LIMITS_SUPPORTED if (png_ptr->user_chunk_cache_max != 0) { if (png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); return; } if (--png_ptr->user_chunk_cache_max == 1) { png_warning(png_ptr, "No space in chunk cache for sPLT"); png_crc_finish(png_ptr, length); return; } } #endif if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } #ifdef PNG_MAX_MALLOC_64K if (length > 65535U) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "too large to fit in memory"); return; } #endif buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); if (buffer == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); return; } /* WARNING: this may break if size_t is less than 32 bits; it is assumed * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a * potential breakage point if the types in pngconf.h aren't exactly right. */ png_crc_read(png_ptr, buffer, length); if (png_crc_finish(png_ptr, skip) != 0) return; buffer[length] = 0; for (entry_start = buffer; *entry_start; entry_start++) /* Empty loop to find end of name */ ; ++entry_start; /* A sample depth should follow the separator, and we should be on it */ if (length < 2U || entry_start > buffer + (length - 2U)) { png_warning(png_ptr, "malformed sPLT chunk"); return; } new_palette.depth = *entry_start++; entry_size = (new_palette.depth == 8 ? 6 : 10); /* This must fit in a png_uint_32 because it is derived from the original * chunk data length. */ data_length = length - (png_uint_32)(entry_start - buffer); /* Integrity-check the data length */ if ((data_length % (unsigned int)entry_size) != 0) { png_warning(png_ptr, "sPLT chunk has bad length"); return; } dl = (png_uint_32)(data_length / (unsigned int)entry_size); max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); if (dl > max_dl) { png_warning(png_ptr, "sPLT chunk too long"); return; } new_palette.nentries = (png_int_32)(data_length / (unsigned int)entry_size); new_palette.entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, (png_alloc_size_t) new_palette.nentries * (sizeof (png_sPLT_entry))); if (new_palette.entries == NULL) { png_warning(png_ptr, "sPLT chunk requires too much memory"); return; } #ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0; i < new_palette.nentries; i++) { pp = new_palette.entries + i; if (new_palette.depth == 8) { pp->red = *entry_start++; pp->green = *entry_start++; pp->blue = *entry_start++; pp->alpha = *entry_start++; } else { pp->red = png_get_uint_16(entry_start); entry_start += 2; pp->green = png_get_uint_16(entry_start); entry_start += 2; pp->blue = png_get_uint_16(entry_start); entry_start += 2; pp->alpha = png_get_uint_16(entry_start); entry_start += 2; } pp->frequency = png_get_uint_16(entry_start); entry_start += 2; } #else pp = new_palette.entries; for (i = 0; i < new_palette.nentries; i++) { if (new_palette.depth == 8) { pp[i].red = *entry_start++; pp[i].green = *entry_start++; pp[i].blue = *entry_start++; pp[i].alpha = *entry_start++; } else { pp[i].red = png_get_uint_16(entry_start); entry_start += 2; pp[i].green = png_get_uint_16(entry_start); entry_start += 2; pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; } pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2; } #endif /* Discard all chunk data except the name and stash that */ new_palette.name = (png_charp)buffer; png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); png_free(png_ptr, new_palette.entries); } #endif /* READ_sPLT */ #ifdef PNG_READ_tRNS_SUPPORTED void /* PRIVATE */ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_tRNS"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) { png_byte buf[2]; if (length != 2) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 2); png_ptr->num_trans = 1; png_ptr->trans_color.gray = png_get_uint_16(buf); } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) { png_byte buf[6]; if (length != 6) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, length); png_ptr->num_trans = 1; png_ptr->trans_color.red = png_get_uint_16(buf); png_ptr->trans_color.green = png_get_uint_16(buf + 2); png_ptr->trans_color.blue = png_get_uint_16(buf + 4); } else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) { /* TODO: is this actually an error in the ISO spec? */ png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } if (length > (unsigned int) png_ptr->num_palette || length > (unsigned int) PNG_MAX_PALETTE_LENGTH || length == 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, readbuf, length); png_ptr->num_trans = (png_uint_16)length; } else { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid with alpha channel"); return; } if (png_crc_finish(png_ptr, 0) != 0) { png_ptr->num_trans = 0; return; } /* TODO: this is a horrible side effect in the palette case because the * png_struct ends up with a pointer to the tRNS buffer owned by the * png_info. Fix this. */ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, &(png_ptr->trans_color)); } #endif #ifdef PNG_READ_bKGD_SUPPORTED void /* PRIVATE */ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int truelen; png_byte buf[6]; png_color_16 background; png_debug(1, "in png_handle_bKGD"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && (png_ptr->mode & PNG_HAVE_PLTE) == 0)) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) truelen = 1; else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) truelen = 6; else truelen = 2; if (length != truelen) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, truelen); if (png_crc_finish(png_ptr, 0) != 0) return; /* We convert the index value into RGB components so that we can allow * arbitrary RGB values for background when we have transparency, and * so it is easy to determine the RGB values of the background color * from the info_ptr struct. */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { background.index = buf[0]; if (info_ptr != NULL && info_ptr->num_palette != 0) { if (buf[0] >= info_ptr->num_palette) { png_chunk_benign_error(png_ptr, "invalid index"); return; } background.red = (png_uint_16)png_ptr->palette[buf[0]].red; background.green = (png_uint_16)png_ptr->palette[buf[0]].green; background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue; } else background.red = background.green = background.blue = 0; background.gray = 0; } else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */ { background.index = 0; background.red = background.green = background.blue = background.gray = png_get_uint_16(buf); } else { background.index = 0; background.red = png_get_uint_16(buf); background.green = png_get_uint_16(buf + 2); background.blue = png_get_uint_16(buf + 4); background.gray = 0; } png_set_bKGD(png_ptr, info_ptr, &background); } #endif #ifdef PNG_READ_eXIf_SUPPORTED void /* PRIVATE */ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int i; png_debug(1, "in png_handle_eXIf"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); if (length < 2) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "too short"); return; } else if (info_ptr == NULL || (info_ptr->valid & PNG_INFO_eXIf) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } info_ptr->free_me |= PNG_FREE_EXIF; info_ptr->eXIf_buf = png_voidcast(png_bytep, png_malloc_warn(png_ptr, length)); if (info_ptr->eXIf_buf == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); return; } for (i = 0; i < length; i++) { png_byte buf[1]; png_crc_read(png_ptr, buf, 1); info_ptr->eXIf_buf[i] = buf[0]; if (i == 1 && buf[0] != 'M' && buf[0] != 'I' && info_ptr->eXIf_buf[0] != buf[0]) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "incorrect byte-order specifier"); png_free(png_ptr, info_ptr->eXIf_buf); info_ptr->eXIf_buf = NULL; return; } } if (png_crc_finish(png_ptr, 0) != 0) return; png_set_eXIf_1(png_ptr, info_ptr, length, info_ptr->eXIf_buf); png_free(png_ptr, info_ptr->eXIf_buf); info_ptr->eXIf_buf = NULL; } #endif #ifdef PNG_READ_hIST_SUPPORTED void /* PRIVATE */ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int num, i; png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_hIST"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || (png_ptr->mode & PNG_HAVE_PLTE) == 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } num = length / 2 ; if (num != (unsigned int) png_ptr->num_palette || num > (unsigned int) PNG_MAX_PALETTE_LENGTH) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } for (i = 0; i < num; i++) { png_byte buf[2]; png_crc_read(png_ptr, buf, 2); readbuf[i] = png_get_uint_16(buf); } if (png_crc_finish(png_ptr, 0) != 0) return; png_set_hIST(png_ptr, info_ptr, readbuf); } #endif #ifdef PNG_READ_pHYs_SUPPORTED void /* PRIVATE */ png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; png_uint_32 res_x, res_y; int unit_type; png_debug(1, "in png_handle_pHYs"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } if (length != 9) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 9); if (png_crc_finish(png_ptr, 0) != 0) return; res_x = png_get_uint_32(buf); res_y = png_get_uint_32(buf + 4); unit_type = buf[8]; png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); } #endif #ifdef PNG_READ_oFFs_SUPPORTED void /* PRIVATE */ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; png_int_32 offset_x, offset_y; int unit_type; png_debug(1, "in png_handle_oFFs"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } if (length != 9) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 9); if (png_crc_finish(png_ptr, 0) != 0) return; offset_x = png_get_int_32(buf); offset_y = png_get_int_32(buf + 4); unit_type = buf[8]; png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); } #endif #ifdef PNG_READ_pCAL_SUPPORTED /* Read the pCAL chunk (described in the PNG Extensions document) */ void /* PRIVATE */ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_int_32 X0, X1; png_byte type, nparams; png_bytep buffer, buf, units, endptr; png_charpp params; int i; png_debug(1, "in png_handle_pCAL"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", length + 1); buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); if (buffer == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); return; } png_crc_read(png_ptr, buffer, length); if (png_crc_finish(png_ptr, 0) != 0) return; buffer[length] = 0; /* Null terminate the last string */ png_debug(3, "Finding end of pCAL purpose string"); for (buf = buffer; *buf; buf++) /* Empty loop */ ; endptr = buffer + length; /* We need to have at least 12 bytes after the purpose string * in order to get the parameter information. */ if (endptr - buf <= 12) { png_chunk_benign_error(png_ptr, "invalid"); return; } png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); X0 = png_get_int_32((png_bytep)buf+1); X1 = png_get_int_32((png_bytep)buf+5); type = buf[9]; nparams = buf[10]; units = buf + 11; png_debug(3, "Checking pCAL equation type and number of parameters"); /* Check that we have the right number of parameters for known * equation types. */ if ((type == PNG_EQUATION_LINEAR && nparams != 2) || (type == PNG_EQUATION_BASE_E && nparams != 3) || (type == PNG_EQUATION_ARBITRARY && nparams != 3) || (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) { png_chunk_benign_error(png_ptr, "invalid parameter count"); return; } else if (type >= PNG_EQUATION_LAST) { png_chunk_benign_error(png_ptr, "unrecognized equation type"); } for (buf = units; *buf; buf++) /* Empty loop to move past the units string. */ ; png_debug(3, "Allocating pCAL parameters array"); params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, nparams * (sizeof (png_charp)))); if (params == NULL) { png_chunk_benign_error(png_ptr, "out of memory"); return; } /* Get pointers to the start of each parameter string. */ for (i = 0; i < nparams; i++) { buf++; /* Skip the null string terminator from previous parameter. */ png_debug1(3, "Reading pCAL parameter %d", i); for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++) /* Empty loop to move past each parameter string */ ; /* Make sure we haven't run out of data yet */ if (buf > endptr) { png_free(png_ptr, params); png_chunk_benign_error(png_ptr, "invalid data"); return; } } png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, (png_charp)units, params); png_free(png_ptr, params); } #endif #ifdef PNG_READ_sCAL_SUPPORTED /* Read the sCAL chunk */ void /* PRIVATE */ png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_bytep buffer; png_size_t i; int state; png_debug(1, "in png_handle_sCAL"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); return; } else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } /* Need unit type, width, \0, height: minimum 4 bytes */ else if (length < 4) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", length + 1); buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); if (buffer == NULL) { png_chunk_benign_error(png_ptr, "out of memory"); png_crc_finish(png_ptr, length); return; } png_crc_read(png_ptr, buffer, length); buffer[length] = 0; /* Null terminate the last string */ if (png_crc_finish(png_ptr, 0) != 0) return; /* Validate the unit. */ if (buffer[0] != 1 && buffer[0] != 2) { png_chunk_benign_error(png_ptr, "invalid unit"); return; } /* Validate the ASCII numbers, need two ASCII numbers separated by * a '\0' and they need to fit exactly in the chunk data. */ i = 1; state = 0; if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 || i >= length || buffer[i++] != 0) png_chunk_benign_error(png_ptr, "bad width format"); else if (PNG_FP_IS_POSITIVE(state) == 0) png_chunk_benign_error(png_ptr, "non-positive width"); else { png_size_t heighti = i; state = 0; if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 || i != length) png_chunk_benign_error(png_ptr, "bad height format"); else if (PNG_FP_IS_POSITIVE(state) == 0) png_chunk_benign_error(png_ptr, "non-positive height"); else /* This is the (only) success case. */ png_set_sCAL_s(png_ptr, info_ptr, buffer[0], (png_charp)buffer+1, (png_charp)buffer+heighti); } } #endif #ifdef PNG_READ_tIME_SUPPORTED void /* PRIVATE */ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[7]; png_time mod_time; png_debug(1, "in png_handle_tIME"); if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "duplicate"); return; } if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; if (length != 7) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 7); if (png_crc_finish(png_ptr, 0) != 0) return; mod_time.second = buf[6]; mod_time.minute = buf[5]; mod_time.hour = buf[4]; mod_time.day = buf[3]; mod_time.month = buf[2]; mod_time.year = png_get_uint_16(buf); png_set_tIME(png_ptr, info_ptr, &mod_time); } #endif #ifdef PNG_READ_tEXt_SUPPORTED /* Note: this does not properly handle chunks that are > 64K under DOS */ void /* PRIVATE */ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_text text_info; png_bytep buffer; png_charp key; png_charp text; png_uint_32 skip = 0; png_debug(1, "in png_handle_tEXt"); #ifdef PNG_USER_LIMITS_SUPPORTED if (png_ptr->user_chunk_cache_max != 0) { if (png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); return; } if (--png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; #ifdef PNG_MAX_MALLOC_64K if (length > 65535U) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "too large to fit in memory"); return; } #endif buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); if (buffer == NULL) { png_chunk_benign_error(png_ptr, "out of memory"); return; } png_crc_read(png_ptr, buffer, length); if (png_crc_finish(png_ptr, skip) != 0) return; key = (png_charp)buffer; key[length] = 0; for (text = key; *text; text++) /* Empty loop to find end of key */ ; if (text != key + length) text++; text_info.compression = PNG_TEXT_COMPRESSION_NONE; text_info.key = key; text_info.lang = NULL; text_info.lang_key = NULL; text_info.itxt_length = 0; text_info.text = text; text_info.text_length = strlen(text); if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0) png_warning(png_ptr, "Insufficient memory to process text chunk"); } #endif #ifdef PNG_READ_zTXt_SUPPORTED /* Note: this does not correctly handle chunks that are > 64K under DOS */ void /* PRIVATE */ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_const_charp errmsg = NULL; png_bytep buffer; png_uint_32 keyword_length; png_debug(1, "in png_handle_zTXt"); #ifdef PNG_USER_LIMITS_SUPPORTED if (png_ptr->user_chunk_cache_max != 0) { if (png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); return; } if (--png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; /* Note, "length" is sufficient here; we won't be adding * a null terminator later. */ buffer = png_read_buffer(png_ptr, length, 2/*silent*/); if (buffer == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); return; } png_crc_read(png_ptr, buffer, length); if (png_crc_finish(png_ptr, 0) != 0) return; /* TODO: also check that the keyword contents match the spec! */ for (keyword_length = 0; keyword_length < length && buffer[keyword_length] != 0; ++keyword_length) /* Empty loop to find end of name */ ; if (keyword_length > 79 || keyword_length < 1) errmsg = "bad keyword"; /* zTXt must have some LZ data after the keyword, although it may expand to * zero bytes; we need a '\0' at the end of the keyword, the compression type * then the LZ data: */ else if (keyword_length + 3 > length) errmsg = "truncated"; else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE) errmsg = "unknown compression type"; else { png_alloc_size_t uncompressed_length = PNG_SIZE_MAX; /* TODO: at present png_decompress_chunk imposes a single application * level memory limit, this should be split to different values for iCCP * and text chunks. */ if (png_decompress_chunk(png_ptr, length, keyword_length+2, &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) { png_text text; if (png_ptr->read_buffer == NULL) errmsg="Read failure in png_handle_zTXt"; else { /* It worked; png_ptr->read_buffer now looks like a tEXt chunk * except for the extra compression type byte and the fact that * it isn't necessarily '\0' terminated. */ buffer = png_ptr->read_buffer; buffer[uncompressed_length+(keyword_length+2)] = 0; text.compression = PNG_TEXT_COMPRESSION_zTXt; text.key = (png_charp)buffer; text.text = (png_charp)(buffer + keyword_length+2); text.text_length = uncompressed_length; text.itxt_length = 0; text.lang = NULL; text.lang_key = NULL; if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) errmsg = "insufficient memory"; } } else errmsg = png_ptr->zstream.msg; } if (errmsg != NULL) png_chunk_benign_error(png_ptr, errmsg); } #endif #ifdef PNG_READ_iTXt_SUPPORTED /* Note: this does not correctly handle chunks that are > 64K under DOS */ void /* PRIVATE */ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_const_charp errmsg = NULL; png_bytep buffer; png_uint_32 prefix_length; png_debug(1, "in png_handle_iTXt"); #ifdef PNG_USER_LIMITS_SUPPORTED if (png_ptr->user_chunk_cache_max != 0) { if (png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); return; } if (--png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) png_chunk_error(png_ptr, "missing IHDR"); if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); if (buffer == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); return; } png_crc_read(png_ptr, buffer, length); if (png_crc_finish(png_ptr, 0) != 0) return; /* First the keyword. */ for (prefix_length=0; prefix_length < length && buffer[prefix_length] != 0; ++prefix_length) /* Empty loop */ ; /* Perform a basic check on the keyword length here. */ if (prefix_length > 79 || prefix_length < 1) errmsg = "bad keyword"; /* Expect keyword, compression flag, compression type, language, translated * keyword (both may be empty but are 0 terminated) then the text, which may * be empty. */ else if (prefix_length + 5 > length) errmsg = "truncated"; else if (buffer[prefix_length+1] == 0 || (buffer[prefix_length+1] == 1 && buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE)) { int compressed = buffer[prefix_length+1] != 0; png_uint_32 language_offset, translated_keyword_offset; png_alloc_size_t uncompressed_length = 0; /* Now the language tag */ prefix_length += 3; language_offset = prefix_length; for (; prefix_length < length && buffer[prefix_length] != 0; ++prefix_length) /* Empty loop */ ; /* WARNING: the length may be invalid here, this is checked below. */ translated_keyword_offset = ++prefix_length; for (; prefix_length < length && buffer[prefix_length] != 0; ++prefix_length) /* Empty loop */ ; /* prefix_length should now be at the trailing '\0' of the translated * keyword, but it may already be over the end. None of this arithmetic * can overflow because chunks are at most 2^31 bytes long, but on 16-bit * systems the available allocation may overflow. */ ++prefix_length; if (compressed == 0 && prefix_length <= length) uncompressed_length = length - prefix_length; else if (compressed != 0 && prefix_length < length) { uncompressed_length = PNG_SIZE_MAX; /* TODO: at present png_decompress_chunk imposes a single application * level memory limit, this should be split to different values for * iCCP and text chunks. */ if (png_decompress_chunk(png_ptr, length, prefix_length, &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) buffer = png_ptr->read_buffer; else errmsg = png_ptr->zstream.msg; } else errmsg = "truncated"; if (errmsg == NULL) { png_text text; buffer[uncompressed_length+prefix_length] = 0; if (compressed == 0) text.compression = PNG_ITXT_COMPRESSION_NONE; else text.compression = PNG_ITXT_COMPRESSION_zTXt; text.key = (png_charp)buffer; text.lang = (png_charp)buffer + language_offset; text.lang_key = (png_charp)buffer + translated_keyword_offset; text.text = (png_charp)buffer + prefix_length; text.text_length = 0; text.itxt_length = uncompressed_length; if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) errmsg = "insufficient memory"; } } else errmsg = "bad compression info"; if (errmsg != NULL) png_chunk_benign_error(png_ptr, errmsg); } #endif #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED /* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ static int png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) { png_alloc_size_t limit = PNG_SIZE_MAX; if (png_ptr->unknown_chunk.data != NULL) { png_free(png_ptr, png_ptr->unknown_chunk.data); png_ptr->unknown_chunk.data = NULL; } # ifdef PNG_SET_USER_LIMITS_SUPPORTED if (png_ptr->user_chunk_malloc_max > 0 && png_ptr->user_chunk_malloc_max < limit) limit = png_ptr->user_chunk_malloc_max; # elif PNG_USER_CHUNK_MALLOC_MAX > 0 if (PNG_USER_CHUNK_MALLOC_MAX < limit) limit = PNG_USER_CHUNK_MALLOC_MAX; # endif if (length <= limit) { PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); /* The following is safe because of the PNG_SIZE_MAX init above */ png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/; /* 'mode' is a flag array, only the bottom four bits matter here */ png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; if (length == 0) png_ptr->unknown_chunk.data = NULL; else { /* Do a 'warn' here - it is handled below. */ png_ptr->unknown_chunk.data = png_voidcast(png_bytep, png_malloc_warn(png_ptr, length)); } } if (png_ptr->unknown_chunk.data == NULL && length > 0) { /* This is benign because we clean up correctly */ png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits"); return 0; } else { if (length > 0) png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); png_crc_finish(png_ptr, 0); return 1; } } #endif /* READ_UNKNOWN_CHUNKS */ /* Handle an unknown, or known but disabled, chunk */ void /* PRIVATE */ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep) { int handled = 0; /* the chunk was handled */ png_debug(1, "in png_handle_unknown"); #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing * the bug which meant that setting a non-default behavior for a specific * chunk would be ignored (the default was always used unless a user * callback was installed). * * 'keep' is the value from the png_chunk_unknown_handling, the setting for * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here. * This is just an optimization to avoid multiple calls to the lookup * function. */ # ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED # ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); # endif # endif /* One of the following methods will read the chunk or skip it (at least one * of these is always defined because this is the only way to switch on * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) */ # ifdef PNG_READ_USER_CHUNKS_SUPPORTED /* The user callback takes precedence over the chunk keep value, but the * keep value is still required to validate a save of a critical chunk. */ if (png_ptr->read_user_chunk_fn != NULL) { if (png_cache_unknown_chunk(png_ptr, length) != 0) { /* Callback to user unknown chunk handler */ int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, &png_ptr->unknown_chunk); /* ret is: * negative: An error occurred; png_chunk_error will be called. * zero: The chunk was not handled, the chunk will be discarded * unless png_set_keep_unknown_chunks has been used to set * a 'keep' behavior for this particular chunk, in which * case that will be used. A critical chunk will cause an * error at this point unless it is to be saved. * positive: The chunk was handled, libpng will ignore/discard it. */ if (ret < 0) png_chunk_error(png_ptr, "error in user chunk"); else if (ret == 0) { /* If the keep value is 'default' or 'never' override it, but * still error out on critical chunks unless the keep value is * 'always' While this is weird it is the behavior in 1.4.12. * A possible improvement would be to obey the value set for the * chunk, but this would be an API change that would probably * damage some applications. * * The png_app_warning below catches the case that matters, where * the application has not set specific save or ignore for this * chunk or global save or ignore. */ if (keep < PNG_HANDLE_CHUNK_IF_SAFE) { # ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) { png_chunk_warning(png_ptr, "Saving unknown chunk:"); png_app_warning(png_ptr, "forcing save of an unhandled chunk;" " please call png_set_keep_unknown_chunks"); /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ } # endif keep = PNG_HANDLE_CHUNK_IF_SAFE; } } else /* chunk was handled */ { handled = 1; /* Critical chunks can be safely discarded at this point. */ keep = PNG_HANDLE_CHUNK_NEVER; } } else keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ } else /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ # endif /* READ_USER_CHUNKS */ # ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED { /* keep is currently just the per-chunk setting, if there was no * setting change it to the global default now (not that this may * still be AS_DEFAULT) then obtain the cache of the chunk if required, * if not simply skip the chunk. */ if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) keep = png_ptr->unknown_default; if (keep == PNG_HANDLE_CHUNK_ALWAYS || (keep == PNG_HANDLE_CHUNK_IF_SAFE && PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) { if (png_cache_unknown_chunk(png_ptr, length) == 0) keep = PNG_HANDLE_CHUNK_NEVER; } else png_crc_finish(png_ptr, length); } # else # ifndef PNG_READ_USER_CHUNKS_SUPPORTED # error no method to support READ_UNKNOWN_CHUNKS # endif { /* If here there is no read callback pointer set and no support is * compiled in to just save the unknown chunks, so simply skip this * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then * the app has erroneously asked for unknown chunk saving when there * is no support. */ if (keep > PNG_HANDLE_CHUNK_NEVER) png_app_error(png_ptr, "no unknown chunk support available"); png_crc_finish(png_ptr, length); } # endif # ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED /* Now store the chunk in the chunk list if appropriate, and if the limits * permit it. */ if (keep == PNG_HANDLE_CHUNK_ALWAYS || (keep == PNG_HANDLE_CHUNK_IF_SAFE && PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) { # ifdef PNG_USER_LIMITS_SUPPORTED switch (png_ptr->user_chunk_cache_max) { case 2: png_ptr->user_chunk_cache_max = 1; png_chunk_benign_error(png_ptr, "no space in chunk cache"); /* FALLTHROUGH */ case 1: /* NOTE: prior to 1.6.0 this case resulted in an unknown critical * chunk being skipped, now there will be a hard error below. */ break; default: /* not at limit */ --(png_ptr->user_chunk_cache_max); /* FALLTHROUGH */ case 0: /* no limit */ # endif /* USER_LIMITS */ /* Here when the limit isn't reached or when limits are compiled * out; store the chunk. */ png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); handled = 1; # ifdef PNG_USER_LIMITS_SUPPORTED break; } # endif } # else /* no store support: the chunk must be handled by the user callback */ PNG_UNUSED(info_ptr) # endif /* Regardless of the error handling below the cached data (if any) can be * freed now. Notice that the data is not freed if there is a png_error, but * it will be freed by destroy_read_struct. */ if (png_ptr->unknown_chunk.data != NULL) png_free(png_ptr, png_ptr->unknown_chunk.data); png_ptr->unknown_chunk.data = NULL; #else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ /* There is no support to read an unknown chunk, so just skip it. */ png_crc_finish(png_ptr, length); PNG_UNUSED(info_ptr) PNG_UNUSED(keep) #endif /* !READ_UNKNOWN_CHUNKS */ /* Check for unhandled critical chunks */ if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) png_chunk_error(png_ptr, "unhandled critical chunk"); } /* This function is called to verify that a chunk name is valid. * This function can't have the "critical chunk check" incorporated * into it, since in the future we will need to be able to call user * functions to handle unknown critical chunks after we check that * the chunk name itself is valid. */ /* Bit hacking: the test for an invalid byte in the 4 byte chunk name is: * * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) */ void /* PRIVATE */ png_check_chunk_name(png_const_structrp png_ptr, const png_uint_32 chunk_name) { int i; png_uint_32 cn=chunk_name; png_debug(1, "in png_check_chunk_name"); for (i=1; i<=4; ++i) { int c = cn & 0xff; if (c < 65 || c > 122 || (c > 90 && c < 97)) png_chunk_error(png_ptr, "invalid chunk type"); cn >>= 8; } } void /* PRIVATE */ png_check_chunk_length(png_const_structrp png_ptr, const png_uint_32 length) { png_alloc_size_t limit = PNG_UINT_31_MAX; # ifdef PNG_SET_USER_LIMITS_SUPPORTED if (png_ptr->user_chunk_malloc_max > 0 && png_ptr->user_chunk_malloc_max < limit) limit = png_ptr->user_chunk_malloc_max; # elif PNG_USER_CHUNK_MALLOC_MAX > 0 if (PNG_USER_CHUNK_MALLOC_MAX < limit) limit = PNG_USER_CHUNK_MALLOC_MAX; # endif if (png_ptr->chunk_name == png_IDAT) { png_alloc_size_t idat_limit = PNG_UINT_31_MAX; size_t row_factor = (png_ptr->width * png_ptr->channels * (png_ptr->bit_depth > 8? 2: 1) + 1 + (png_ptr->interlaced? 6: 0)); if (png_ptr->height > PNG_UINT_32_MAX/row_factor) idat_limit=PNG_UINT_31_MAX; else idat_limit = png_ptr->height * row_factor; row_factor = row_factor > 32566? 32566 : row_factor; idat_limit += 6 + 5*(idat_limit/row_factor+1); /* zlib+deflate overhead */ idat_limit=idat_limit < PNG_UINT_31_MAX? idat_limit : PNG_UINT_31_MAX; limit = limit < idat_limit? idat_limit : limit; } if (length > limit) { png_debug2(0," length = %lu, limit = %lu", (unsigned long)length,(unsigned long)limit); png_chunk_error(png_ptr, "chunk data is too large"); } } /* Combines the row recently read in with the existing pixels in the row. This * routine takes care of alpha and transparency if requested. This routine also * handles the two methods of progressive display of interlaced images, * depending on the 'display' value; if 'display' is true then the whole row * (dp) is filled from the start by replicating the available pixels. If * 'display' is false only those pixels present in the pass are filled in. */ void /* PRIVATE */ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) { unsigned int pixel_depth = png_ptr->transformed_pixel_depth; png_const_bytep sp = png_ptr->row_buf + 1; png_alloc_size_t row_width = png_ptr->width; unsigned int pass = png_ptr->pass; png_bytep end_ptr = 0; png_byte end_byte = 0; unsigned int end_mask; png_debug(1, "in png_combine_row"); /* Added in 1.5.6: it should not be possible to enter this routine until at * least one row has been read from the PNG data and transformed. */ if (pixel_depth == 0) png_error(png_ptr, "internal row logic error"); /* Added in 1.5.4: the pixel depth should match the information returned by * any call to png_read_update_info at this point. Do not continue if we got * this wrong. */ if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes != PNG_ROWBYTES(pixel_depth, row_width)) png_error(png_ptr, "internal row size calculation error"); /* Don't expect this to ever happen: */ if (row_width == 0) png_error(png_ptr, "internal row width error"); /* Preserve the last byte in cases where only part of it will be overwritten, * the multiply below may overflow, we don't care because ANSI-C guarantees * we get the low bits. */ end_mask = (pixel_depth * row_width) & 7; if (end_mask != 0) { /* end_ptr == NULL is a flag to say do nothing */ end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; end_byte = *end_ptr; # ifdef PNG_READ_PACKSWAP_SUPPORTED if ((png_ptr->transformations & PNG_PACKSWAP) != 0) /* little-endian byte */ end_mask = (unsigned int)(0xff << end_mask); else /* big-endian byte */ # endif end_mask = 0xff >> end_mask; /* end_mask is now the bits to *keep* from the destination row */ } /* For non-interlaced images this reduces to a memcpy(). A memcpy() * will also happen if interlacing isn't supported or if the application * does not call png_set_interlace_handling(). In the latter cases the * caller just gets a sequence of the unexpanded rows from each interlace * pass. */ #ifdef PNG_READ_INTERLACING_SUPPORTED if (png_ptr->interlaced != 0 && (png_ptr->transformations & PNG_INTERLACE) != 0 && pass < 6 && (display == 0 || /* The following copies everything for 'display' on passes 0, 2 and 4. */ (display == 1 && (pass & 1) != 0))) { /* Narrow images may have no bits in a pass; the caller should handle * this, but this test is cheap: */ if (row_width <= PNG_PASS_START_COL(pass)) return; if (pixel_depth < 8) { /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit * into 32 bits, then a single loop over the bytes using the four byte * values in the 32-bit mask can be used. For the 'display' option the * expanded mask may also not require any masking within a byte. To * make this work the PACKSWAP option must be taken into account - it * simply requires the pixels to be reversed in each byte. * * The 'regular' case requires a mask for each of the first 6 passes, * the 'display' case does a copy for the even passes in the range * 0..6. This has already been handled in the test above. * * The masks are arranged as four bytes with the first byte to use in * the lowest bits (little-endian) regardless of the order (PACKSWAP or * not) of the pixels in each byte. * * NOTE: the whole of this logic depends on the caller of this function * only calling it on rows appropriate to the pass. This function only * understands the 'x' logic; the 'y' logic is handled by the caller. * * The following defines allow generation of compile time constant bit * masks for each pixel depth and each possibility of swapped or not * swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index, * is in the range 0..7; and the result is 1 if the pixel is to be * copied in the pass, 0 if not. 'S' is for the sparkle method, 'B' * for the block method. * * With some compilers a compile time expression of the general form: * * (shift >= 32) ? (a >> (shift-32)) : (b >> shift) * * Produces warnings with values of 'shift' in the range 33 to 63 * because the right hand side of the ?: expression is evaluated by * the compiler even though it isn't used. Microsoft Visual C (various * versions) and the Intel C compiler are known to do this. To avoid * this the following macros are used in 1.5.6. This is a temporary * solution to avoid destabilizing the code during the release process. */ # if PNG_USE_COMPILE_TIME_MASKS # define PNG_LSR(x,s) ((x)>>((s) & 0x1f)) # define PNG_LSL(x,s) ((x)<<((s) & 0x1f)) # else # define PNG_LSR(x,s) ((x)>>(s)) # define PNG_LSL(x,s) ((x)<<(s)) # endif # define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\ PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1) # define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\ PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1) /* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is * little endian - the first pixel is at bit 0 - however the extra * parameter 's' can be set to cause the mask position to be swapped * within each byte, to match the PNG format. This is done by XOR of * the shift with 7, 6 or 4 for bit depths 1, 2 and 4. */ # define PIXEL_MASK(p,x,d,s) \ (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0)))) /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask. */ # define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) # define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) /* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp * cases the result needs replicating, for the 4-bpp case the above * generates a full 32 bits. */ # define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1))) # define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\ S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\ S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d) # define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\ B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\ B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d) #if PNG_USE_COMPILE_TIME_MASKS /* Utility macros to construct all the masks for a depth/swap * combination. The 's' parameter says whether the format is PNG * (big endian bytes) or not. Only the three odd-numbered passes are * required for the display/block algorithm. */ # define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } # define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) } # define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and * then pass: */ static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = { /* Little-endian byte masks for PACKSWAP */ { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) }, /* Normal (big-endian byte) masks - PNG format */ { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) } }; /* display_mask has only three entries for the odd passes, so index by * pass>>1. */ static PNG_CONST png_uint_32 display_mask[2][3][3] = { /* Little-endian byte masks for PACKSWAP */ { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) }, /* Normal (big-endian byte) masks - PNG format */ { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) } }; # define MASK(pass,depth,display,png)\ ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\ row_mask[png][DEPTH_INDEX(depth)][pass]) #else /* !PNG_USE_COMPILE_TIME_MASKS */ /* This is the runtime alternative: it seems unlikely that this will * ever be either smaller or faster than the compile time approach. */ # define MASK(pass,depth,display,png)\ ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) #endif /* !USE_COMPILE_TIME_MASKS */ /* Use the appropriate mask to copy the required bits. In some cases * the byte mask will be 0 or 0xff; optimize these cases. row_width is * the number of pixels, but the code copies bytes, so it is necessary * to special case the end. */ png_uint_32 pixels_per_byte = 8 / pixel_depth; png_uint_32 mask; # ifdef PNG_READ_PACKSWAP_SUPPORTED if ((png_ptr->transformations & PNG_PACKSWAP) != 0) mask = MASK(pass, pixel_depth, display, 0); else # endif mask = MASK(pass, pixel_depth, display, 1); for (;;) { png_uint_32 m; /* It doesn't matter in the following if png_uint_32 has more than * 32 bits because the high bits always match those in m<<24; it is, * however, essential to use OR here, not +, because of this. */ m = mask; mask = (m >> 8) | (m << 24); /* rotate right to good compilers */ m &= 0xff; if (m != 0) /* something to copy */ { if (m != 0xff) *dp = (png_byte)((*dp & ~m) | (*sp & m)); else *dp = *sp; } /* NOTE: this may overwrite the last byte with garbage if the image * is not an exact number of bytes wide; libpng has always done * this. */ if (row_width <= pixels_per_byte) break; /* May need to restore part of the last byte */ row_width -= pixels_per_byte; ++dp; ++sp; } } else /* pixel_depth >= 8 */ { unsigned int bytes_to_copy, bytes_to_jump; /* Validate the depth - it must be a multiple of 8 */ if (pixel_depth & 7) png_error(png_ptr, "invalid user transform pixel depth"); pixel_depth >>= 3; /* now in bytes */ row_width *= pixel_depth; /* Regardless of pass number the Adam 7 interlace always results in a * fixed number of pixels to copy then to skip. There may be a * different number of pixels to skip at the start though. */ { unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth; row_width -= offset; dp += offset; sp += offset; } /* Work out the bytes to copy. */ if (display != 0) { /* When doing the 'block' algorithm the pixel in the pass gets * replicated to adjacent pixels. This is why the even (0,2,4,6) * passes are skipped above - the entire expanded row is copied. */ bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth; /* But don't allow this number to exceed the actual row width. */ if (bytes_to_copy > row_width) bytes_to_copy = (unsigned int)/*SAFE*/row_width; } else /* normal row; Adam7 only ever gives us one pixel to copy. */ bytes_to_copy = pixel_depth; /* In Adam7 there is a constant offset between where the pixels go. */ bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth; /* And simply copy these bytes. Some optimization is possible here, * depending on the value of 'bytes_to_copy'. Special case the low * byte counts, which we know to be frequent. * * Notice that these cases all 'return' rather than 'break' - this * avoids an unnecessary test on whether to restore the last byte * below. */ switch (bytes_to_copy) { case 1: for (;;) { *dp = *sp; if (row_width <= bytes_to_jump) return; dp += bytes_to_jump; sp += bytes_to_jump; row_width -= bytes_to_jump; } case 2: /* There is a possibility of a partial copy at the end here; this * slows the code down somewhat. */ do { dp[0] = sp[0]; dp[1] = sp[1]; if (row_width <= bytes_to_jump) return; sp += bytes_to_jump; dp += bytes_to_jump; row_width -= bytes_to_jump; } while (row_width > 1); /* And there can only be one byte left at this point: */ *dp = *sp; return; case 3: /* This can only be the RGB case, so each copy is exactly one * pixel and it is not necessary to check for a partial copy. */ for (;;) { dp[0] = sp[0]; dp[1] = sp[1]; dp[2] = sp[2]; if (row_width <= bytes_to_jump) return; sp += bytes_to_jump; dp += bytes_to_jump; row_width -= bytes_to_jump; } default: #if PNG_ALIGN_TYPE != PNG_ALIGN_NONE /* Check for double byte alignment and, if possible, use a * 16-bit copy. Don't attempt this for narrow images - ones that * are less than an interlace panel wide. Don't attempt it for * wide bytes_to_copy either - use the memcpy there. */ if (bytes_to_copy < 16 /*else use memcpy*/ && png_isaligned(dp, png_uint_16) && png_isaligned(sp, png_uint_16) && bytes_to_copy % (sizeof (png_uint_16)) == 0 && bytes_to_jump % (sizeof (png_uint_16)) == 0) { /* Everything is aligned for png_uint_16 copies, but try for * png_uint_32 first. */ if (png_isaligned(dp, png_uint_32) && png_isaligned(sp, png_uint_32) && bytes_to_copy % (sizeof (png_uint_32)) == 0 && bytes_to_jump % (sizeof (png_uint_32)) == 0) { png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); png_const_uint_32p sp32 = png_aligncastconst( png_const_uint_32p, sp); size_t skip = (bytes_to_jump-bytes_to_copy) / (sizeof (png_uint_32)); do { size_t c = bytes_to_copy; do { *dp32++ = *sp32++; c -= (sizeof (png_uint_32)); } while (c > 0); if (row_width <= bytes_to_jump) return; dp32 += skip; sp32 += skip; row_width -= bytes_to_jump; } while (bytes_to_copy <= row_width); /* Get to here when the row_width truncates the final copy. * There will be 1-3 bytes left to copy, so don't try the * 16-bit loop below. */ dp = (png_bytep)dp32; sp = (png_const_bytep)sp32; do *dp++ = *sp++; while (--row_width > 0); return; } /* Else do it in 16-bit quantities, but only if the size is * not too large. */ else { png_uint_16p dp16 = png_aligncast(png_uint_16p, dp); png_const_uint_16p sp16 = png_aligncastconst( png_const_uint_16p, sp); size_t skip = (bytes_to_jump-bytes_to_copy) / (sizeof (png_uint_16)); do { size_t c = bytes_to_copy; do { *dp16++ = *sp16++; c -= (sizeof (png_uint_16)); } while (c > 0); if (row_width <= bytes_to_jump) return; dp16 += skip; sp16 += skip; row_width -= bytes_to_jump; } while (bytes_to_copy <= row_width); /* End of row - 1 byte left, bytes_to_copy > row_width: */ dp = (png_bytep)dp16; sp = (png_const_bytep)sp16; do *dp++ = *sp++; while (--row_width > 0); return; } } #endif /* ALIGN_TYPE code */ /* The true default - use a memcpy: */ for (;;) { memcpy(dp, sp, bytes_to_copy); if (row_width <= bytes_to_jump) return; sp += bytes_to_jump; dp += bytes_to_jump; row_width -= bytes_to_jump; if (bytes_to_copy > row_width) bytes_to_copy = (unsigned int)/*SAFE*/row_width; } } /* NOT REACHED*/ } /* pixel_depth >= 8 */ /* Here if pixel_depth < 8 to check 'end_ptr' below. */ } else #endif /* READ_INTERLACING */ /* If here then the switch above wasn't used so just memcpy the whole row * from the temporary row buffer (notice that this overwrites the end of the * destination row if it is a partial byte.) */ memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); /* Restore the overwritten bits from the last byte if necessary. */ if (end_ptr != NULL) *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask)); } #ifdef PNG_READ_INTERLACING_SUPPORTED void /* PRIVATE */ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, png_uint_32 transformations /* Because these may affect the byte layout */) { /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Offset to next interlace block */ static PNG_CONST unsigned int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; png_debug(1, "in png_do_read_interlace"); if (row != NULL && row_info != NULL) { png_uint_32 final_width; final_width = row_info->width * png_pass_inc[pass]; switch (row_info->pixel_depth) { case 1: { png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); unsigned int sshift, dshift; unsigned int s_start, s_end; int s_inc; int jstop = (int)png_pass_inc[pass]; png_byte v; png_uint_32 i; int j; #ifdef PNG_READ_PACKSWAP_SUPPORTED if ((transformations & PNG_PACKSWAP) != 0) { sshift = ((row_info->width + 7) & 0x07); dshift = ((final_width + 7) & 0x07); s_start = 7; s_end = 0; s_inc = -1; } else #endif { sshift = 7 - ((row_info->width + 7) & 0x07); dshift = 7 - ((final_width + 7) & 0x07); s_start = 0; s_end = 7; s_inc = 1; } for (i = 0; i < row_info->width; i++) { v = (png_byte)((*sp >> sshift) & 0x01); for (j = 0; j < jstop; j++) { unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); tmp |= (unsigned int)(v << dshift); *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { dshift = s_start; dp--; } else dshift = (unsigned int)((int)dshift + s_inc); } if (sshift == s_end) { sshift = s_start; sp--; } else sshift = (unsigned int)((int)sshift + s_inc); } break; } case 2: { png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); unsigned int sshift, dshift; unsigned int s_start, s_end; int s_inc; int jstop = (int)png_pass_inc[pass]; png_uint_32 i; #ifdef PNG_READ_PACKSWAP_SUPPORTED if ((transformations & PNG_PACKSWAP) != 0) { sshift = (((row_info->width + 3) & 0x03) << 1); dshift = (((final_width + 3) & 0x03) << 1); s_start = 6; s_end = 0; s_inc = -2; } else #endif { sshift = ((3 - ((row_info->width + 3) & 0x03)) << 1); dshift = ((3 - ((final_width + 3) & 0x03)) << 1); s_start = 0; s_end = 6; s_inc = 2; } for (i = 0; i < row_info->width; i++) { png_byte v; int j; v = (png_byte)((*sp >> sshift) & 0x03); for (j = 0; j < jstop; j++) { unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); tmp |= (unsigned int)(v << dshift); *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { dshift = s_start; dp--; } else dshift = (unsigned int)((int)dshift + s_inc); } if (sshift == s_end) { sshift = s_start; sp--; } else sshift = (unsigned int)((int)sshift + s_inc); } break; } case 4: { png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); unsigned int sshift, dshift; unsigned int s_start, s_end; int s_inc; png_uint_32 i; int jstop = (int)png_pass_inc[pass]; #ifdef PNG_READ_PACKSWAP_SUPPORTED if ((transformations & PNG_PACKSWAP) != 0) { sshift = (((row_info->width + 1) & 0x01) << 2); dshift = (((final_width + 1) & 0x01) << 2); s_start = 4; s_end = 0; s_inc = -4; } else #endif { sshift = ((1 - ((row_info->width + 1) & 0x01)) << 2); dshift = ((1 - ((final_width + 1) & 0x01)) << 2); s_start = 0; s_end = 4; s_inc = 4; } for (i = 0; i < row_info->width; i++) { png_byte v = (png_byte)((*sp >> sshift) & 0x0f); int j; for (j = 0; j < jstop; j++) { unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); tmp |= (unsigned int)(v << dshift); *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { dshift = s_start; dp--; } else dshift = (unsigned int)((int)dshift + s_inc); } if (sshift == s_end) { sshift = s_start; sp--; } else sshift = (unsigned int)((int)sshift + s_inc); } break; } default: { png_size_t pixel_bytes = (row_info->pixel_depth >> 3); png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes; png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; int jstop = (int)png_pass_inc[pass]; png_uint_32 i; for (i = 0; i < row_info->width; i++) { png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */ int j; memcpy(v, sp, pixel_bytes); for (j = 0; j < jstop; j++) { memcpy(dp, v, pixel_bytes); dp -= pixel_bytes; } sp -= pixel_bytes; } break; } } row_info->width = final_width; row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); } #ifndef PNG_READ_PACKSWAP_SUPPORTED PNG_UNUSED(transformations) /* Silence compiler warning */ #endif } #endif /* READ_INTERLACING */ static void png_read_filter_row_sub(png_row_infop row_info, png_bytep row, png_const_bytep prev_row) { png_size_t i; png_size_t istop = row_info->rowbytes; unsigned int bpp = (row_info->pixel_depth + 7) >> 3; png_bytep rp = row + bpp; PNG_UNUSED(prev_row) for (i = bpp; i < istop; i++) { *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); rp++; } } static void png_read_filter_row_up(png_row_infop row_info, png_bytep row, png_const_bytep prev_row) { png_size_t i; png_size_t istop = row_info->rowbytes; png_bytep rp = row; png_const_bytep pp = prev_row; for (i = 0; i < istop; i++) { *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); rp++; } } static void png_read_filter_row_avg(png_row_infop row_info, png_bytep row, png_const_bytep prev_row) { png_size_t i; png_bytep rp = row; png_const_bytep pp = prev_row; unsigned int bpp = (row_info->pixel_depth + 7) >> 3; png_size_t istop = row_info->rowbytes - bpp; for (i = 0; i < bpp; i++) { *rp = (png_byte)(((int)(*rp) + ((int)(*pp++) / 2 )) & 0xff); rp++; } for (i = 0; i < istop; i++) { *rp = (png_byte)(((int)(*rp) + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); rp++; } } static void png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, png_const_bytep prev_row) { png_bytep rp_end = row + row_info->rowbytes; int a, c; /* First pixel/byte */ c = *prev_row++; a = *row + c; *row++ = (png_byte)a; /* Remainder */ while (row < rp_end) { int b, pa, pb, pc, p; a &= 0xff; /* From previous iteration or start */ b = *prev_row++; p = b - c; pc = a - c; #ifdef PNG_USE_ABS pa = abs(p); pb = abs(pc); pc = abs(p + pc); #else pa = p < 0 ? -p : p; pb = pc < 0 ? -pc : pc; pc = (p + pc) < 0 ? -(p + pc) : p + pc; #endif /* Find the best predictor, the least of pa, pb, pc favoring the earlier * ones in the case of a tie. */ if (pb < pa) { pa = pb; a = b; } if (pc < pa) a = c; /* Calculate the current pixel in a, and move the previous row pixel to c * for the next time round the loop */ c = b; a += *row; *row++ = (png_byte)a; } } static void png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, png_const_bytep prev_row) { unsigned int bpp = (row_info->pixel_depth + 7) >> 3; png_bytep rp_end = row + bpp; /* Process the first pixel in the row completely (this is the same as 'up' * because there is only one candidate predictor for the first row). */ while (row < rp_end) { int a = *row + *prev_row++; *row++ = (png_byte)a; } /* Remainder */ rp_end = rp_end + (row_info->rowbytes - bpp); while (row < rp_end) { int a, b, c, pa, pb, pc, p; c = *(prev_row - bpp); a = *(row - bpp); b = *prev_row++; p = b - c; pc = a - c; #ifdef PNG_USE_ABS pa = abs(p); pb = abs(pc); pc = abs(p + pc); #else pa = p < 0 ? -p : p; pb = pc < 0 ? -pc : pc; pc = (p + pc) < 0 ? -(p + pc) : p + pc; #endif if (pb < pa) { pa = pb; a = b; } if (pc < pa) a = c; a += *row; *row++ = (png_byte)a; } } static void png_init_filter_functions(png_structrp pp) /* This function is called once for every PNG image (except for PNG images * that only use PNG_FILTER_VALUE_NONE for all rows) to set the * implementations required to reverse the filtering of PNG rows. Reversing * the filter is the first transformation performed on the row data. It is * performed in place, therefore an implementation can be selected based on * the image pixel format. If the implementation depends on image width then * take care to ensure that it works correctly if the image is interlaced - * interlacing causes the actual row width to vary. */ { unsigned int bpp = (pp->pixel_depth + 7) >> 3; pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub; pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up; pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg; if (bpp == 1) pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth_1byte_pixel; else pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = png_read_filter_row_paeth_multibyte_pixel; #ifdef PNG_FILTER_OPTIMIZATIONS /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to * call to install hardware optimizations for the above functions; simply * replace whatever elements of the pp->read_filter[] array with a hardware * specific (or, for that matter, generic) optimization. * * To see an example of this examine what configure.ac does when * --enable-arm-neon is specified on the command line. */ PNG_FILTER_OPTIMIZATIONS(pp, bpp); #endif } void /* PRIVATE */ png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, png_const_bytep prev_row, int filter) { /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic * implementations. See png_init_filter_functions above. */ if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) { if (pp->read_filter[0] == NULL) png_init_filter_functions(pp); pp->read_filter[filter-1](row_info, row, prev_row); } } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED void /* PRIVATE */ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, png_alloc_size_t avail_out) { /* Loop reading IDATs and decompressing the result into output[avail_out] */ png_ptr->zstream.next_out = output; png_ptr->zstream.avail_out = 0; /* safety: set below */ if (output == NULL) avail_out = 0; do { int ret; png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; if (png_ptr->zstream.avail_in == 0) { uInt avail_in; png_bytep buffer; while (png_ptr->idat_size == 0) { png_crc_finish(png_ptr, 0); png_ptr->idat_size = png_read_chunk_header(png_ptr); /* This is an error even in the 'check' case because the code just * consumed a non-IDAT header. */ if (png_ptr->chunk_name != png_IDAT) png_error(png_ptr, "Not enough image data"); } avail_in = png_ptr->IDAT_read_size; if (avail_in > png_ptr->idat_size) avail_in = (uInt)png_ptr->idat_size; /* A PNG with a gradually increasing IDAT size will defeat this attempt * to minimize memory usage by causing lots of re-allocs, but * realistically doing IDAT_read_size re-allocs is not likely to be a * big problem. */ buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); png_crc_read(png_ptr, buffer, avail_in); png_ptr->idat_size -= avail_in; png_ptr->zstream.next_in = buffer; png_ptr->zstream.avail_in = avail_in; } /* And set up the output side. */ if (output != NULL) /* standard read */ { uInt out = ZLIB_IO_MAX; if (out > avail_out) out = (uInt)avail_out; avail_out -= out; png_ptr->zstream.avail_out = out; } else /* after last row, checking for end */ { png_ptr->zstream.next_out = tmpbuf; png_ptr->zstream.avail_out = (sizeof tmpbuf); } /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the * process. If the LZ stream is truncated the sequential reader will * terminally damage the stream, above, by reading the chunk header of the * following chunk (it then exits with png_error). * * TODO: deal more elegantly with truncated IDAT lists. */ ret = PNG_INFLATE(png_ptr, Z_NO_FLUSH); /* Take the unconsumed output back. */ if (output != NULL) avail_out += png_ptr->zstream.avail_out; else /* avail_out counts the extra bytes */ avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out; png_ptr->zstream.avail_out = 0; if (ret == Z_STREAM_END) { /* Do this for safety; we won't read any more into this row. */ png_ptr->zstream.next_out = NULL; png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) png_chunk_benign_error(png_ptr, "Extra compressed data"); break; } if (ret != Z_OK) { png_zstream_error(png_ptr, ret); if (output != NULL) png_chunk_error(png_ptr, png_ptr->zstream.msg); else /* checking */ { png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); return; } } } while (avail_out > 0); if (avail_out > 0) { /* The stream ended before the image; this is the same as too few IDATs so * should be handled the same way. */ if (output != NULL) png_error(png_ptr, "Not enough image data"); else /* the deflate stream contained extra data */ png_chunk_benign_error(png_ptr, "Too much image data"); } } void /* PRIVATE */ png_read_finish_IDAT(png_structrp png_ptr) { /* We don't need any more data and the stream should have ended, however the * LZ end code may actually not have been processed. In this case we must * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk * may still remain to be consumed. */ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) { /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in * the compressed stream, but the stream may be damaged too, so even after * this call we may need to terminate the zstream ownership. */ png_read_IDAT_data(png_ptr, NULL, 0); png_ptr->zstream.next_out = NULL; /* safety */ /* Now clear everything out for safety; the following may not have been * done. */ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) { png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; } } /* If the zstream has not been released do it now *and* terminate the reading * of the final IDAT chunk. */ if (png_ptr->zowner == png_IDAT) { /* Always do this; the pointers otherwise point into the read buffer. */ png_ptr->zstream.next_in = NULL; png_ptr->zstream.avail_in = 0; /* Now we no longer own the zstream. */ png_ptr->zowner = 0; /* The slightly weird semantics of the sequential IDAT reading is that we * are always in or at the end of an IDAT chunk, so we always need to do a * crc_finish here. If idat_size is non-zero we also need to read the * spurious bytes at the end of the chunk now. */ (void)png_crc_finish(png_ptr, png_ptr->idat_size); } } void /* PRIVATE */ png_read_finish_row(png_structrp png_ptr) { /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; png_debug(1, "in png_read_finish_row"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; /* TO DO: don't do this if prev_row isn't needed (requires * read-ahead of the next row's filter byte. */ memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); do { png_ptr->pass++; if (png_ptr->pass >= 7) break; png_ptr->iwidth = (png_ptr->width + png_pass_inc[png_ptr->pass] - 1 - png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; if ((png_ptr->transformations & PNG_INTERLACE) == 0) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[png_ptr->pass] - 1 - png_pass_ystart[png_ptr->pass]) / png_pass_yinc[png_ptr->pass]; } else /* if (png_ptr->transformations & PNG_INTERLACE) */ break; /* libpng deinterlacing sees every row */ } while (png_ptr->num_rows == 0 || png_ptr->iwidth == 0); if (png_ptr->pass < 7) return; } /* Here after at the end of the last row of the last pass. */ png_read_finish_IDAT(png_ptr); } #endif /* SEQUENTIAL_READ */ void /* PRIVATE */ png_read_start_row(png_structrp png_ptr) { /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; unsigned int max_pixel_depth; png_size_t row_bytes; png_debug(1, "in png_read_start_row"); #ifdef PNG_READ_TRANSFORMS_SUPPORTED png_init_read_transformations(png_ptr); #endif if (png_ptr->interlaced != 0) { if ((png_ptr->transformations & PNG_INTERLACE) == 0) png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; else png_ptr->num_rows = png_ptr->height; png_ptr->iwidth = (png_ptr->width + png_pass_inc[png_ptr->pass] - 1 - png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; } else { png_ptr->num_rows = png_ptr->height; png_ptr->iwidth = png_ptr->width; } max_pixel_depth = (unsigned int)png_ptr->pixel_depth; /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of * calculations to calculate the final pixel depth, then * png_do_read_transforms actually does the transforms. This means that the * code which effectively calculates this value is actually repeated in three * separate places. They must all match. Innocent changes to the order of * transformations can and will break libpng in a way that causes memory * overwrites. * * TODO: fix this. */ #ifdef PNG_READ_PACK_SUPPORTED if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8) max_pixel_depth = 8; #endif #ifdef PNG_READ_EXPAND_SUPPORTED if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if (png_ptr->num_trans != 0) max_pixel_depth = 32; else max_pixel_depth = 24; } else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) { if (max_pixel_depth < 8) max_pixel_depth = 8; if (png_ptr->num_trans != 0) max_pixel_depth *= 2; } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) { if (png_ptr->num_trans != 0) { max_pixel_depth *= 4; max_pixel_depth /= 3; } } } #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED if ((png_ptr->transformations & PNG_EXPAND_16) != 0) { # ifdef PNG_READ_EXPAND_SUPPORTED /* In fact it is an error if it isn't supported, but checking is * the safe way. */ if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (png_ptr->bit_depth < 16) max_pixel_depth *= 2; } else # endif png_ptr->transformations &= ~PNG_EXPAND_16; } #endif #ifdef PNG_READ_FILLER_SUPPORTED if ((png_ptr->transformations & (PNG_FILLER)) != 0) { if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) { if (max_pixel_depth <= 8) max_pixel_depth = 16; else max_pixel_depth = 32; } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB || png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if (max_pixel_depth <= 32) max_pixel_depth = 32; else max_pixel_depth = 64; } } #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) { if ( #ifdef PNG_READ_EXPAND_SUPPORTED (png_ptr->num_trans != 0 && (png_ptr->transformations & PNG_EXPAND) != 0) || #endif #ifdef PNG_READ_FILLER_SUPPORTED (png_ptr->transformations & (PNG_FILLER)) != 0 || #endif png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (max_pixel_depth <= 16) max_pixel_depth = 32; else max_pixel_depth = 64; } else { if (max_pixel_depth <= 8) { if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) max_pixel_depth = 32; else max_pixel_depth = 24; } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA) max_pixel_depth = 64; else max_pixel_depth = 48; } } #endif #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) { unsigned int user_pixel_depth = png_ptr->user_transform_depth * png_ptr->user_transform_channels; if (user_pixel_depth > max_pixel_depth) max_pixel_depth = user_pixel_depth; } #endif /* This value is stored in png_struct and double checked in the row read * code. */ png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth; png_ptr->transformed_pixel_depth = 0; /* calculated on demand */ /* Align the width on the next larger 8 pixels. Mainly used * for interlacing */ row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7)); /* Calculate the maximum bytes needed, adding a byte and a pixel * for safety's sake */ row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + 1 + ((max_pixel_depth + 7) >> 3U); #ifdef PNG_MAX_MALLOC_64K if (row_bytes > (png_uint_32)65536L) png_error(png_ptr, "This image requires a row greater than 64KB"); #endif if (row_bytes + 48 > png_ptr->old_big_row_buf_size) { png_free(png_ptr, png_ptr->big_row_buf); png_free(png_ptr, png_ptr->big_prev_row); if (png_ptr->interlaced != 0) png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, row_bytes + 48); else png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); #ifdef PNG_ALIGNED_MEMORY_SUPPORTED /* Use 16-byte aligned memory for row_buf with at least 16 bytes * of padding before and after row_buf; treat prev_row similarly. * NOTE: the alignment is to the start of the pixels, one beyond the start * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this * was incorrect; the filter byte was aligned, which had the exact * opposite effect of that intended. */ { png_bytep temp = png_ptr->big_row_buf + 32; int extra = (int)((temp - (png_bytep)0) & 0x0f); png_ptr->row_buf = temp - extra - 1/*filter byte*/; temp = png_ptr->big_prev_row + 32; extra = (int)((temp - (png_bytep)0) & 0x0f); png_ptr->prev_row = temp - extra - 1/*filter byte*/; } #else /* Use 31 bytes of padding before and 17 bytes after row_buf. */ png_ptr->row_buf = png_ptr->big_row_buf + 31; png_ptr->prev_row = png_ptr->big_prev_row + 31; #endif png_ptr->old_big_row_buf_size = row_bytes + 48; } #ifdef PNG_MAX_MALLOC_64K if (png_ptr->rowbytes > 65535) png_error(png_ptr, "This image requires a row greater than 64KB"); #endif if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1)) png_error(png_ptr, "Row has too many bytes to allocate in memory"); memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); png_debug1(3, "width = %u,", png_ptr->width); png_debug1(3, "height = %u,", png_ptr->height); png_debug1(3, "iwidth = %u,", png_ptr->iwidth); png_debug1(3, "num_rows = %u,", png_ptr->num_rows); png_debug1(3, "rowbytes = %lu,", (unsigned long)png_ptr->rowbytes); png_debug1(3, "irowbytes = %lu", (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); /* The sequential reader needs a buffer for IDAT, but the progressive reader * does not, so free the read buffer now regardless; the sequential reader * reallocates it on demand. */ if (png_ptr->read_buffer != NULL) { png_bytep buffer = png_ptr->read_buffer; png_ptr->read_buffer_size = 0; png_ptr->read_buffer = NULL; png_free(png_ptr, buffer); } /* Finally claim the zstream for the inflate of the IDAT data, use the bits * value from the stream (note that this will result in a fatal error if the * IDAT stream has a bogus deflate header window_bits value, but this should * not be happening any longer!) */ if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); png_ptr->flags |= PNG_FLAG_ROW_INIT; } #endif /* READ */ stella-5.1.1/src/libpng/pngset.c000066400000000000000000001444171324334165500165310ustar00rootroot00000000000000 /* pngset.c - storage of image information into info struct * * Last changed in libpng 1.6.32 [August 24, 2017] * Copyright (c) 1998-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * The functions here are used during reads to store data from the file * into the info struct, and during writes to store application data * into the info struct for writing into the file. This abstracts the * info struct and allows us to change the structure in the future. */ #include "pngpriv.h" #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) #ifdef PNG_bKGD_SUPPORTED void PNGAPI png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, png_const_color_16p background) { png_debug1(1, "in %s storage function", "bKGD"); if (png_ptr == NULL || info_ptr == NULL || background == NULL) return; info_ptr->background = *background; info_ptr->valid |= PNG_INFO_bKGD; } #endif #ifdef PNG_cHRM_SUPPORTED void PNGFAPI png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, png_fixed_point blue_y) { png_xy xy; png_debug1(1, "in %s storage function", "cHRM fixed"); if (png_ptr == NULL || info_ptr == NULL) return; xy.redx = red_x; xy.redy = red_y; xy.greenx = green_x; xy.greeny = green_y; xy.bluex = blue_x; xy.bluey = blue_y; xy.whitex = white_x; xy.whitey = white_y; if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy, 2/* override with app values*/) != 0) info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; png_colorspace_sync_info(png_ptr, info_ptr); } void PNGFAPI png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, png_fixed_point int_red_Z, png_fixed_point int_green_X, png_fixed_point int_green_Y, png_fixed_point int_green_Z, png_fixed_point int_blue_X, png_fixed_point int_blue_Y, png_fixed_point int_blue_Z) { png_XYZ XYZ; png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); if (png_ptr == NULL || info_ptr == NULL) return; XYZ.red_X = int_red_X; XYZ.red_Y = int_red_Y; XYZ.red_Z = int_red_Z; XYZ.green_X = int_green_X; XYZ.green_Y = int_green_Y; XYZ.green_Z = int_green_Z; XYZ.blue_X = int_blue_X; XYZ.blue_Y = int_blue_Y; XYZ.blue_Z = int_blue_Z; if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, &XYZ, 2) != 0) info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; png_colorspace_sync_info(png_ptr, info_ptr); } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, double green_y, double blue_x, double blue_y) { png_set_cHRM_fixed(png_ptr, info_ptr, png_fixed(png_ptr, white_x, "cHRM White X"), png_fixed(png_ptr, white_y, "cHRM White Y"), png_fixed(png_ptr, red_x, "cHRM Red X"), png_fixed(png_ptr, red_y, "cHRM Red Y"), png_fixed(png_ptr, green_x, "cHRM Green X"), png_fixed(png_ptr, green_y, "cHRM Green Y"), png_fixed(png_ptr, blue_x, "cHRM Blue X"), png_fixed(png_ptr, blue_y, "cHRM Blue Y")); } void PNGAPI png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, double red_Y, double red_Z, double green_X, double green_Y, double green_Z, double blue_X, double blue_Y, double blue_Z) { png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, png_fixed(png_ptr, red_X, "cHRM Red X"), png_fixed(png_ptr, red_Y, "cHRM Red Y"), png_fixed(png_ptr, red_Z, "cHRM Red Z"), png_fixed(png_ptr, green_X, "cHRM Green X"), png_fixed(png_ptr, green_Y, "cHRM Green Y"), png_fixed(png_ptr, green_Z, "cHRM Green Z"), png_fixed(png_ptr, blue_X, "cHRM Blue X"), png_fixed(png_ptr, blue_Y, "cHRM Blue Y"), png_fixed(png_ptr, blue_Z, "cHRM Blue Z")); } # endif /* FLOATING_POINT */ #endif /* cHRM */ #ifdef PNG_eXIf_SUPPORTED void PNGAPI png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, const png_bytep eXIf_buf) { png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1"); PNG_UNUSED(info_ptr) PNG_UNUSED(eXIf_buf) } void PNGAPI png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr, const png_uint_32 num_exif, const png_bytep eXIf_buf) { int i; png_debug1(1, "in %s storage function", "eXIf"); if (png_ptr == NULL || info_ptr == NULL) return; if (info_ptr->exif) { png_free(png_ptr, info_ptr->exif); info_ptr->exif = NULL; } info_ptr->num_exif = num_exif; info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, info_ptr->num_exif)); if (info_ptr->exif == NULL) { png_warning(png_ptr, "Insufficient memory for eXIf chunk data"); return; } info_ptr->free_me |= PNG_FREE_EXIF; for (i = 0; i < (int) info_ptr->num_exif; i++) info_ptr->exif[i] = eXIf_buf[i]; info_ptr->valid |= PNG_INFO_eXIf; } #endif /* eXIf */ #ifdef PNG_gAMA_SUPPORTED void PNGFAPI png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point file_gamma) { png_debug1(1, "in %s storage function", "gAMA"); if (png_ptr == NULL || info_ptr == NULL) return; png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma); png_colorspace_sync_info(png_ptr, info_ptr); } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) { png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, "png_set_gAMA")); } # endif #endif #ifdef PNG_hIST_SUPPORTED void PNGAPI png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, png_const_uint_16p hist) { int i; png_debug1(1, "in %s storage function", "hIST"); if (png_ptr == NULL || info_ptr == NULL) return; if (info_ptr->num_palette == 0 || info_ptr->num_palette > PNG_MAX_PALETTE_LENGTH) { png_warning(png_ptr, "Invalid palette size, hIST allocation skipped"); return; } png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in * version 1.2.1 */ info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); if (info_ptr->hist == NULL) { png_warning(png_ptr, "Insufficient memory for hIST chunk data"); return; } info_ptr->free_me |= PNG_FREE_HIST; for (i = 0; i < info_ptr->num_palette; i++) info_ptr->hist[i] = hist[i]; info_ptr->valid |= PNG_INFO_hIST; } #endif void PNGAPI png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, int filter_type) { png_debug1(1, "in %s storage function", "IHDR"); if (png_ptr == NULL || info_ptr == NULL) return; info_ptr->width = width; info_ptr->height = height; info_ptr->bit_depth = (png_byte)bit_depth; info_ptr->color_type = (png_byte)color_type; info_ptr->compression_type = (png_byte)compression_type; info_ptr->filter_type = (png_byte)filter_type; info_ptr->interlace_type = (png_byte)interlace_type; png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, info_ptr->compression_type, info_ptr->filter_type); if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_ptr->channels = 3; else info_ptr->channels = 1; if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) info_ptr->channels++; info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); } #ifdef PNG_oFFs_SUPPORTED void PNGAPI png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, int unit_type) { png_debug1(1, "in %s storage function", "oFFs"); if (png_ptr == NULL || info_ptr == NULL) return; info_ptr->x_offset = offset_x; info_ptr->y_offset = offset_y; info_ptr->offset_unit_type = (png_byte)unit_type; info_ptr->valid |= PNG_INFO_oFFs; } #endif #ifdef PNG_pCAL_SUPPORTED void PNGAPI png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params) { png_size_t length; int i; png_debug1(1, "in %s storage function", "pCAL"); if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL || (nparams > 0 && params == NULL)) return; length = strlen(purpose) + 1; png_debug1(3, "allocating purpose for info (%lu bytes)", (unsigned long)length); /* TODO: validate format of calibration name and unit name */ /* Check that the type matches the specification. */ if (type < 0 || type > 3) { png_chunk_report(png_ptr, "Invalid pCAL equation type", PNG_CHUNK_WRITE_ERROR); return; } if (nparams < 0 || nparams > 255) { png_chunk_report(png_ptr, "Invalid pCAL parameter count", PNG_CHUNK_WRITE_ERROR); return; } /* Validate params[nparams] */ for (i=0; ipcal_purpose = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); if (info_ptr->pcal_purpose == NULL) { png_chunk_report(png_ptr, "Insufficient memory for pCAL purpose", PNG_CHUNK_WRITE_ERROR); return; } memcpy(info_ptr->pcal_purpose, purpose, length); png_debug(3, "storing X0, X1, type, and nparams in info"); info_ptr->pcal_X0 = X0; info_ptr->pcal_X1 = X1; info_ptr->pcal_type = (png_byte)type; info_ptr->pcal_nparams = (png_byte)nparams; length = strlen(units) + 1; png_debug1(3, "allocating units for info (%lu bytes)", (unsigned long)length); info_ptr->pcal_units = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); if (info_ptr->pcal_units == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL units"); return; } memcpy(info_ptr->pcal_units, units, length); info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, (png_size_t)(((unsigned int)nparams + 1) * (sizeof (png_charp))))); if (info_ptr->pcal_params == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL params"); return; } memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) * (sizeof (png_charp))); for (i = 0; i < nparams; i++) { length = strlen(params[i]) + 1; png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, (unsigned long)length); info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); if (info_ptr->pcal_params[i] == NULL) { png_warning(png_ptr, "Insufficient memory for pCAL parameter"); return; } memcpy(info_ptr->pcal_params[i], params[i], length); } info_ptr->valid |= PNG_INFO_pCAL; info_ptr->free_me |= PNG_FREE_PCAL; } #endif #ifdef PNG_sCAL_SUPPORTED void PNGAPI png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_const_charp swidth, png_const_charp sheight) { png_size_t lengthw = 0, lengthh = 0; png_debug1(1, "in %s storage function", "sCAL"); if (png_ptr == NULL || info_ptr == NULL) return; /* Double check the unit (should never get here with an invalid * unit unless this is an API call.) */ if (unit != 1 && unit != 2) png_error(png_ptr, "Invalid sCAL unit"); if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) png_error(png_ptr, "Invalid sCAL width"); if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) png_error(png_ptr, "Invalid sCAL height"); info_ptr->scal_unit = (png_byte)unit; ++lengthw; png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); info_ptr->scal_s_width = png_voidcast(png_charp, png_malloc_warn(png_ptr, lengthw)); if (info_ptr->scal_s_width == NULL) { png_warning(png_ptr, "Memory allocation failed while processing sCAL"); return; } memcpy(info_ptr->scal_s_width, swidth, lengthw); ++lengthh; png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); info_ptr->scal_s_height = png_voidcast(png_charp, png_malloc_warn(png_ptr, lengthh)); if (info_ptr->scal_s_height == NULL) { png_free (png_ptr, info_ptr->scal_s_width); info_ptr->scal_s_width = NULL; png_warning(png_ptr, "Memory allocation failed while processing sCAL"); return; } memcpy(info_ptr->scal_s_height, sheight, lengthh); info_ptr->valid |= PNG_INFO_sCAL; info_ptr->free_me |= PNG_FREE_SCAL; } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, double width, double height) { png_debug1(1, "in %s storage function", "sCAL"); /* Check the arguments. */ if (width <= 0) png_warning(png_ptr, "Invalid sCAL width ignored"); else if (height <= 0) png_warning(png_ptr, "Invalid sCAL height ignored"); else { /* Convert 'width' and 'height' to ASCII. */ char swidth[PNG_sCAL_MAX_DIGITS+1]; char sheight[PNG_sCAL_MAX_DIGITS+1]; png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, PNG_sCAL_PRECISION); png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, PNG_sCAL_PRECISION); png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); } } # endif # ifdef PNG_FIXED_POINT_SUPPORTED void PNGAPI png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_fixed_point width, png_fixed_point height) { png_debug1(1, "in %s storage function", "sCAL"); /* Check the arguments. */ if (width <= 0) png_warning(png_ptr, "Invalid sCAL width ignored"); else if (height <= 0) png_warning(png_ptr, "Invalid sCAL height ignored"); else { /* Convert 'width' and 'height' to ASCII. */ char swidth[PNG_sCAL_MAX_DIGITS+1]; char sheight[PNG_sCAL_MAX_DIGITS+1]; png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); } } # endif #endif #ifdef PNG_pHYs_SUPPORTED void PNGAPI png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type) { png_debug1(1, "in %s storage function", "pHYs"); if (png_ptr == NULL || info_ptr == NULL) return; info_ptr->x_pixels_per_unit = res_x; info_ptr->y_pixels_per_unit = res_y; info_ptr->phys_unit_type = (png_byte)unit_type; info_ptr->valid |= PNG_INFO_pHYs; } #endif void PNGAPI png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_const_colorp palette, int num_palette) { png_uint_32 max_palette_length; png_debug1(1, "in %s storage function", "PLTE"); if (png_ptr == NULL || info_ptr == NULL) return; max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; if (num_palette < 0 || num_palette > (int) max_palette_length) { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_error(png_ptr, "Invalid palette length"); else { png_warning(png_ptr, "Invalid palette length"); return; } } if ((num_palette > 0 && palette == NULL) || (num_palette == 0 # ifdef PNG_MNG_FEATURES_SUPPORTED && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 # endif )) { png_error(png_ptr, "Invalid palette"); } /* It may not actually be necessary to set png_ptr->palette here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. * * 1.6.0: the above statement appears to be incorrect; something has to set * the palette inside png_struct on read. */ png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead * of num_palette entries, in case of an invalid PNG file or incorrect * call to png_set_PLTE() with too-large sample values. */ png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); if (num_palette > 0) memcpy(png_ptr->palette, palette, (unsigned int)num_palette * (sizeof (png_color))); info_ptr->palette = png_ptr->palette; info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; info_ptr->free_me |= PNG_FREE_PLTE; info_ptr->valid |= PNG_INFO_PLTE; } #ifdef PNG_sBIT_SUPPORTED void PNGAPI png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, png_const_color_8p sig_bit) { png_debug1(1, "in %s storage function", "sBIT"); if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) return; info_ptr->sig_bit = *sig_bit; info_ptr->valid |= PNG_INFO_sBIT; } #endif #ifdef PNG_sRGB_SUPPORTED void PNGAPI png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) { png_debug1(1, "in %s storage function", "sRGB"); if (png_ptr == NULL || info_ptr == NULL) return; (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent); png_colorspace_sync_info(png_ptr, info_ptr); } void PNGAPI png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) { png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); if (png_ptr == NULL || info_ptr == NULL) return; if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent) != 0) { /* This causes the gAMA and cHRM to be written too */ info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; } png_colorspace_sync_info(png_ptr, info_ptr); } #endif /* sRGB */ #ifdef PNG_iCCP_SUPPORTED void PNGAPI png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp name, int compression_type, png_const_bytep profile, png_uint_32 proflen) { png_charp new_iccp_name; png_bytep new_iccp_profile; png_size_t length; png_debug1(1, "in %s storage function", "iCCP"); if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) return; if (compression_type != PNG_COMPRESSION_TYPE_BASE) png_app_error(png_ptr, "Invalid iCCP compression method"); /* Set the colorspace first because this validates the profile; do not * override previously set app cHRM or gAMA here (because likely as not the * application knows better than libpng what the correct values are.) Pass * the info_ptr color_type field to png_colorspace_set_ICC because in the * write case it has not yet been stored in png_ptr. */ { int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name, proflen, profile, info_ptr->color_type); png_colorspace_sync_info(png_ptr, info_ptr); /* Don't do any of the copying if the profile was bad, or inconsistent. */ if (result == 0) return; /* But do write the gAMA and cHRM chunks from the profile. */ info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; } length = strlen(name)+1; new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); if (new_iccp_name == NULL) { png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); return; } memcpy(new_iccp_name, name, length); new_iccp_profile = png_voidcast(png_bytep, png_malloc_warn(png_ptr, proflen)); if (new_iccp_profile == NULL) { png_free(png_ptr, new_iccp_name); png_benign_error(png_ptr, "Insufficient memory to process iCCP profile"); return; } memcpy(new_iccp_profile, profile, proflen); png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); info_ptr->iccp_proflen = proflen; info_ptr->iccp_name = new_iccp_name; info_ptr->iccp_profile = new_iccp_profile; info_ptr->free_me |= PNG_FREE_ICCP; info_ptr->valid |= PNG_INFO_iCCP; } #endif #ifdef PNG_TEXT_SUPPORTED void PNGAPI png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, png_const_textp text_ptr, int num_text) { int ret; ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); if (ret != 0) png_error(png_ptr, "Insufficient memory to store text"); } int /* PRIVATE */ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, png_const_textp text_ptr, int num_text) { int i; png_debug1(1, "in %lx storage function", png_ptr == NULL ? 0xabadca11U : (unsigned long)png_ptr->chunk_name); if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) return(0); /* Make sure we have enough space in the "text" array in info_struct * to hold all of the incoming text_ptr objects. This compare can't overflow * because max_text >= num_text (anyway, subtract of two positive integers * can't overflow in any case.) */ if (num_text > info_ptr->max_text - info_ptr->num_text) { int old_num_text = info_ptr->num_text; int max_text; png_textp new_text = NULL; /* Calculate an appropriate max_text, checking for overflow. */ max_text = old_num_text; if (num_text <= INT_MAX - max_text) { max_text += num_text; /* Round up to a multiple of 8 */ if (max_text < INT_MAX-8) max_text = (max_text + 8) & ~0x7; else max_text = INT_MAX; /* Now allocate a new array and copy the old members in; this does all * the overflow checks. */ new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, info_ptr->text, old_num_text, max_text-old_num_text, sizeof *new_text)); } if (new_text == NULL) { png_chunk_report(png_ptr, "too many text chunks", PNG_CHUNK_WRITE_ERROR); return 1; } png_free(png_ptr, info_ptr->text); info_ptr->text = new_text; info_ptr->free_me |= PNG_FREE_TEXT; info_ptr->max_text = max_text; /* num_text is adjusted below as the entries are copied in */ png_debug1(3, "allocated %d entries for info_ptr->text", max_text); } for (i = 0; i < num_text; i++) { size_t text_length, key_len; size_t lang_len, lang_key_len; png_textp textp = &(info_ptr->text[info_ptr->num_text]); if (text_ptr[i].key == NULL) continue; if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE || text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) { png_chunk_report(png_ptr, "text compression mode is out of range", PNG_CHUNK_WRITE_ERROR); continue; } key_len = strlen(text_ptr[i].key); if (text_ptr[i].compression <= 0) { lang_len = 0; lang_key_len = 0; } else # ifdef PNG_iTXt_SUPPORTED { /* Set iTXt data */ if (text_ptr[i].lang != NULL) lang_len = strlen(text_ptr[i].lang); else lang_len = 0; if (text_ptr[i].lang_key != NULL) lang_key_len = strlen(text_ptr[i].lang_key); else lang_key_len = 0; } # else /* iTXt */ { png_chunk_report(png_ptr, "iTXt chunk not supported", PNG_CHUNK_WRITE_ERROR); continue; } # endif if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') { text_length = 0; # ifdef PNG_iTXt_SUPPORTED if (text_ptr[i].compression > 0) textp->compression = PNG_ITXT_COMPRESSION_NONE; else # endif textp->compression = PNG_TEXT_COMPRESSION_NONE; } else { text_length = strlen(text_ptr[i].text); textp->compression = text_ptr[i].compression; } textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, key_len + text_length + lang_len + lang_key_len + 4)); if (textp->key == NULL) { png_chunk_report(png_ptr, "text chunk: out of memory", PNG_CHUNK_WRITE_ERROR); return 1; } png_debug2(2, "Allocated %lu bytes at %p in png_set_text", (unsigned long)(png_uint_32) (key_len + lang_len + lang_key_len + text_length + 4), textp->key); memcpy(textp->key, text_ptr[i].key, key_len); *(textp->key + key_len) = '\0'; if (text_ptr[i].compression > 0) { textp->lang = textp->key + key_len + 1; memcpy(textp->lang, text_ptr[i].lang, lang_len); *(textp->lang + lang_len) = '\0'; textp->lang_key = textp->lang + lang_len + 1; memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); *(textp->lang_key + lang_key_len) = '\0'; textp->text = textp->lang_key + lang_key_len + 1; } else { textp->lang=NULL; textp->lang_key=NULL; textp->text = textp->key + key_len + 1; } if (text_length != 0) memcpy(textp->text, text_ptr[i].text, text_length); *(textp->text + text_length) = '\0'; # ifdef PNG_iTXt_SUPPORTED if (textp->compression > 0) { textp->text_length = 0; textp->itxt_length = text_length; } else # endif { textp->text_length = text_length; textp->itxt_length = 0; } info_ptr->num_text++; png_debug1(3, "transferred text chunk %d", info_ptr->num_text); } return(0); } #endif #ifdef PNG_tIME_SUPPORTED void PNGAPI png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, png_const_timep mod_time) { png_debug1(1, "in %s storage function", "tIME"); if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || (png_ptr->mode & PNG_WROTE_tIME) != 0) return; if (mod_time->month == 0 || mod_time->month > 12 || mod_time->day == 0 || mod_time->day > 31 || mod_time->hour > 23 || mod_time->minute > 59 || mod_time->second > 60) { png_warning(png_ptr, "Ignoring invalid time value"); return; } info_ptr->mod_time = *mod_time; info_ptr->valid |= PNG_INFO_tIME; } #endif #ifdef PNG_tRNS_SUPPORTED void PNGAPI png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) { png_debug1(1, "in %s storage function", "tRNS"); if (png_ptr == NULL || info_ptr == NULL) return; if (trans_alpha != NULL) { /* It may not actually be necessary to set png_ptr->trans_alpha here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. * * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively * relies on png_set_tRNS storing the information in png_struct * (otherwise it won't be there for the code in pngrtran.c). */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) { /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ info_ptr->trans_alpha = png_voidcast(png_bytep, png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); } png_ptr->trans_alpha = info_ptr->trans_alpha; } if (trans_color != NULL) { #ifdef PNG_WARNINGS_SUPPORTED if (info_ptr->bit_depth < 16) { int sample_max = (1 << info_ptr->bit_depth) - 1; if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && trans_color->gray > sample_max) || (info_ptr->color_type == PNG_COLOR_TYPE_RGB && (trans_color->red > sample_max || trans_color->green > sample_max || trans_color->blue > sample_max))) png_warning(png_ptr, "tRNS chunk has out-of-range samples for bit_depth"); } #endif info_ptr->trans_color = *trans_color; if (num_trans == 0) num_trans = 1; } info_ptr->num_trans = (png_uint_16)num_trans; if (num_trans != 0) { info_ptr->valid |= PNG_INFO_tRNS; info_ptr->free_me |= PNG_FREE_TRNS; } } #endif #ifdef PNG_sPLT_SUPPORTED void PNGAPI png_set_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) /* * entries - array of png_sPLT_t structures * to be added to the list of palettes * in the info structure. * * nentries - number of palette structures to be * added. */ { png_sPLT_tp np; if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) return; /* Use the internal realloc function, which checks for all the possible * overflows. Notice that the parameters are (int) and (size_t) */ np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, sizeof *np)); if (np == NULL) { /* Out of memory or too many chunks */ png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); return; } png_free(png_ptr, info_ptr->splt_palettes); info_ptr->splt_palettes = np; info_ptr->free_me |= PNG_FREE_SPLT; np += info_ptr->splt_palettes_num; do { png_size_t length; /* Skip invalid input entries */ if (entries->name == NULL || entries->entries == NULL) { /* png_handle_sPLT doesn't do this, so this is an app error */ png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); /* Just skip the invalid entry */ continue; } np->depth = entries->depth; /* In the event of out-of-memory just return - there's no point keeping * on trying to add sPLT chunks. */ length = strlen(entries->name) + 1; np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); if (np->name == NULL) break; memcpy(np->name, entries->name, length); /* IMPORTANT: we have memory now that won't get freed if something else * goes wrong; this code must free it. png_malloc_array produces no * warnings; use a png_chunk_report (below) if there is an error. */ np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, entries->nentries, sizeof (png_sPLT_entry))); if (np->entries == NULL) { png_free(png_ptr, np->name); np->name = NULL; break; } np->nentries = entries->nentries; /* This multiply can't overflow because png_malloc_array has already * checked it when doing the allocation. */ memcpy(np->entries, entries->entries, (unsigned int)entries->nentries * sizeof (png_sPLT_entry)); /* Note that 'continue' skips the advance of the out pointer and out * count, so an invalid entry is not added. */ info_ptr->valid |= PNG_INFO_sPLT; ++(info_ptr->splt_palettes_num); ++np; ++entries; } while (--nentries); if (nentries > 0) png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); } #endif /* sPLT */ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED static png_byte check_location(png_const_structrp png_ptr, int location) { location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); /* New in 1.6.0; copy the location and check it. This is an API * change; previously the app had to use the * png_set_unknown_chunk_location API below for each chunk. */ if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0) { /* Write struct, so unknown chunks come from the app */ png_app_warning(png_ptr, "png_set_unknown_chunks now expects a valid location"); /* Use the old behavior */ location = (png_byte)(png_ptr->mode & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); } /* This need not be an internal error - if the app calls * png_set_unknown_chunks on a read pointer it must get the location right. */ if (location == 0) png_error(png_ptr, "invalid location in png_set_unknown_chunks"); /* Now reduce the location to the top-most set bit by removing each least * significant bit in turn. */ while (location != (location & -location)) location &= ~(location & -location); /* The cast is safe because 'location' is a bit mask and only the low four * bits are significant. */ return (png_byte)location; } void PNGAPI png_set_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) { png_unknown_chunkp np; if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || unknowns == NULL) return; /* Check for the failure cases where support has been disabled at compile * time. This code is hardly ever compiled - it's here because * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this * code) but may be meaningless if the read or write handling of unknown * chunks is not compiled in. */ # if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ defined(PNG_READ_SUPPORTED) if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) { png_app_error(png_ptr, "no unknown chunk support on read"); return; } # endif # if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ defined(PNG_WRITE_SUPPORTED) if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) { png_app_error(png_ptr, "no unknown chunk support on write"); return; } # endif /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that * unknown critical chunks could be lost with just a warning resulting in * undefined behavior. Now png_chunk_report is used to provide behavior * appropriate to read or write. */ np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, sizeof *np)); if (np == NULL) { png_chunk_report(png_ptr, "too many unknown chunks", PNG_CHUNK_WRITE_ERROR); return; } png_free(png_ptr, info_ptr->unknown_chunks); info_ptr->unknown_chunks = np; /* safe because it is initialized */ info_ptr->free_me |= PNG_FREE_UNKN; np += info_ptr->unknown_chunks_num; /* Increment unknown_chunks_num each time round the loop to protect the * just-allocated chunk data. */ for (; num_unknowns > 0; --num_unknowns, ++unknowns) { memcpy(np->name, unknowns->name, (sizeof np->name)); np->name[(sizeof np->name)-1] = '\0'; np->location = check_location(png_ptr, unknowns->location); if (unknowns->size == 0) { np->data = NULL; np->size = 0; } else { np->data = png_voidcast(png_bytep, png_malloc_base(png_ptr, unknowns->size)); if (np->data == NULL) { png_chunk_report(png_ptr, "unknown chunk: out of memory", PNG_CHUNK_WRITE_ERROR); /* But just skip storing the unknown chunk */ continue; } memcpy(np->data, unknowns->data, unknowns->size); np->size = unknowns->size; } /* These increments are skipped on out-of-memory for the data - the * unknown chunk entry gets overwritten if the png_chunk_report returns. * This is correct in the read case (the chunk is just dropped.) */ ++np; ++(info_ptr->unknown_chunks_num); } } void PNGAPI png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location) { /* This API is pretty pointless in 1.6.0 because the location can be set * before the call to png_set_unknown_chunks. * * TODO: add a png_app_warning in 1.7 */ if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk < info_ptr->unknown_chunks_num) { if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) { png_app_error(png_ptr, "invalid unknown chunk location"); /* Fake out the pre 1.6.0 behavior: */ if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */ location = PNG_AFTER_IDAT; else location = PNG_HAVE_IHDR; /* also undocumented */ } info_ptr->unknown_chunks[chunk].location = check_location(png_ptr, location); } } #endif /* STORE_UNKNOWN_CHUNKS */ #ifdef PNG_MNG_FEATURES_SUPPORTED png_uint_32 PNGAPI png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) { png_debug(1, "in png_permit_mng_features"); if (png_ptr == NULL) return 0; png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; return png_ptr->mng_features_permitted; } #endif #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED static unsigned int add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) { unsigned int i; /* Utility function: update the 'keep' state of a chunk if it is already in * the list, otherwise add it to the list. */ for (i=0; i= PNG_HANDLE_CHUNK_LAST) { png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); return; } if (num_chunks_in <= 0) { png_ptr->unknown_default = keep; /* '0' means just set the flags, so stop here */ if (num_chunks_in == 0) return; } if (num_chunks_in < 0) { /* Ignore all unknown chunks and all chunks recognized by * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND */ static PNG_CONST png_byte chunks_to_ignore[] = { 98, 75, 71, 68, '\0', /* bKGD */ 99, 72, 82, 77, '\0', /* cHRM */ 101, 88, 73, 102, '\0', /* eXIf */ 103, 65, 77, 65, '\0', /* gAMA */ 104, 73, 83, 84, '\0', /* hIST */ 105, 67, 67, 80, '\0', /* iCCP */ 105, 84, 88, 116, '\0', /* iTXt */ 111, 70, 70, 115, '\0', /* oFFs */ 112, 67, 65, 76, '\0', /* pCAL */ 112, 72, 89, 115, '\0', /* pHYs */ 115, 66, 73, 84, '\0', /* sBIT */ 115, 67, 65, 76, '\0', /* sCAL */ 115, 80, 76, 84, '\0', /* sPLT */ 115, 84, 69, 82, '\0', /* sTER */ 115, 82, 71, 66, '\0', /* sRGB */ 116, 69, 88, 116, '\0', /* tEXt */ 116, 73, 77, 69, '\0', /* tIME */ 122, 84, 88, 116, '\0' /* zTXt */ }; chunk_list = chunks_to_ignore; num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U; } else /* num_chunks_in > 0 */ { if (chunk_list == NULL) { /* Prior to 1.6.0 this was silently ignored, now it is an app_error * which can be switched off. */ png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); return; } num_chunks = (unsigned int)num_chunks_in; } old_num_chunks = png_ptr->num_chunk_list; if (png_ptr->chunk_list == NULL) old_num_chunks = 0; /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. */ if (num_chunks + old_num_chunks > UINT_MAX/5) { png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); return; } /* If these chunks are being reset to the default then no more memory is * required because add_one_chunk above doesn't extend the list if the 'keep' * parameter is the default. */ if (keep != 0) { new_list = png_voidcast(png_bytep, png_malloc(png_ptr, 5 * (num_chunks + old_num_chunks))); if (old_num_chunks > 0) memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); } else if (old_num_chunks > 0) new_list = png_ptr->chunk_list; else new_list = NULL; /* Add the new chunks together with each one's handling code. If the chunk * already exists the code is updated, otherwise the chunk is added to the * end. (In libpng 1.6.0 order no longer matters because this code enforces * the earlier convention that the last setting is the one that is used.) */ if (new_list != NULL) { png_const_bytep inlist; png_bytep outlist; unsigned int i; for (i=0; ichunk_list != new_list) png_free(png_ptr, new_list); new_list = NULL; } } else num_chunks = 0; png_ptr->num_chunk_list = num_chunks; if (png_ptr->chunk_list != new_list) { if (png_ptr->chunk_list != NULL) png_free(png_ptr, png_ptr->chunk_list); png_ptr->chunk_list = new_list; } } #endif #ifdef PNG_READ_USER_CHUNKS_SUPPORTED void PNGAPI png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn) { png_debug(1, "in png_set_read_user_chunk_fn"); if (png_ptr == NULL) return; png_ptr->read_user_chunk_fn = read_user_chunk_fn; png_ptr->user_chunk_ptr = user_chunk_ptr; } #endif #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, png_bytepp row_pointers) { png_debug1(1, "in %s storage function", "rows"); if (png_ptr == NULL || info_ptr == NULL) return; if (info_ptr->row_pointers != NULL && (info_ptr->row_pointers != row_pointers)) png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); info_ptr->row_pointers = row_pointers; if (row_pointers != NULL) info_ptr->valid |= PNG_INFO_IDAT; } #endif void PNGAPI png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) { if (png_ptr == NULL) return; if (size == 0 || size > PNG_UINT_31_MAX) png_error(png_ptr, "invalid compression buffer size"); # ifdef PNG_SEQUENTIAL_READ_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) { png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ return; } # endif # ifdef PNG_WRITE_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) { if (png_ptr->zowner != 0) { png_warning(png_ptr, "Compression buffer size cannot be changed because it is in use"); return; } #ifndef __COVERITY__ /* Some compilers complain that this is always false. However, it * can be true when integer overflow happens. */ if (size > ZLIB_IO_MAX) { png_warning(png_ptr, "Compression buffer size limited to system maximum"); size = ZLIB_IO_MAX; /* must fit */ } #endif if (size < 6) { /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH * if this is permitted. */ png_warning(png_ptr, "Compression buffer size cannot be reduced below 6"); return; } if (png_ptr->zbuffer_size != size) { png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); png_ptr->zbuffer_size = (uInt)size; } } # endif } void PNGAPI png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) { if (png_ptr != NULL && info_ptr != NULL) info_ptr->valid &= (unsigned int)(~mask); } #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* This function was added to libpng 1.2.6 */ void PNGAPI png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max) { /* Images with dimensions larger than these limits will be * rejected by png_set_IHDR(). To accept any PNG datastream * regardless of dimensions, set both limits to 0x7fffffff. */ if (png_ptr == NULL) return; png_ptr->user_width_max = user_width_max; png_ptr->user_height_max = user_height_max; } /* This function was added to libpng 1.4.0 */ void PNGAPI png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) { if (png_ptr != NULL) png_ptr->user_chunk_cache_max = user_chunk_cache_max; } /* This function was added to libpng 1.4.1 */ void PNGAPI png_set_chunk_malloc_max (png_structrp png_ptr, png_alloc_size_t user_chunk_malloc_max) { if (png_ptr != NULL) png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; } #endif /* ?SET_USER_LIMITS */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI png_set_benign_errors(png_structrp png_ptr, int allowed) { png_debug(1, "in png_set_benign_errors"); /* If allowed is 1, png_benign_error() is treated as a warning. * * If allowed is 0, png_benign_error() is treated as an error (which * is the default behavior if png_set_benign_errors() is not called). */ if (allowed != 0) png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; else png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); } #endif /* BENIGN_ERRORS */ #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Whether to report invalid palette index; added at libng-1.5.10. * It is possible for an indexed (color-type==3) PNG file to contain * pixels with invalid (out-of-range) indexes if the PLTE chunk has * fewer entries than the image's bit-depth would allow. We recover * from this gracefully by filling any incomplete palette with zeros * (opaque black). By default, when this occurs libpng will issue * a benign error. This API can be used to override that behavior. */ void PNGAPI png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) { png_debug(1, "in png_set_check_for_invalid_index"); if (allowed > 0) png_ptr->num_palette_max = 0; else png_ptr->num_palette_max = -1; } #endif #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \ defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) /* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, * and if invalid, correct the keyword rather than discarding the entire * chunk. The PNG 1.0 specification requires keywords 1-79 characters in * length, forbids leading or trailing whitespace, multiple internal spaces, * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. * * The 'new_key' buffer must be 80 characters in size (for the keyword plus a * trailing '\0'). If this routine returns 0 then there was no keyword, or a * valid one could not be generated, and the caller must png_error. */ png_uint_32 /* PRIVATE */ png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) { #ifdef PNG_WARNINGS_SUPPORTED png_const_charp orig_key = key; #endif png_uint_32 key_len = 0; int bad_character = 0; int space = 1; png_debug(1, "in png_check_keyword"); if (key == NULL) { *new_key = 0; return 0; } while (*key && key_len < 79) { png_byte ch = (png_byte)*key++; if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) { *new_key++ = ch; ++key_len; space = 0; } else if (space == 0) { /* A space or an invalid character when one wasn't seen immediately * before; output just a space. */ *new_key++ = 32; ++key_len; space = 1; /* If the character was not a space then it is invalid. */ if (ch != 32) bad_character = ch; } else if (bad_character == 0) bad_character = ch; /* just skip it, record the first error */ } if (key_len > 0 && space != 0) /* trailing space */ { --key_len; --new_key; if (bad_character == 0) bad_character = 32; } /* Terminate the keyword */ *new_key = 0; if (key_len == 0) return 0; #ifdef PNG_WARNINGS_SUPPORTED /* Try to only output one warning per keyword: */ if (*key != 0) /* keyword too long */ png_warning(png_ptr, "keyword truncated"); else if (bad_character != 0) { PNG_WARNING_PARAMETERS(p) png_warning_parameter(p, 1, orig_key); png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); } #else /* !WARNINGS */ PNG_UNUSED(png_ptr) #endif /* !WARNINGS */ return key_len; } #endif /* TEXT || pCAL || iCCP || sPLT */ #endif /* READ || WRITE */ stella-5.1.1/src/libpng/pngstruct.h000066400000000000000000000471051324334165500172630ustar00rootroot00000000000000 /* pngstruct.h - header file for PNG reference library * * Last changed in libpng 1.6.32 [August 24, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ /* The structure that holds the information to read and write PNG files. * The only people who need to care about what is inside of this are the * people who will be modifying the library for their own special needs. * It should NOT be accessed directly by an application. */ #ifndef PNGSTRUCT_H #define PNGSTRUCT_H /* zlib.h defines the structure z_stream, an instance of which is included * in this structure and is required for decompressing the LZ compressed * data in PNG files. */ #ifndef ZLIB_CONST /* We must ensure that zlib uses 'const' in declarations. */ # define ZLIB_CONST #endif #include "zlib.h" #ifdef const /* zlib.h sometimes #defines const to nothing, undo this. */ # undef const #endif /* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility * with older builds. */ #if ZLIB_VERNUM < 0x1260 # define PNGZ_MSG_CAST(s) png_constcast(char*,s) # define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) #else # define PNGZ_MSG_CAST(s) (s) # define PNGZ_INPUT_CAST(b) (b) #endif /* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib * can handle at once. This type need be no larger than 16 bits (so maximum of * 65535), this define allows us to discover how big it is, but limited by the * maximuum for png_size_t. The value can be overriden in a library build * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably * lower value (e.g. 255 works). A lower value may help memory usage (slightly) * and may even improve performance on some systems (and degrade it on others.) */ #ifndef ZLIB_IO_MAX # define ZLIB_IO_MAX ((uInt)-1) #endif #ifdef PNG_WRITE_SUPPORTED /* The type of a compression buffer list used by the write code. */ typedef struct png_compression_buffer { struct png_compression_buffer *next; png_byte output[1]; /* actually zbuf_size */ } png_compression_buffer, *png_compression_bufferp; #define PNG_COMPRESSION_BUFFER_SIZE(pp)\ (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) #endif /* Colorspace support; structures used in png_struct, png_info and in internal * functions to hold and communicate information about the color space. * * PNG_COLORSPACE_SUPPORTED is only required if the application will perform * colorspace corrections, otherwise all the colorspace information can be * skipped and the size of libpng can be reduced (significantly) by compiling * out the colorspace support. */ #ifdef PNG_COLORSPACE_SUPPORTED /* The chromaticities of the red, green and blue colorants and the chromaticity * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). */ typedef struct png_xy { png_fixed_point redx, redy; png_fixed_point greenx, greeny; png_fixed_point bluex, bluey; png_fixed_point whitex, whitey; } png_xy; /* The same data as above but encoded as CIE XYZ values. When this data comes * from chromaticities the sum of the Y values is assumed to be 1.0 */ typedef struct png_XYZ { png_fixed_point red_X, red_Y, red_Z; png_fixed_point green_X, green_Y, green_Z; png_fixed_point blue_X, blue_Y, blue_Z; } png_XYZ; #endif /* COLORSPACE */ #if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) /* A colorspace is all the above plus, potentially, profile information; * however at present libpng does not use the profile internally so it is only * stored in the png_info struct (if iCCP is supported.) The rendering intent * is retained here and is checked. * * The file gamma encoding information is also stored here and gamma correction * is done by libpng, whereas color correction must currently be done by the * application. */ typedef struct png_colorspace { #ifdef PNG_GAMMA_SUPPORTED png_fixed_point gamma; /* File gamma */ #endif #ifdef PNG_COLORSPACE_SUPPORTED png_xy end_points_xy; /* End points as chromaticities */ png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ png_uint_16 rendering_intent; /* Rendering intent of a profile */ #endif /* Flags are always defined to simplify the code. */ png_uint_16 flags; /* As defined below */ } png_colorspace, * PNG_RESTRICT png_colorspacerp; typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; /* General flags for the 'flags' field */ #define PNG_COLORSPACE_HAVE_GAMMA 0x0001 #define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 #define PNG_COLORSPACE_HAVE_INTENT 0x0004 #define PNG_COLORSPACE_FROM_gAMA 0x0008 #define PNG_COLORSPACE_FROM_cHRM 0x0010 #define PNG_COLORSPACE_FROM_sRGB 0x0020 #define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 #define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ #define PNG_COLORSPACE_INVALID 0x8000 #define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) #endif /* COLORSPACE || GAMMA */ struct png_struct_def { #ifdef PNG_SETJMP_SUPPORTED jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ size_t jmp_buf_size; /* size of the above, if allocated */ #endif png_error_ptr error_fn; /* function for printing errors and aborting */ #ifdef PNG_WARNINGS_SUPPORTED png_error_ptr warning_fn; /* function for printing warnings */ #endif png_voidp error_ptr; /* user supplied struct for error functions */ png_rw_ptr write_data_fn; /* function for writing output data */ png_rw_ptr read_data_fn; /* function for reading input data */ png_voidp io_ptr; /* ptr to application struct for I/O functions */ #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED png_user_transform_ptr read_user_transform_fn; /* user read transform */ #endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED png_user_transform_ptr write_user_transform_fn; /* user write transform */ #endif /* These were added in libpng-1.0.2 */ #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) png_voidp user_transform_ptr; /* user supplied struct for user transform */ png_byte user_transform_depth; /* bit depth of user transformed pixels */ png_byte user_transform_channels; /* channels in user transformed pixels */ #endif #endif png_uint_32 mode; /* tells us where we are in the PNG file */ png_uint_32 flags; /* flags indicating various things to libpng */ png_uint_32 transformations; /* which transformations to perform */ png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ z_stream zstream; /* decompression structure */ #ifdef PNG_WRITE_SUPPORTED png_compression_bufferp zbuffer_list; /* Created on demand during write */ uInt zbuffer_size; /* size of the actual buffer */ int zlib_level; /* holds zlib compression level */ int zlib_method; /* holds zlib compression method */ int zlib_window_bits; /* holds zlib compression window bits */ int zlib_mem_level; /* holds zlib compression memory level */ int zlib_strategy; /* holds zlib compression strategy */ #endif /* Added at libpng 1.5.4 */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED int zlib_text_level; /* holds zlib compression level */ int zlib_text_method; /* holds zlib compression method */ int zlib_text_window_bits; /* holds zlib compression window bits */ int zlib_text_mem_level; /* holds zlib compression memory level */ int zlib_text_strategy; /* holds zlib compression strategy */ #endif /* End of material added at libpng 1.5.4 */ /* Added at libpng 1.6.0 */ #ifdef PNG_WRITE_SUPPORTED int zlib_set_level; /* Actual values set into the zstream on write */ int zlib_set_method; int zlib_set_window_bits; int zlib_set_mem_level; int zlib_set_strategy; #endif png_uint_32 width; /* width of image in pixels */ png_uint_32 height; /* height of image in pixels */ png_uint_32 num_rows; /* number of rows in current pass */ png_uint_32 usr_width; /* width of row at start of write */ png_size_t rowbytes; /* size of row in bytes */ png_uint_32 iwidth; /* width of current interlaced row in pixels */ png_uint_32 row_number; /* current row in interlace pass */ png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ png_bytep prev_row; /* buffer to save previous (unfiltered) row. * While reading this is a pointer into * big_prev_row; while writing it is separately * allocated if needed. */ png_bytep row_buf; /* buffer to save current (unfiltered) row. * While reading, this is a pointer into * big_row_buf; while writing it is separately * allocated. */ #ifdef PNG_WRITE_FILTER_SUPPORTED png_bytep try_row; /* buffer to save trial row when filtering */ png_bytep tst_row; /* buffer to save best trial row when filtering */ #endif png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ png_uint_32 idat_size; /* current IDAT size for read */ png_uint_32 crc; /* current chunk CRC value */ png_colorp palette; /* palette from the input file */ png_uint_16 num_palette; /* number of color entries in palette */ /* Added at libpng-1.5.10 */ #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED int num_palette_max; /* maximum palette index found in IDAT */ #endif png_uint_16 num_trans; /* number of transparency values */ png_byte compression; /* file compression type (always 0) */ png_byte filter; /* file filter type (always 0) */ png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ png_byte pass; /* current interlace pass (0 - 6) */ png_byte do_filter; /* row filter flags (see PNG_FILTER_ in png.h ) */ png_byte color_type; /* color type of file */ png_byte bit_depth; /* bit depth of file */ png_byte usr_bit_depth; /* bit depth of users row: write only */ png_byte pixel_depth; /* number of bits per pixel */ png_byte channels; /* number of channels in file */ #ifdef PNG_WRITE_SUPPORTED png_byte usr_channels; /* channels at start of write: write only */ #endif png_byte sig_bytes; /* magic bytes read/written from start of file */ png_byte maximum_pixel_depth; /* pixel depth used for the row buffers */ png_byte transformed_pixel_depth; /* pixel depth after read/write transforms */ #if ZLIB_VERNUM >= 0x1240 png_byte zstream_start; /* at start of an input zlib stream */ #endif /* Zlib >= 1.2.4 */ #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) png_uint_16 filler; /* filler bytes for pixel expansion */ #endif #if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ defined(PNG_READ_ALPHA_MODE_SUPPORTED) png_byte background_gamma_type; png_fixed_point background_gamma; png_color_16 background; /* background color in screen gamma space */ #ifdef PNG_READ_GAMMA_SUPPORTED png_color_16 background_1; /* background normalized to gamma 1.0 */ #endif #endif /* bKGD */ #ifdef PNG_WRITE_FLUSH_SUPPORTED png_flush_ptr output_flush_fn; /* Function for flushing output */ png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ png_uint_32 flush_rows; /* number of rows written since last flush */ #endif #ifdef PNG_READ_GAMMA_SUPPORTED int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ png_bytep gamma_table; /* gamma table for 8-bit depth files */ png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) png_bytep gamma_from_1; /* converts from 1.0 to screen */ png_bytep gamma_to_1; /* converts from file to 1.0 */ png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ #endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) png_color_8 sig_bit; /* significant bits in each available channel */ #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) png_color_8 shift; /* shift for significant bit tranformation */ #endif #if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) png_bytep trans_alpha; /* alpha values for paletted files */ png_color_16 trans_color; /* transparent color for non-paletted files */ #endif png_read_status_ptr read_row_fn; /* called after each row is decoded */ png_write_status_ptr write_row_fn; /* called after each row is encoded */ #ifdef PNG_PROGRESSIVE_READ_SUPPORTED png_progressive_info_ptr info_fn; /* called after header data fully read */ png_progressive_row_ptr row_fn; /* called after a prog. row is decoded */ png_progressive_end_ptr end_fn; /* called after image is complete */ png_bytep save_buffer_ptr; /* current location in save_buffer */ png_bytep save_buffer; /* buffer for previously read data */ png_bytep current_buffer_ptr; /* current location in current_buffer */ png_bytep current_buffer; /* buffer for recently used data */ png_uint_32 push_length; /* size of current input chunk */ png_uint_32 skip_length; /* bytes to skip in input data */ png_size_t save_buffer_size; /* amount of data now in save_buffer */ png_size_t save_buffer_max; /* total size of save_buffer */ png_size_t buffer_size; /* total amount of available input data */ png_size_t current_buffer_size; /* amount of data now in current_buffer */ int process_mode; /* what push library is currently doing */ int cur_palette; /* current push library palette index */ #endif /* PROGRESSIVE_READ */ #if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) /* For the Borland special 64K segment handler */ png_bytepp offset_table_ptr; png_bytep offset_table; png_uint_16 offset_table_number; png_uint_16 offset_table_count; png_uint_16 offset_table_count_free; #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED png_bytep palette_lookup; /* lookup table for quantizing */ png_bytep quantize_index; /* index translation for palette files */ #endif /* Options */ #ifdef PNG_SET_OPTION_SUPPORTED png_uint_32 options; /* On/off state (up to 16 options) */ #endif #if PNG_LIBPNG_VER < 10700 /* To do: remove this from libpng-1.7 */ #ifdef PNG_TIME_RFC1123_SUPPORTED char time_buffer[29]; /* String to hold RFC 1123 time text */ #endif #endif /* New members added in libpng-1.0.6 */ png_uint_32 free_me; /* flags items libpng is responsible for freeing */ #ifdef PNG_USER_CHUNKS_SUPPORTED png_voidp user_chunk_ptr; #ifdef PNG_READ_USER_CHUNKS_SUPPORTED png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ #endif #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED int unknown_default; /* As PNG_HANDLE_* */ unsigned int num_chunk_list; /* Number of entries in the list */ png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name * followed by a PNG_HANDLE_* byte */ #endif /* New members added in libpng-1.0.3 */ #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED png_byte rgb_to_gray_status; /* Added in libpng 1.5.5 to record setting of coefficients: */ png_byte rgb_to_gray_coefficients_set; /* These were changed from png_byte in libpng-1.0.6 */ png_uint_16 rgb_to_gray_red_coeff; png_uint_16 rgb_to_gray_green_coeff; /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ #endif /* New member added in libpng-1.0.4 (renamed in 1.0.9) */ #if defined(PNG_MNG_FEATURES_SUPPORTED) /* Changed from png_byte to png_uint_32 at version 1.2.0 */ png_uint_32 mng_features_permitted; #endif /* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */ #ifdef PNG_MNG_FEATURES_SUPPORTED png_byte filter_type; #endif /* New members added in libpng-1.2.0 */ /* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */ #ifdef PNG_USER_MEM_SUPPORTED png_voidp mem_ptr; /* user supplied struct for mem functions */ png_malloc_ptr malloc_fn; /* function for allocating memory */ png_free_ptr free_fn; /* function for freeing memory */ #endif /* New member added in libpng-1.0.13 and 1.2.0 */ png_bytep big_row_buf; /* buffer to save current (unfiltered) row */ #ifdef PNG_READ_QUANTIZE_SUPPORTED /* The following three members were added at version 1.0.14 and 1.2.4 */ png_bytep quantize_sort; /* working sort array */ png_bytep index_to_palette; /* where the original index currently is in the palette */ png_bytep palette_to_index; /* which original index points to this palette color */ #endif /* New members added in libpng-1.0.16 and 1.2.6 */ png_byte compression_type; #ifdef PNG_USER_LIMITS_SUPPORTED png_uint_32 user_width_max; png_uint_32 user_height_max; /* Added in libpng-1.4.0: Total number of sPLT, text, and unknown * chunks that can be stored (0 means unlimited). */ png_uint_32 user_chunk_cache_max; /* Total memory that a zTXt, sPLT, iTXt, iCCP, or unknown chunk * can occupy when decompressed. 0 means unlimited. */ png_alloc_size_t user_chunk_malloc_max; #endif /* New member added in libpng-1.0.25 and 1.2.17 */ #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED /* Temporary storage for unknown chunk that the library doesn't recognize, * used while reading the chunk. */ png_unknown_chunk unknown_chunk; #endif /* New member added in libpng-1.2.26 */ png_size_t old_big_row_buf_size; #ifdef PNG_READ_SUPPORTED /* New member added in libpng-1.2.30 */ png_bytep read_buffer; /* buffer for reading chunk data */ png_alloc_size_t read_buffer_size; /* current size of the buffer */ #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED uInt IDAT_read_size; /* limit on read buffer size for IDAT */ #endif #ifdef PNG_IO_STATE_SUPPORTED /* New member added in libpng-1.4.0 */ png_uint_32 io_state; #endif /* New member added in libpng-1.5.6 */ png_bytep big_prev_row; /* New member added in libpng-1.5.7 */ void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, png_bytep row, png_const_bytep prev_row); #ifdef PNG_READ_SUPPORTED #if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) png_colorspace colorspace; #endif #endif }; #endif /* PNGSTRUCT_H */ stella-5.1.1/src/libpng/pngtrans.c000066400000000000000000000613631324334165500170630ustar00rootroot00000000000000 /* pngtrans.c - transforms the data in a row (used by both readers and writers) * * Last changed in libpng 1.6.33 [September 28, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ #include "pngpriv.h" #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Turn on BGR-to-RGB mapping */ void PNGAPI png_set_bgr(png_structrp png_ptr) { png_debug(1, "in png_set_bgr"); if (png_ptr == NULL) return; png_ptr->transformations |= PNG_BGR; } #endif #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Turn on 16-bit byte swapping */ void PNGAPI png_set_swap(png_structrp png_ptr) { png_debug(1, "in png_set_swap"); if (png_ptr == NULL) return; if (png_ptr->bit_depth == 16) png_ptr->transformations |= PNG_SWAP_BYTES; } #endif #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) /* Turn on pixel packing */ void PNGAPI png_set_packing(png_structrp png_ptr) { png_debug(1, "in png_set_packing"); if (png_ptr == NULL) return; if (png_ptr->bit_depth < 8) { png_ptr->transformations |= PNG_PACK; # ifdef PNG_WRITE_SUPPORTED png_ptr->usr_bit_depth = 8; # endif } } #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) /* Turn on packed pixel swapping */ void PNGAPI png_set_packswap(png_structrp png_ptr) { png_debug(1, "in png_set_packswap"); if (png_ptr == NULL) return; if (png_ptr->bit_depth < 8) png_ptr->transformations |= PNG_PACKSWAP; } #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) void PNGAPI png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) { png_debug(1, "in png_set_shift"); if (png_ptr == NULL) return; png_ptr->transformations |= PNG_SHIFT; png_ptr->shift = *true_bits; } #endif #if defined(PNG_READ_INTERLACING_SUPPORTED) || \ defined(PNG_WRITE_INTERLACING_SUPPORTED) int PNGAPI png_set_interlace_handling(png_structrp png_ptr) { png_debug(1, "in png_set_interlace handling"); if (png_ptr != 0 && png_ptr->interlaced != 0) { png_ptr->transformations |= PNG_INTERLACE; return (7); } return (1); } #endif #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) /* Add a filler byte on read, or remove a filler or alpha byte on write. * The filler type has changed in v0.95 to allow future 2-byte fillers * for 48-bit input data, as well as to avoid problems with some compilers * that don't like bytes as parameters. */ void PNGAPI png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) { png_debug(1, "in png_set_filler"); if (png_ptr == NULL) return; /* In libpng 1.6 it is possible to determine whether this is a read or write * operation and therefore to do more checking here for a valid call. */ if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) { # ifdef PNG_READ_FILLER_SUPPORTED /* On read png_set_filler is always valid, regardless of the base PNG * format, because other transformations can give a format where the * filler code can execute (basically an 8 or 16-bit component RGB or G * format.) * * NOTE: usr_channels is not used by the read code! (This has led to * confusion in the past.) The filler is only used in the read code. */ png_ptr->filler = (png_uint_16)filler; # else png_app_error(png_ptr, "png_set_filler not supported on read"); PNG_UNUSED(filler) /* not used in the write case */ return; # endif } else /* write */ { # ifdef PNG_WRITE_FILLER_SUPPORTED /* On write the usr_channels parameter must be set correctly at the * start to record the number of channels in the app-supplied data. */ switch (png_ptr->color_type) { case PNG_COLOR_TYPE_RGB: png_ptr->usr_channels = 4; break; case PNG_COLOR_TYPE_GRAY: if (png_ptr->bit_depth >= 8) { png_ptr->usr_channels = 2; break; } else { /* There simply isn't any code in libpng to strip out bits * from bytes when the components are less than a byte in * size! */ png_app_error(png_ptr, "png_set_filler is invalid for" " low bit depth gray output"); return; } default: png_app_error(png_ptr, "png_set_filler: inappropriate color type"); return; } # else png_app_error(png_ptr, "png_set_filler not supported on write"); return; # endif } /* Here on success - libpng supports the operation, set the transformation * and the flag to say where the filler channel is. */ png_ptr->transformations |= PNG_FILLER; if (filler_loc == PNG_FILLER_AFTER) png_ptr->flags |= PNG_FLAG_FILLER_AFTER; else png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; } /* Added to libpng-1.2.7 */ void PNGAPI png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) { png_debug(1, "in png_set_add_alpha"); if (png_ptr == NULL) return; png_set_filler(png_ptr, filler, filler_loc); /* The above may fail to do anything. */ if ((png_ptr->transformations & PNG_FILLER) != 0) png_ptr->transformations |= PNG_ADD_ALPHA; } #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) void PNGAPI png_set_swap_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_swap_alpha"); if (png_ptr == NULL) return; png_ptr->transformations |= PNG_SWAP_ALPHA; } #endif #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) void PNGAPI png_set_invert_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_invert_alpha"); if (png_ptr == NULL) return; png_ptr->transformations |= PNG_INVERT_ALPHA; } #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) void PNGAPI png_set_invert_mono(png_structrp png_ptr) { png_debug(1, "in png_set_invert_mono"); if (png_ptr == NULL) return; png_ptr->transformations |= PNG_INVERT_MONO; } /* Invert monochrome grayscale data */ void /* PRIVATE */ png_do_invert(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_invert"); /* This test removed from libpng version 1.0.13 and 1.2.0: * if (row_info->bit_depth == 1 && */ if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { png_bytep rp = row; png_size_t i; png_size_t istop = row_info->rowbytes; for (i = 0; i < istop; i++) { *rp = (png_byte)(~(*rp)); rp++; } } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && row_info->bit_depth == 8) { png_bytep rp = row; png_size_t i; png_size_t istop = row_info->rowbytes; for (i = 0; i < istop; i += 2) { *rp = (png_byte)(~(*rp)); rp += 2; } } #ifdef PNG_16BIT_SUPPORTED else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA && row_info->bit_depth == 16) { png_bytep rp = row; png_size_t i; png_size_t istop = row_info->rowbytes; for (i = 0; i < istop; i += 4) { *rp = (png_byte)(~(*rp)); *(rp + 1) = (png_byte)(~(*(rp + 1))); rp += 4; } } #endif } #endif #ifdef PNG_16BIT_SUPPORTED #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Swaps byte order on 16-bit depth images */ void /* PRIVATE */ png_do_swap(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_swap"); if (row_info->bit_depth == 16) { png_bytep rp = row; png_uint_32 i; png_uint_32 istop= row_info->width * row_info->channels; for (i = 0; i < istop; i++, rp += 2) { #ifdef PNG_BUILTIN_BSWAP16_SUPPORTED /* Feature added to libpng-1.6.11 for testing purposes, not * enabled by default. */ *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp); #else png_byte t = *rp; *rp = *(rp + 1); *(rp + 1) = t; #endif } } } #endif #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) static PNG_CONST png_byte onebppswaptable[256] = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF }; static PNG_CONST png_byte twobppswaptable[256] = { 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4, 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8, 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8, 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC, 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC, 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1, 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1, 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5, 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5, 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9, 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9, 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD, 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD, 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2, 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2, 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6, 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6, 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA, 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA, 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE, 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE, 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3, 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3, 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7, 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7, 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB, 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB, 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF, 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF }; static PNG_CONST png_byte fourbppswaptable[256] = { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1, 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2, 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74, 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4, 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5, 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76, 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6, 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7, 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78, 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8, 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79, 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9, 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A, 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA, 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C, 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC, 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D, 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD, 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E, 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE, 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF }; /* Swaps pixel packing order within bytes */ void /* PRIVATE */ png_do_packswap(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_packswap"); if (row_info->bit_depth < 8) { png_bytep rp; png_const_bytep end, table; end = row + row_info->rowbytes; if (row_info->bit_depth == 1) table = onebppswaptable; else if (row_info->bit_depth == 2) table = twobppswaptable; else if (row_info->bit_depth == 4) table = fourbppswaptable; else return; for (rp = row; rp < end; rp++) *rp = table[*rp]; } } #endif /* PACKSWAP || WRITE_PACKSWAP */ #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) /* Remove a channel - this used to be 'png_do_strip_filler' but it used a * somewhat weird combination of flags to determine what to do. All the calls * to png_do_strip_filler are changed in 1.5.2 to call this instead with the * correct arguments. * * The routine isn't general - the channel must be the channel at the start or * end (not in the middle) of each pixel. */ void /* PRIVATE */ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) { png_bytep sp = row; /* source pointer */ png_bytep dp = row; /* destination pointer */ png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */ /* At the start sp will point to the first byte to copy and dp to where * it is copied to. ep always points just beyond the end of the row, so * the loop simply copies (channels-1) channels until sp reaches ep. * * at_start: 0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc. * nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc. */ /* GA, GX, XG cases */ if (row_info->channels == 2) { if (row_info->bit_depth == 8) { if (at_start != 0) /* Skip initial filler */ ++sp; else /* Skip initial channel and, for sp, the filler */ { sp += 2; ++dp; } /* For a 1 pixel wide image there is nothing to do */ while (sp < ep) { *dp++ = *sp; sp += 2; } row_info->pixel_depth = 8; } else if (row_info->bit_depth == 16) { if (at_start != 0) /* Skip initial filler */ sp += 2; else /* Skip initial channel and, for sp, the filler */ { sp += 4; dp += 2; } while (sp < ep) { *dp++ = *sp++; *dp++ = *sp; sp += 3; } row_info->pixel_depth = 16; } else return; /* bad bit depth */ row_info->channels = 1; /* Finally fix the color type if it records an alpha channel */ if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) row_info->color_type = PNG_COLOR_TYPE_GRAY; } /* RGBA, RGBX, XRGB cases */ else if (row_info->channels == 4) { if (row_info->bit_depth == 8) { if (at_start != 0) /* Skip initial filler */ ++sp; else /* Skip initial channels and, for sp, the filler */ { sp += 4; dp += 3; } /* Note that the loop adds 3 to dp and 4 to sp each time. */ while (sp < ep) { *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp; sp += 2; } row_info->pixel_depth = 24; } else if (row_info->bit_depth == 16) { if (at_start != 0) /* Skip initial filler */ sp += 2; else /* Skip initial channels and, for sp, the filler */ { sp += 8; dp += 6; } while (sp < ep) { /* Copy 6 bytes, skip 2 */ *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp; sp += 3; } row_info->pixel_depth = 48; } else return; /* bad bit depth */ row_info->channels = 3; /* Finally fix the color type if it records an alpha channel */ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) row_info->color_type = PNG_COLOR_TYPE_RGB; } else return; /* The filler channel has gone already */ /* Fix the rowbytes value. */ row_info->rowbytes = (png_size_t)(dp-row); } #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Swaps red and blue bytes within a pixel */ void /* PRIVATE */ png_do_bgr(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_bgr"); if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { png_uint_32 row_width = row_info->width; if (row_info->bit_depth == 8) { if (row_info->color_type == PNG_COLOR_TYPE_RGB) { png_bytep rp; png_uint_32 i; for (i = 0, rp = row; i < row_width; i++, rp += 3) { png_byte save = *rp; *rp = *(rp + 2); *(rp + 2) = save; } } else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_bytep rp; png_uint_32 i; for (i = 0, rp = row; i < row_width; i++, rp += 4) { png_byte save = *rp; *rp = *(rp + 2); *(rp + 2) = save; } } } #ifdef PNG_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { if (row_info->color_type == PNG_COLOR_TYPE_RGB) { png_bytep rp; png_uint_32 i; for (i = 0, rp = row; i < row_width; i++, rp += 6) { png_byte save = *rp; *rp = *(rp + 4); *(rp + 4) = save; save = *(rp + 1); *(rp + 1) = *(rp + 5); *(rp + 5) = save; } } else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { png_bytep rp; png_uint_32 i; for (i = 0, rp = row; i < row_width; i++, rp += 8) { png_byte save = *rp; *rp = *(rp + 4); *(rp + 4) = save; save = *(rp + 1); *(rp + 1) = *(rp + 5); *(rp + 5) = save; } } } #endif } } #endif /* READ_BGR || WRITE_BGR */ #if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) /* Added at libpng-1.5.10 */ void /* PRIVATE */ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) { if (png_ptr->num_palette < (1 << row_info->bit_depth) && png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ { /* Calculations moved outside switch in an attempt to stop different * compiler warnings. 'padding' is in *bits* within the last byte, it is * an 'int' because pixel_depth becomes an 'int' in the expression below, * and this calculation is used because it avoids warnings that other * forms produced on either GCC or MSVC. */ int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width); png_bytep rp = png_ptr->row_buf + row_info->rowbytes - 1; switch (row_info->bit_depth) { case 1: { /* in this case, all bytes must be 0 so we don't need * to unpack the pixels except for the rightmost one. */ for (; rp > png_ptr->row_buf; rp--) { if ((*rp >> padding) != 0) png_ptr->num_palette_max = 1; padding = 0; } break; } case 2: { for (; rp > png_ptr->row_buf; rp--) { int i = ((*rp >> padding) & 0x03); if (i > png_ptr->num_palette_max) png_ptr->num_palette_max = i; i = (((*rp >> padding) >> 2) & 0x03); if (i > png_ptr->num_palette_max) png_ptr->num_palette_max = i; i = (((*rp >> padding) >> 4) & 0x03); if (i > png_ptr->num_palette_max) png_ptr->num_palette_max = i; i = (((*rp >> padding) >> 6) & 0x03); if (i > png_ptr->num_palette_max) png_ptr->num_palette_max = i; padding = 0; } break; } case 4: { for (; rp > png_ptr->row_buf; rp--) { int i = ((*rp >> padding) & 0x0f); if (i > png_ptr->num_palette_max) png_ptr->num_palette_max = i; i = (((*rp >> padding) >> 4) & 0x0f); if (i > png_ptr->num_palette_max) png_ptr->num_palette_max = i; padding = 0; } break; } case 8: { for (; rp > png_ptr->row_buf; rp--) { if (*rp > png_ptr->num_palette_max) png_ptr->num_palette_max = (int) *rp; } break; } default: break; } } } #endif /* CHECK_FOR_INVALID_INDEX */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED void PNGAPI png_set_user_transform_info(png_structrp png_ptr, png_voidp user_transform_ptr, int user_transform_depth, int user_transform_channels) { png_debug(1, "in png_set_user_transform_info"); if (png_ptr == NULL) return; #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) { png_app_error(png_ptr, "info change after png_start_read_image or png_read_update_info"); return; } #endif png_ptr->user_transform_ptr = user_transform_ptr; png_ptr->user_transform_depth = (png_byte)user_transform_depth; png_ptr->user_transform_channels = (png_byte)user_transform_channels; } #endif /* This function returns a pointer to the user_transform_ptr associated with * the user transform functions. The application should free any memory * associated with this pointer before png_write_destroy and png_read_destroy * are called. */ #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED png_voidp PNGAPI png_get_user_transform_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); return png_ptr->user_transform_ptr; } #endif #ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED png_uint_32 PNGAPI png_get_current_row_number(png_const_structrp png_ptr) { /* See the comments in png.h - this is the sub-image row when reading an * interlaced image. */ if (png_ptr != NULL) return png_ptr->row_number; return PNG_UINT_32_MAX; /* help the app not to fail silently */ } png_byte PNGAPI png_get_current_pass_number(png_const_structrp png_ptr) { if (png_ptr != NULL) return png_ptr->pass; return 8; /* invalid */ } #endif /* USER_TRANSFORM_INFO */ #endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */ #endif /* READ || WRITE */ stella-5.1.1/src/libpng/pngwio.c000066400000000000000000000130271324334165500165240ustar00rootroot00000000000000 /* pngwio.c - functions for data output * * Last changed in libpng 1.6.24 [August 4, 2016] * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * * This file provides a location for all output. Users who need * special handling are expected to write functions that have the same * arguments as these and perform similar functions, but that possibly * use different output methods. Note that you shouldn't change these * functions, but rather write replacement functions and then change * them at run time with png_set_write_fn(...). */ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED /* Write the data to whatever output you are using. The default routine * writes to a file pointer. Note that this routine sometimes gets called * with very small lengths, so you should implement some kind of simple * buffering if you are using unbuffered writes. This should never be asked * to write more than 64K on a 16-bit machine. */ void /* PRIVATE */ png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) { /* NOTE: write_data_fn must not change the buffer! */ if (png_ptr->write_data_fn != NULL ) (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), length); else png_error(png_ptr, "Call to NULL write function"); } #ifdef PNG_STDIO_SUPPORTED /* This is the function that does the actual writing of data. If you are * not writing to a standard C stream, you should create a replacement * write_data function and use it at run time with png_set_write_fn(), rather * than changing the library. */ void PNGCBAPI png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { png_size_t check; if (png_ptr == NULL) return; check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); if (check != length) png_error(png_ptr, "Write Error"); } #endif /* This function is called to output any data pending writing (normally * to disk). After png_flush is called, there should be no data pending * writing in any buffers. */ #ifdef PNG_WRITE_FLUSH_SUPPORTED void /* PRIVATE */ png_flush(png_structrp png_ptr) { if (png_ptr->output_flush_fn != NULL) (*(png_ptr->output_flush_fn))(png_ptr); } # ifdef PNG_STDIO_SUPPORTED void PNGCBAPI png_default_flush(png_structp png_ptr) { png_FILE_p io_ptr; if (png_ptr == NULL) return; io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr)); fflush(io_ptr); } # endif #endif /* This function allows the application to supply new output functions for * libpng if standard C streams aren't being used. * * This function takes as its arguments: * png_ptr - pointer to a png output data structure * io_ptr - pointer to user supplied structure containing info about * the output functions. May be NULL. * write_data_fn - pointer to a new output function that takes as its * arguments a pointer to a png_struct, a pointer to * data to be written, and a 32-bit unsigned int that is * the number of bytes to be written. The new write * function should call png_error(png_ptr, "Error msg") * to exit and output any fatal error messages. May be * NULL, in which case libpng's default function will * be used. * flush_data_fn - pointer to a new flush function that takes as its * arguments a pointer to a png_struct. After a call to * the flush function, there should be no data in any buffers * or pending transmission. If the output method doesn't do * any buffering of output, a function prototype must still be * supplied although it doesn't have to do anything. If * PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile * time, output_flush_fn will be ignored, although it must be * supplied for compatibility. May be NULL, in which case * libpng's default function will be used, if * PNG_WRITE_FLUSH_SUPPORTED is defined. This is not * a good idea if io_ptr does not point to a standard * *FILE structure. */ void PNGAPI png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) { if (png_ptr == NULL) return; png_ptr->io_ptr = io_ptr; #ifdef PNG_STDIO_SUPPORTED if (write_data_fn != NULL) png_ptr->write_data_fn = write_data_fn; else png_ptr->write_data_fn = png_default_write_data; #else png_ptr->write_data_fn = write_data_fn; #endif #ifdef PNG_WRITE_FLUSH_SUPPORTED # ifdef PNG_STDIO_SUPPORTED if (output_flush_fn != NULL) png_ptr->output_flush_fn = output_flush_fn; else png_ptr->output_flush_fn = png_default_flush; # else png_ptr->output_flush_fn = output_flush_fn; # endif #else PNG_UNUSED(output_flush_fn) #endif /* WRITE_FLUSH */ #ifdef PNG_READ_SUPPORTED /* It is an error to read while writing a png file */ if (png_ptr->read_data_fn != NULL) { png_ptr->read_data_fn = NULL; png_warning(png_ptr, "Can't set both read_data_fn and write_data_fn in the" " same structure"); } #endif } #endif /* WRITE */ stella-5.1.1/src/libpng/pngwrite.c000066400000000000000000002254211324334165500170630ustar00rootroot00000000000000 /* pngwrite.c - general routines to write a PNG file * * Last changed in libpng 1.6.32 [August 24, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ #include "pngpriv.h" #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED # include #endif /* SIMPLIFIED_WRITE_STDIO */ #ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED /* Write out all the unknown chunks for the current given location */ static void write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, unsigned int where) { if (info_ptr->unknown_chunks_num != 0) { png_const_unknown_chunkp up; png_debug(5, "writing extra chunks"); for (up = info_ptr->unknown_chunks; up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; ++up) if ((up->location & where) != 0) { /* If per-chunk unknown chunk handling is enabled use it, otherwise * just write the chunks the application has set. */ #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED int keep = png_handle_as_unknown(png_ptr, up->name); /* NOTE: this code is radically different from the read side in the * matter of handling an ancillary unknown chunk. In the read side * the default behavior is to discard it, in the code below the default * behavior is to write it. Critical chunks are, however, only * written if explicitly listed or if the default is set to write all * unknown chunks. * * The default handling is also slightly weird - it is not possible to * stop the writing of all unsafe-to-copy chunks! * * TODO: REVIEW: this would seem to be a bug. */ if (keep != PNG_HANDLE_CHUNK_NEVER && ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || keep == PNG_HANDLE_CHUNK_ALWAYS || (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) #endif { /* TODO: review, what is wrong with a zero length unknown chunk? */ if (up->size == 0) png_warning(png_ptr, "Writing zero-length unknown chunk"); png_write_chunk(png_ptr, up->name, up->data, up->size); } } } } #endif /* WRITE_UNKNOWN_CHUNKS */ /* Writes all the PNG information. This is the suggested way to use the * library. If you have a new chunk to add, make a function to write it, * and put it in the correct location here. If you want the chunk written * after the image data, put it in png_write_end(). I strongly encourage * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing * the chunk, as that will keep the code from breaking if you want to just * write a plain PNG file. If you have long comments, I suggest writing * them in png_write_end(), and compressing them. */ void PNGAPI png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) { png_debug(1, "in png_write_info_before_PLTE"); if (png_ptr == NULL || info_ptr == NULL) return; if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) { /* Write PNG signature */ png_write_sig(png_ptr); #ifdef PNG_MNG_FEATURES_SUPPORTED if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \ png_ptr->mng_features_permitted != 0) { png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); png_ptr->mng_features_permitted = 0; } #endif /* Write IHDR information. */ png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, info_ptr->filter_type, #ifdef PNG_WRITE_INTERLACING_SUPPORTED info_ptr->interlace_type #else 0 #endif ); /* The rest of these check to see if the valid field has the appropriate * flag set, and if it does, writes the chunk. * * 1.6.0: COLORSPACE support controls the writing of these chunks too, and * the chunks will be written if the WRITE routine is there and * information * is available in the COLORSPACE. (See * png_colorspace_sync_info in png.c for where the valid flags get set.) * * Under certain circumstances the colorspace can be invalidated without * syncing the info_struct 'valid' flags; this happens if libpng detects * an error and calls png_error while the color space is being set, yet * the application continues writing the PNG. So check the 'invalid' * flag here too. */ #ifdef PNG_GAMMA_SUPPORTED # ifdef PNG_WRITE_gAMA_SUPPORTED if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 && (info_ptr->valid & PNG_INFO_gAMA) != 0) png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); # endif #endif #ifdef PNG_COLORSPACE_SUPPORTED /* Write only one of sRGB or an ICC profile. If a profile was supplied * and it matches one of the known sRGB ones issue a warning. */ # ifdef PNG_WRITE_iCCP_SUPPORTED if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && (info_ptr->valid & PNG_INFO_iCCP) != 0) { # ifdef PNG_WRITE_sRGB_SUPPORTED if ((info_ptr->valid & PNG_INFO_sRGB) != 0) png_app_warning(png_ptr, "profile matches sRGB but writing iCCP instead"); # endif png_write_iCCP(png_ptr, info_ptr->iccp_name, info_ptr->iccp_profile); } # ifdef PNG_WRITE_sRGB_SUPPORTED else # endif # endif # ifdef PNG_WRITE_sRGB_SUPPORTED if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && (info_ptr->valid & PNG_INFO_sRGB) != 0) png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); # endif /* WRITE_sRGB */ #endif /* COLORSPACE */ #ifdef PNG_WRITE_sBIT_SUPPORTED if ((info_ptr->valid & PNG_INFO_sBIT) != 0) png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); #endif #ifdef PNG_COLORSPACE_SUPPORTED # ifdef PNG_WRITE_cHRM_SUPPORTED if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 && (info_ptr->valid & PNG_INFO_cHRM) != 0) png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); # endif #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); #endif png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; } } void PNGAPI png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) { #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) int i; #endif png_debug(1, "in png_write_info"); if (png_ptr == NULL || info_ptr == NULL) return; png_write_info_before_PLTE(png_ptr, info_ptr); if ((info_ptr->valid & PNG_INFO_PLTE) != 0) png_write_PLTE(png_ptr, info_ptr->palette, (png_uint_32)info_ptr->num_palette); else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_error(png_ptr, "Valid palette required for paletted images"); #ifdef PNG_WRITE_tRNS_SUPPORTED if ((info_ptr->valid & PNG_INFO_tRNS) !=0) { #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel (in tRNS) */ if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int j, jend; jend = info_ptr->num_trans; if (jend > PNG_MAX_PALETTE_LENGTH) jend = PNG_MAX_PALETTE_LENGTH; for (j = 0; jtrans_alpha[j] = (png_byte)(255 - info_ptr->trans_alpha[j]); } #endif png_write_tRNS(png_ptr, info_ptr->trans_alpha, &(info_ptr->trans_color), info_ptr->num_trans, info_ptr->color_type); } #endif #ifdef PNG_WRITE_bKGD_SUPPORTED if ((info_ptr->valid & PNG_INFO_bKGD) != 0) png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); #endif #ifdef PNG_WRITE_eXIf_SUPPORTED if ((info_ptr->valid & PNG_INFO_eXIf) != 0) png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif); #endif #ifdef PNG_WRITE_hIST_SUPPORTED if ((info_ptr->valid & PNG_INFO_hIST) != 0) png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED if ((info_ptr->valid & PNG_INFO_oFFs) != 0) png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, info_ptr->offset_unit_type); #endif #ifdef PNG_WRITE_pCAL_SUPPORTED if ((info_ptr->valid & PNG_INFO_pCAL) != 0) png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, info_ptr->pcal_units, info_ptr->pcal_params); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED if ((info_ptr->valid & PNG_INFO_sCAL) != 0) png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, info_ptr->scal_s_width, info_ptr->scal_s_height); #endif /* sCAL */ #ifdef PNG_WRITE_pHYs_SUPPORTED if ((info_ptr->valid & PNG_INFO_pHYs) != 0) png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); #endif /* pHYs */ #ifdef PNG_WRITE_tIME_SUPPORTED if ((info_ptr->valid & PNG_INFO_tIME) != 0) { png_write_tIME(png_ptr, &(info_ptr->mod_time)); png_ptr->mode |= PNG_WROTE_tIME; } #endif /* tIME */ #ifdef PNG_WRITE_sPLT_SUPPORTED if ((info_ptr->valid & PNG_INFO_sPLT) != 0) for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); #endif /* sPLT */ #ifdef PNG_WRITE_TEXT_SUPPORTED /* Check to see if we need to write text chunks */ for (i = 0; i < info_ptr->num_text; i++) { png_debug2(2, "Writing header text chunk %d, type %d", i, info_ptr->text[i].compression); /* An internationalized chunk? */ if (info_ptr->text[i].compression > 0) { #ifdef PNG_WRITE_iTXt_SUPPORTED /* Write international chunk */ png_write_iTXt(png_ptr, info_ptr->text[i].compression, info_ptr->text[i].key, info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); /* Mark this chunk as written */ if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; else info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write international text"); #endif } /* If we want a compressed text chunk */ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt) { #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, info_ptr->text[i].compression); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) { #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else /* Can't get here */ png_warning(png_ptr, "Unable to write uncompressed text"); #endif } } #endif /* tEXt */ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); #endif } /* Writes the end of the PNG file. If you don't want to write comments or * time information, you can pass NULL for info. If you already wrote these * in png_write_info(), do not write them again here. If you have long * comments, I suggest writing them here, and compressing them. */ void PNGAPI png_write_end(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_write_end"); if (png_ptr == NULL) return; if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) png_error(png_ptr, "No IDATs written into file"); #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED if (png_ptr->num_palette_max > png_ptr->num_palette) png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); #endif /* See if user wants us to write information chunks */ if (info_ptr != NULL) { #ifdef PNG_WRITE_TEXT_SUPPORTED int i; /* local index variable */ #endif #ifdef PNG_WRITE_tIME_SUPPORTED /* Check to see if user has supplied a time chunk */ if ((info_ptr->valid & PNG_INFO_tIME) != 0 && (png_ptr->mode & PNG_WROTE_tIME) == 0) png_write_tIME(png_ptr, &(info_ptr->mod_time)); #endif #ifdef PNG_WRITE_TEXT_SUPPORTED /* Loop through comment chunks */ for (i = 0; i < info_ptr->num_text; i++) { png_debug2(2, "Writing trailer text chunk %d, type %d", i, info_ptr->text[i].compression); /* An internationalized chunk? */ if (info_ptr->text[i].compression > 0) { #ifdef PNG_WRITE_iTXt_SUPPORTED /* Write international chunk */ png_write_iTXt(png_ptr, info_ptr->text[i].compression, info_ptr->text[i].key, info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); /* Mark this chunk as written */ if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; else info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write international text"); #endif } else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) { #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, info_ptr->text[i].compression); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) { #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0); /* Mark this chunk as written */ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write uncompressed text"); #endif } } #endif #ifdef PNG_WRITE_eXIf_SUPPORTED if ((info_ptr->valid & PNG_INFO_eXIf) != 0) png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif); #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); #endif } png_ptr->mode |= PNG_AFTER_IDAT; /* Write end of PNG file */ png_write_IEND(png_ptr); /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, * and restored again in libpng-1.2.30, may cause some applications that * do not set png_ptr->output_flush_fn to crash. If your application * experiences a problem, please try building libpng with * PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED defined, and report the event to * png-mng-implement at lists.sf.net . */ #ifdef PNG_WRITE_FLUSH_SUPPORTED # ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED png_flush(png_ptr); # endif #endif } #ifdef PNG_CONVERT_tIME_SUPPORTED void PNGAPI png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) { png_debug(1, "in png_convert_from_struct_tm"); ptime->year = (png_uint_16)(1900 + ttime->tm_year); ptime->month = (png_byte)(ttime->tm_mon + 1); ptime->day = (png_byte)ttime->tm_mday; ptime->hour = (png_byte)ttime->tm_hour; ptime->minute = (png_byte)ttime->tm_min; ptime->second = (png_byte)ttime->tm_sec; } void PNGAPI png_convert_from_time_t(png_timep ptime, time_t ttime) { struct tm *tbuf; png_debug(1, "in png_convert_from_time_t"); tbuf = gmtime(&ttime); png_convert_from_struct_tm(ptime, tbuf); } #endif /* Initialize png_ptr structure, and allocate any memory needed */ PNG_FUNCTION(png_structp,PNGAPI png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) { #ifndef PNG_USER_MEM_SUPPORTED png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, error_fn, warn_fn, NULL, NULL, NULL); #else return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, warn_fn, NULL, NULL, NULL); } /* Alternate initialize png_ptr structure, and allocate any memory needed */ PNG_FUNCTION(png_structp,PNGAPI png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); #endif /* USER_MEM */ if (png_ptr != NULL) { /* Set the zlib control values to defaults; they can be overridden by the * application after the struct has been created. */ png_ptr->zbuffer_size = PNG_ZBUF_SIZE; /* The 'zlib_strategy' setting is irrelevant because png_default_claim in * pngwutil.c defaults it according to whether or not filters will be * used, and ignores this setting. */ png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; png_ptr->zlib_mem_level = 8; png_ptr->zlib_window_bits = 15; png_ptr->zlib_method = 8; #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; png_ptr->zlib_text_mem_level = 8; png_ptr->zlib_text_window_bits = 15; png_ptr->zlib_text_method = 8; #endif /* WRITE_COMPRESSED_TEXT */ /* This is a highly dubious configuration option; by default it is off, * but it may be appropriate for private builds that are testing * extensions not conformant to the current specification, or of * applications that must not fail to write at all costs! */ #ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED /* In stable builds only warn if an application error can be completely * handled. */ png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; #endif /* App warnings are warnings in release (or release candidate) builds but * are errors during development. */ #if PNG_RELEASE_BUILD png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; #endif /* TODO: delay this, it can be done in png_init_io() (if the app doesn't * do it itself) avoiding setting the default function if it is not * required. */ png_set_write_fn(png_ptr, NULL, NULL, NULL); } return png_ptr; } /* Write a few rows of image data. If the image is interlaced, * either you will have to write the 7 sub images, or, if you * have called png_set_interlace_handling(), you will have to * "write" the image seven times. */ void PNGAPI png_write_rows(png_structrp png_ptr, png_bytepp row, png_uint_32 num_rows) { png_uint_32 i; /* row counter */ png_bytepp rp; /* row pointer */ png_debug(1, "in png_write_rows"); if (png_ptr == NULL) return; /* Loop through the rows */ for (i = 0, rp = row; i < num_rows; i++, rp++) { png_write_row(png_ptr, *rp); } } /* Write the image. You only need to call this function once, even * if you are writing an interlaced image. */ void PNGAPI png_write_image(png_structrp png_ptr, png_bytepp image) { png_uint_32 i; /* row index */ int pass, num_pass; /* pass variables */ png_bytepp rp; /* points to current row */ if (png_ptr == NULL) return; png_debug(1, "in png_write_image"); #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Initialize interlace handling. If image is not interlaced, * this will set pass to 1 */ num_pass = png_set_interlace_handling(png_ptr); #else num_pass = 1; #endif /* Loop through passes */ for (pass = 0; pass < num_pass; pass++) { /* Loop through image */ for (i = 0, rp = image; i < png_ptr->height; i++, rp++) { png_write_row(png_ptr, *rp); } } } #ifdef PNG_MNG_FEATURES_SUPPORTED /* Performs intrapixel differencing */ static void png_do_write_intrapixel(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_intrapixel"); if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { int bytes_per_pixel; png_uint_32 row_width = row_info->width; if (row_info->bit_depth == 8) { png_bytep rp; png_uint_32 i; if (row_info->color_type == PNG_COLOR_TYPE_RGB) bytes_per_pixel = 3; else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) bytes_per_pixel = 4; else return; for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { *(rp) = (png_byte)(*rp - *(rp + 1)); *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1)); } } #ifdef PNG_WRITE_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { png_bytep rp; png_uint_32 i; if (row_info->color_type == PNG_COLOR_TYPE_RGB) bytes_per_pixel = 6; else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) bytes_per_pixel = 8; else return; for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1); png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3); png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5); png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); *(rp ) = (png_byte)(red >> 8); *(rp + 1) = (png_byte)red; *(rp + 4) = (png_byte)(blue >> 8); *(rp + 5) = (png_byte)blue; } } #endif /* WRITE_16BIT */ } } #endif /* MNG_FEATURES */ /* Called by user to write a row of image data */ void PNGAPI png_write_row(png_structrp png_ptr, png_const_bytep row) { /* 1.5.6: moved from png_struct to be a local structure: */ png_row_info row_info; if (png_ptr == NULL) return; png_debug2(1, "in png_write_row (row %u, pass %d)", png_ptr->row_number, png_ptr->pass); /* Initialize transformations and other stuff if first time */ if (png_ptr->row_number == 0 && png_ptr->pass == 0) { /* Make sure we wrote the header info */ if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) png_error(png_ptr, "png_write_info was never called before png_write_row"); /* Check for transforms that have been set but were defined out */ #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) if ((png_ptr->transformations & PNG_FILLER) != 0) png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ defined(PNG_READ_PACKSWAP_SUPPORTED) if ((png_ptr->transformations & PNG_PACKSWAP) != 0) png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) if ((png_ptr->transformations & PNG_PACK) != 0) png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) if ((png_ptr->transformations & PNG_SHIFT) != 0) png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) if ((png_ptr->transformations & PNG_BGR) != 0) png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); #endif png_write_start_row(png_ptr); } #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced and not interested in row, return */ if (png_ptr->interlaced != 0 && (png_ptr->transformations & PNG_INTERLACE) != 0) { switch (png_ptr->pass) { case 0: if ((png_ptr->row_number & 0x07) != 0) { png_write_finish_row(png_ptr); return; } break; case 1: if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5) { png_write_finish_row(png_ptr); return; } break; case 2: if ((png_ptr->row_number & 0x07) != 4) { png_write_finish_row(png_ptr); return; } break; case 3: if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3) { png_write_finish_row(png_ptr); return; } break; case 4: if ((png_ptr->row_number & 0x03) != 2) { png_write_finish_row(png_ptr); return; } break; case 5: if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2) { png_write_finish_row(png_ptr); return; } break; case 6: if ((png_ptr->row_number & 0x01) == 0) { png_write_finish_row(png_ptr); return; } break; default: /* error: ignore it */ break; } } #endif /* Set up row info for transformations */ row_info.color_type = png_ptr->color_type; row_info.width = png_ptr->usr_width; row_info.channels = png_ptr->usr_channels; row_info.bit_depth = png_ptr->usr_bit_depth; row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); png_debug1(3, "row_info->color_type = %d", row_info.color_type); png_debug1(3, "row_info->width = %u", row_info.width); png_debug1(3, "row_info->channels = %d", row_info.channels); png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); /* Copy user's row into buffer, leaving room for filter byte. */ memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Handle interlacing */ if (png_ptr->interlaced && png_ptr->pass < 6 && (png_ptr->transformations & PNG_INTERLACE) != 0) { png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); /* This should always get caught above, but still ... */ if (row_info.width == 0) { png_write_finish_row(png_ptr); return; } } #endif #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* Handle other transformations */ if (png_ptr->transformations != 0) png_do_write_transformations(png_ptr, &row_info); #endif /* At this point the row_info pixel depth must match the 'transformed' depth, * which is also the output depth. */ if (row_info.pixel_depth != png_ptr->pixel_depth || row_info.pixel_depth != png_ptr->transformed_pixel_depth) png_error(png_ptr, "internal write transform logic error"); #ifdef PNG_MNG_FEATURES_SUPPORTED /* Write filter_method 64 (intrapixel differencing) only if * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and * 2. Libpng did not write a PNG signature (this filter_method is only * used in PNG datastreams that are embedded in MNG datastreams) and * 3. The application called png_permit_mng_features with a mask that * included PNG_FLAG_MNG_FILTER_64 and * 4. The filter_method is 64 and * 5. The color_type is RGB or RGBA */ if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); } #endif /* Added at libpng-1.5.10 */ #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Check for out-of-range palette index */ if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_palette_max >= 0) png_do_check_palette_indexes(png_ptr, &row_info); #endif /* Find a filter if necessary, filter the row and write it out. */ png_write_find_filter(png_ptr, &row_info); if (png_ptr->write_row_fn != NULL) (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); } #ifdef PNG_WRITE_FLUSH_SUPPORTED /* Set the automatic flush interval or 0 to turn flushing off */ void PNGAPI png_set_flush(png_structrp png_ptr, int nrows) { png_debug(1, "in png_set_flush"); if (png_ptr == NULL) return; png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows); } /* Flush the current output buffers now */ void PNGAPI png_write_flush(png_structrp png_ptr) { png_debug(1, "in png_write_flush"); if (png_ptr == NULL) return; /* We have already written out all of the data */ if (png_ptr->row_number >= png_ptr->num_rows) return; png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); png_ptr->flush_rows = 0; png_flush(png_ptr); } #endif /* WRITE_FLUSH */ /* Free any memory used in png_ptr struct without freeing the struct itself. */ static void png_write_destroy(png_structrp png_ptr) { png_debug(1, "in png_write_destroy"); /* Free any memory zlib uses */ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) deflateEnd(&png_ptr->zstream); /* Free our memory. png_free checks NULL for us. */ png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); png_free(png_ptr, png_ptr->row_buf); png_ptr->row_buf = NULL; #ifdef PNG_WRITE_FILTER_SUPPORTED png_free(png_ptr, png_ptr->prev_row); png_free(png_ptr, png_ptr->try_row); png_free(png_ptr, png_ptr->tst_row); png_ptr->prev_row = NULL; png_ptr->try_row = NULL; png_ptr->tst_row = NULL; #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED png_free(png_ptr, png_ptr->chunk_list); png_ptr->chunk_list = NULL; #endif /* The error handling and memory handling information is left intact at this * point: the jmp_buf may still have to be freed. See png_destroy_png_struct * for how this happens. */ } /* Free all memory used by the write. * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free * the passed in info_structs but it would quietly fail to free any of the data * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it * has no png_ptr.) */ void PNGAPI png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) { png_debug(1, "in png_destroy_write_struct"); if (png_ptr_ptr != NULL) { png_structrp png_ptr = *png_ptr_ptr; if (png_ptr != NULL) /* added in libpng 1.6.0 */ { png_destroy_info_struct(png_ptr, info_ptr_ptr); *png_ptr_ptr = NULL; png_write_destroy(png_ptr); png_destroy_png_struct(png_ptr); } } } /* Allow the application to select one or more row filters to use. */ void PNGAPI png_set_filter(png_structrp png_ptr, int method, int filters) { png_debug(1, "in png_set_filter"); if (png_ptr == NULL) return; #ifdef PNG_MNG_FEATURES_SUPPORTED if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (method == PNG_INTRAPIXEL_DIFFERENCING)) method = PNG_FILTER_TYPE_BASE; #endif if (method == PNG_FILTER_TYPE_BASE) { switch (filters & (PNG_ALL_FILTERS | 0x07)) { #ifdef PNG_WRITE_FILTER_SUPPORTED case 5: case 6: case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); #endif /* WRITE_FILTER */ /* FALLTHROUGH */ case PNG_FILTER_VALUE_NONE: png_ptr->do_filter = PNG_FILTER_NONE; break; #ifdef PNG_WRITE_FILTER_SUPPORTED case PNG_FILTER_VALUE_SUB: png_ptr->do_filter = PNG_FILTER_SUB; break; case PNG_FILTER_VALUE_UP: png_ptr->do_filter = PNG_FILTER_UP; break; case PNG_FILTER_VALUE_AVG: png_ptr->do_filter = PNG_FILTER_AVG; break; case PNG_FILTER_VALUE_PAETH: png_ptr->do_filter = PNG_FILTER_PAETH; break; default: png_ptr->do_filter = (png_byte)filters; break; #else default: png_app_error(png_ptr, "Unknown row filter for method 0"); #endif /* WRITE_FILTER */ } #ifdef PNG_WRITE_FILTER_SUPPORTED /* If we have allocated the row_buf, this means we have already started * with the image and we should have allocated all of the filter buffers * that have been selected. If prev_row isn't already allocated, then * it is too late to start using the filters that need it, since we * will be missing the data in the previous row. If an application * wants to start and stop using particular filters during compression, * it should start out with all of the filters, and then remove them * or add them back after the start of compression. * * NOTE: this is a nasty constraint on the code, because it means that the * prev_row buffer must be maintained even if there are currently no * 'prev_row' requiring filters active. */ if (png_ptr->row_buf != NULL) { int num_filters; png_alloc_size_t buf_size; /* Repeat the checks in png_write_start_row; 1 pixel high or wide * images cannot benefit from certain filters. If this isn't done here * the check below will fire on 1 pixel high images. */ if (png_ptr->height == 1) filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); if (png_ptr->width == 1) filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0 && png_ptr->prev_row == NULL) { /* This is the error case, however it is benign - the previous row * is not available so the filter can't be used. Just warn here. */ png_app_warning(png_ptr, "png_set_filter: UP/AVG/PAETH cannot be added after start"); filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); } num_filters = 0; if (filters & PNG_FILTER_SUB) num_filters++; if (filters & PNG_FILTER_UP) num_filters++; if (filters & PNG_FILTER_AVG) num_filters++; if (filters & PNG_FILTER_PAETH) num_filters++; /* Allocate needed row buffers if they have not already been * allocated. */ buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth, png_ptr->width) + 1; if (png_ptr->try_row == NULL) png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); if (num_filters > 1) { if (png_ptr->tst_row == NULL) png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); } } png_ptr->do_filter = (png_byte)filters; #endif } else png_error(png_ptr, "Unknown custom filter method"); } #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ /* Provide floating and fixed point APIs */ #ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, int num_weights, png_const_doublep filter_weights, png_const_doublep filter_costs) { PNG_UNUSED(png_ptr) PNG_UNUSED(heuristic_method) PNG_UNUSED(num_weights) PNG_UNUSED(filter_weights) PNG_UNUSED(filter_costs) } #endif /* FLOATING_POINT */ #ifdef PNG_FIXED_POINT_SUPPORTED void PNGAPI png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, int num_weights, png_const_fixed_point_p filter_weights, png_const_fixed_point_p filter_costs) { PNG_UNUSED(png_ptr) PNG_UNUSED(heuristic_method) PNG_UNUSED(num_weights) PNG_UNUSED(filter_weights) PNG_UNUSED(filter_costs) } #endif /* FIXED_POINT */ #endif /* WRITE_WEIGHTED_FILTER */ #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED void PNGAPI png_set_compression_level(png_structrp png_ptr, int level) { png_debug(1, "in png_set_compression_level"); if (png_ptr == NULL) return; png_ptr->zlib_level = level; } void PNGAPI png_set_compression_mem_level(png_structrp png_ptr, int mem_level) { png_debug(1, "in png_set_compression_mem_level"); if (png_ptr == NULL) return; png_ptr->zlib_mem_level = mem_level; } void PNGAPI png_set_compression_strategy(png_structrp png_ptr, int strategy) { png_debug(1, "in png_set_compression_strategy"); if (png_ptr == NULL) return; /* The flag setting here prevents the libpng dynamic selection of strategy. */ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; png_ptr->zlib_strategy = strategy; } /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a * smaller value of window_bits if it can do so safely. */ void PNGAPI png_set_compression_window_bits(png_structrp png_ptr, int window_bits) { if (png_ptr == NULL) return; /* Prior to 1.6.0 this would warn but then set the window_bits value. This * meant that negative window bits values could be selected that would cause * libpng to write a non-standard PNG file with raw deflate or gzip * compressed IDAT or ancillary chunks. Such files can be read and there is * no warning on read, so this seems like a very bad idea. */ if (window_bits > 15) { png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); window_bits = 15; } else if (window_bits < 8) { png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); window_bits = 8; } png_ptr->zlib_window_bits = window_bits; } void PNGAPI png_set_compression_method(png_structrp png_ptr, int method) { png_debug(1, "in png_set_compression_method"); if (png_ptr == NULL) return; /* This would produce an invalid PNG file if it worked, but it doesn't and * deflate will fault it, so it is harmless to just warn here. */ if (method != 8) png_warning(png_ptr, "Only compression method 8 is supported by PNG"); png_ptr->zlib_method = method; } #endif /* WRITE_CUSTOMIZE_COMPRESSION */ /* The following were added to libpng-1.5.4 */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED void PNGAPI png_set_text_compression_level(png_structrp png_ptr, int level) { png_debug(1, "in png_set_text_compression_level"); if (png_ptr == NULL) return; png_ptr->zlib_text_level = level; } void PNGAPI png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) { png_debug(1, "in png_set_text_compression_mem_level"); if (png_ptr == NULL) return; png_ptr->zlib_text_mem_level = mem_level; } void PNGAPI png_set_text_compression_strategy(png_structrp png_ptr, int strategy) { png_debug(1, "in png_set_text_compression_strategy"); if (png_ptr == NULL) return; png_ptr->zlib_text_strategy = strategy; } /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a * smaller value of window_bits if it can do so safely. */ void PNGAPI png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) { if (png_ptr == NULL) return; if (window_bits > 15) { png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); window_bits = 15; } else if (window_bits < 8) { png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); window_bits = 8; } png_ptr->zlib_text_window_bits = window_bits; } void PNGAPI png_set_text_compression_method(png_structrp png_ptr, int method) { png_debug(1, "in png_set_text_compression_method"); if (png_ptr == NULL) return; if (method != 8) png_warning(png_ptr, "Only compression method 8 is supported by PNG"); png_ptr->zlib_text_method = method; } #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ /* end of API added to libpng-1.5.4 */ void PNGAPI png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) { if (png_ptr == NULL) return; png_ptr->write_row_fn = write_row_fn; } #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED void PNGAPI png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn) { png_debug(1, "in png_set_write_user_transform_fn"); if (png_ptr == NULL) return; png_ptr->transformations |= PNG_USER_TRANSFORM; png_ptr->write_user_transform_fn = write_user_transform_fn; } #endif #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI png_write_png(png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params) { if (png_ptr == NULL || info_ptr == NULL) return; if ((info_ptr->valid & PNG_INFO_IDAT) == 0) { png_app_error(png_ptr, "no rows for png_write_image to write"); return; } /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* ------ these transformations don't touch the info structure ------- */ /* Invert monochrome pixels */ if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) #ifdef PNG_WRITE_INVERT_SUPPORTED png_set_invert_mono(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif /* Shift the pixels up to a legal bit depth and fill in * as appropriate to correctly scale the image. */ if ((transforms & PNG_TRANSFORM_SHIFT) != 0) #ifdef PNG_WRITE_SHIFT_SUPPORTED if ((info_ptr->valid & PNG_INFO_sBIT) != 0) png_set_shift(png_ptr, &info_ptr->sig_bit); #else png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); #endif /* Pack pixels into bytes */ if ((transforms & PNG_TRANSFORM_PACKING) != 0) #ifdef PNG_WRITE_PACK_SUPPORTED png_set_packing(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); #endif /* Swap location of alpha bytes from ARGB to RGBA */ if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED png_set_swap_alpha(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into * RGB, note that the code expects the input color type to be G or RGB; no * alpha channel. */ if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER| PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0) { #ifdef PNG_WRITE_FILLER_SUPPORTED if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0) { if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported"); /* Continue if ignored - this is the pre-1.6.10 behavior */ png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); } else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); #else png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported"); #endif } /* Flip BGR pixels to RGB */ if ((transforms & PNG_TRANSFORM_BGR) != 0) #ifdef PNG_WRITE_BGR_SUPPORTED png_set_bgr(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif /* Swap bytes of 16-bit files to most significant byte first */ if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) #ifdef PNG_WRITE_SWAP_SUPPORTED png_set_swap(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */ if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) #ifdef PNG_WRITE_PACKSWAP_SUPPORTED png_set_packswap(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif /* Invert the alpha channel from opacity to transparency */ if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED png_set_invert_alpha(png_ptr); #else png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* ----------------------- end of transformations ------------------- */ /* Write the bits */ png_write_image(png_ptr, info_ptr->row_pointers); /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); PNG_UNUSED(params) } #endif #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED /* Initialize the write structure - general purpose utility. */ static int png_image_write_init(png_imagep image) { png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, png_safe_error, png_safe_warning); if (png_ptr != NULL) { png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr != NULL) { png_controlp control = png_voidcast(png_controlp, png_malloc_warn(png_ptr, (sizeof *control))); if (control != NULL) { memset(control, 0, (sizeof *control)); control->png_ptr = png_ptr; control->info_ptr = info_ptr; control->for_write = 1; image->opaque = control; return 1; } /* Error clean up */ png_destroy_info_struct(png_ptr, &info_ptr); } png_destroy_write_struct(&png_ptr, NULL); } return png_image_error(image, "png_image_write_: out of memory"); } /* Arguments to png_image_write_main: */ typedef struct { /* Arguments: */ png_imagep image; png_const_voidp buffer; png_int_32 row_stride; png_const_voidp colormap; int convert_to_8bit; /* Local variables: */ png_const_voidp first_row; ptrdiff_t row_bytes; png_voidp local_row; /* Byte count for memory writing */ png_bytep memory; png_alloc_size_t memory_bytes; /* not used for STDIO */ png_alloc_size_t output_bytes; /* running total */ } png_image_write_control; /* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to * do any necessary byte swapping. The component order is defined by the * png_image format value. */ static int png_write_image_16bit(png_voidp argument) { png_image_write_control *display = png_voidcast(png_image_write_control*, argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, display->first_row); png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); png_uint_16p row_end; const unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; int aindex = 0; png_uint_32 y = image->height; if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) { # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) { aindex = -1; ++input_row; /* To point to the first component */ ++output_row; } else aindex = (int)channels; # else aindex = (int)channels; # endif } else png_error(png_ptr, "png_write_image: internal call error"); /* Work out the output row end and count over this, note that the increment * above to 'row' means that row_end can actually be beyond the end of the * row; this is correct. */ row_end = output_row + image->width * (channels+1); for (; y > 0; --y) { png_const_uint_16p in_ptr = input_row; png_uint_16p out_ptr = output_row; while (out_ptr < row_end) { const png_uint_16 alpha = in_ptr[aindex]; png_uint_32 reciprocal = 0; int c; out_ptr[aindex] = alpha; /* Calculate a reciprocal. The correct calculation is simply * component/alpha*65535 << 15. (I.e. 15 bits of precision); this * allows correct rounding by adding .5 before the shift. 'reciprocal' * is only initialized when required. */ if (alpha > 0 && alpha < 65535) reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; c = (int)channels; do /* always at least one channel */ { png_uint_16 component = *in_ptr++; /* The following gives 65535 for an alpha of 0, which is fine, * otherwise if 0/0 is represented as some other value there is more * likely to be a discontinuity which will probably damage * compression when moving from a fully transparent area to a * nearly transparent one. (The assumption here is that opaque * areas tend not to be 0 intensity.) */ if (component >= alpha) component = 65535; /* component 0 && alpha < 65535) { png_uint_32 calc = component * reciprocal; calc += 16384; /* round to nearest */ component = (png_uint_16)(calc >> 15); } *out_ptr++ = component; } while (--c > 0); /* Skip to next component (skip the intervening alpha channel) */ ++in_ptr; ++out_ptr; } png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); } return 1; } /* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel * is present it must be removed from the components, the components are then * written in sRGB encoding. No components are added or removed. * * Calculate an alpha reciprocal to reverse pre-multiplication. As above the * calculation can be done to 15 bits of accuracy; however, the output needs to * be scaled in the range 0..255*65535, so include that scaling here. */ # define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) static png_byte png_unpremultiply(png_uint_32 component, png_uint_32 alpha, png_uint_32 reciprocal/*from the above macro*/) { /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 * is represented as some other value there is more likely to be a * discontinuity which will probably damage compression when moving from a * fully transparent area to a nearly transparent one. (The assumption here * is that opaque areas tend not to be 0 intensity.) * * There is a rounding problem here; if alpha is less than 128 it will end up * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the * output change for this too. */ if (component >= alpha || alpha < 128) return 255; /* component 0) { /* The test is that alpha/257 (rounded) is less than 255, the first value * that becomes 255 is 65407. * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, * be exact!) [Could also test reciprocal != 0] */ if (alpha < 65407) { component *= reciprocal; component += 64; /* round to nearest */ component >>= 7; } else component *= 255; /* Convert the component to sRGB. */ return (png_byte)PNG_sRGB_FROM_LINEAR(component); } else return 0; } static int png_write_image_8bit(png_voidp argument) { png_image_write_control *display = png_voidcast(png_image_write_control*, argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, display->first_row); png_bytep output_row = png_voidcast(png_bytep, display->local_row); png_uint_32 y = image->height; const unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) { png_bytep row_end; int aindex; # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) { aindex = -1; ++input_row; /* To point to the first component */ ++output_row; } else # endif aindex = (int)channels; /* Use row_end in place of a loop counter: */ row_end = output_row + image->width * (channels+1); for (; y > 0; --y) { png_const_uint_16p in_ptr = input_row; png_bytep out_ptr = output_row; while (out_ptr < row_end) { png_uint_16 alpha = in_ptr[aindex]; png_byte alphabyte = (png_byte)PNG_DIV257(alpha); png_uint_32 reciprocal = 0; int c; /* Scale and write the alpha channel. */ out_ptr[aindex] = alphabyte; if (alphabyte > 0 && alphabyte < 255) reciprocal = UNP_RECIPROCAL(alpha); c = (int)channels; do /* always at least one channel */ *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); while (--c > 0); /* Skip to next component (skip the intervening alpha channel) */ ++in_ptr; ++out_ptr; } /* while out_ptr < row_end */ png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); } /* while y */ } else { /* No alpha channel, so the row_end really is the end of the row and it * is sufficient to loop over the components one by one. */ png_bytep row_end = output_row + image->width * channels; for (; y > 0; --y) { png_const_uint_16p in_ptr = input_row; png_bytep out_ptr = output_row; while (out_ptr < row_end) { png_uint_32 component = *in_ptr++; component *= 255; *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); } png_write_row(png_ptr, output_row); input_row += (png_uint_16)display->row_bytes/(sizeof (png_uint_16)); } } return 1; } static void png_image_set_PLTE(png_image_write_control *display) { const png_imagep image = display->image; const void *cmap = display->colormap; const int entries = image->colormap_entries > 256 ? 256 : (int)image->colormap_entries; /* NOTE: the caller must check for cmap != NULL and entries != 0 */ const png_uint_32 format = image->format; const unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); # if defined(PNG_FORMAT_BGR_SUPPORTED) &&\ defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED) const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0; # else # define afirst 0 # endif # ifdef PNG_FORMAT_BGR_SUPPORTED const int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; # else # define bgr 0 # endif int i, num_trans; png_color palette[256]; png_byte tRNS[256]; memset(tRNS, 255, (sizeof tRNS)); memset(palette, 0, (sizeof palette)); for (i=num_trans=0; i= 3) /* RGB */ { palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * entry[(2 ^ bgr)]); palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * entry[1]); palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * entry[bgr]); } else /* Gray */ palette[i].blue = palette[i].red = palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); } else /* alpha */ { png_uint_16 alpha = entry[afirst ? 0 : channels-1]; png_byte alphabyte = (png_byte)PNG_DIV257(alpha); png_uint_32 reciprocal = 0; /* Calculate a reciprocal, as in the png_write_image_8bit code above * this is designed to produce a value scaled to 255*65535 when * divided by 128 (i.e. asr 7). */ if (alphabyte > 0 && alphabyte < 255) reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; tRNS[i] = alphabyte; if (alphabyte < 255) num_trans = i+1; if (channels >= 3) /* RGB */ { palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], alpha, reciprocal); palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, reciprocal); palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, reciprocal); } else /* gray */ palette[i].blue = palette[i].red = palette[i].green = png_unpremultiply(entry[afirst], alpha, reciprocal); } } else /* Color-map has sRGB values */ { png_const_bytep entry = png_voidcast(png_const_bytep, cmap); entry += (unsigned int)i * channels; switch (channels) { case 4: tRNS[i] = entry[afirst ? 0 : 3]; if (tRNS[i] < 255) num_trans = i+1; /* FALLTHROUGH */ case 3: palette[i].blue = entry[afirst + (2 ^ bgr)]; palette[i].green = entry[afirst + 1]; palette[i].red = entry[afirst + bgr]; break; case 2: tRNS[i] = entry[1 ^ afirst]; if (tRNS[i] < 255) num_trans = i+1; /* FALLTHROUGH */ case 1: palette[i].blue = palette[i].red = palette[i].green = entry[afirst]; break; default: break; } } } # ifdef afirst # undef afirst # endif # ifdef bgr # undef bgr # endif png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, entries); if (num_trans > 0) png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, num_trans, NULL); image->colormap_entries = (png_uint_32)entries; } static int png_image_write_main(png_voidp argument) { png_image_write_control *display = png_voidcast(png_image_write_control*, argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_inforp info_ptr = image->opaque->info_ptr; png_uint_32 format = image->format; /* The following four ints are actually booleans */ int colormap = (format & PNG_FORMAT_FLAG_COLORMAP); int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */ int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA); int write_16bit = linear && (display->convert_to_8bit == 0); # ifdef PNG_BENIGN_ERRORS_SUPPORTED /* Make sure we error out on any bad situation */ png_set_benign_errors(png_ptr, 0/*error*/); # endif /* Default the 'row_stride' parameter if required, also check the row stride * and total image size to ensure that they are within the system limits. */ { const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); if (image->width <= 0x7fffffffU/channels) /* no overflow */ { png_uint_32 check; const png_uint_32 png_row_stride = image->width * channels; if (display->row_stride == 0) display->row_stride = (png_int_32)/*SAFE*/png_row_stride; if (display->row_stride < 0) check = (png_uint_32)(-display->row_stride); else check = (png_uint_32)display->row_stride; if (check >= png_row_stride) { /* Now check for overflow of the image buffer calculation; this * limits the whole image size to 32 bits for API compatibility with * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. */ if (image->height > 0xffffffffU/png_row_stride) png_error(image->opaque->png_ptr, "memory image too large"); } else png_error(image->opaque->png_ptr, "supplied row stride too small"); } else png_error(image->opaque->png_ptr, "image row stride too large"); } /* Set the required transforms then write the rows in the correct order. */ if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) { if (display->colormap != NULL && image->colormap_entries > 0) { png_uint_32 entries = image->colormap_entries; png_set_IHDR(png_ptr, info_ptr, image->width, image->height, entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_image_set_PLTE(display); } else png_error(image->opaque->png_ptr, "no color-map for color-mapped image"); } else png_set_IHDR(png_ptr, info_ptr, image->width, image->height, write_16bit ? 16 : 8, ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Counter-intuitively the data transformations must be called *after* * png_write_info, not before as in the read code, but the 'set' functions * must still be called before. Just set the color space information, never * write an interlaced image. */ if (write_16bit != 0) { /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) png_set_cHRM_fixed(png_ptr, info_ptr, /* color x y */ /* white */ 31270, 32900, /* red */ 64000, 33000, /* green */ 30000, 60000, /* blue */ 15000, 6000 ); } else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit * space must still be gamma encoded. */ else png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); /* Write the file header. */ png_write_info(png_ptr, info_ptr); /* Now set up the data transformations (*after* the header is written), * remove the handled transformations from the 'format' flags for checking. * * First check for a little endian system if writing 16-bit files. */ if (write_16bit != 0) { PNG_CONST png_uint_16 le = 0x0001; if ((*(png_const_bytep) & le) != 0) png_set_swap(png_ptr); } # ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED if ((format & PNG_FORMAT_FLAG_BGR) != 0) { if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0) png_set_bgr(png_ptr); format &= ~PNG_FORMAT_FLAG_BGR; } # endif # ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) { if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0) png_set_swap_alpha(png_ptr); format &= ~PNG_FORMAT_FLAG_AFIRST; } # endif /* If there are 16 or fewer color-map entries we wrote a lower bit depth * above, but the application data is still byte packed. */ if (colormap != 0 && image->colormap_entries <= 16) png_set_packing(png_ptr); /* That should have handled all (both) the transforms. */ if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) png_error(png_ptr, "png_write_image: unsupported transformation"); { png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); ptrdiff_t row_bytes = display->row_stride; if (linear != 0) row_bytes *= (sizeof (png_uint_16)); if (row_bytes < 0) row += (image->height-1) * (-row_bytes); display->first_row = row; display->row_bytes = row_bytes; } /* Apply 'fast' options if the flag is set. */ if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) { png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); /* NOTE: determined by experiment using pngstest, this reflects some * balance between the time to write the image once and the time to read * it about 50 times. The speed-up in pngstest was about 10-20% of the * total (user) time on a heavily loaded system. */ # ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED png_set_compression_level(png_ptr, 3); # endif } /* Check for the cases that currently require a pre-transform on the row * before it is written. This only applies when the input is 16-bit and * either there is an alpha channel or it is converted to 8-bit. */ if ((linear != 0 && alpha != 0 ) || (colormap == 0 && display->convert_to_8bit != 0)) { png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr))); int result; display->local_row = row; if (write_16bit != 0) result = png_safe_execute(image, png_write_image_16bit, display); else result = png_safe_execute(image, png_write_image_8bit, display); display->local_row = NULL; png_free(png_ptr, row); /* Skip the 'write_end' on error: */ if (result == 0) return 0; } /* Otherwise this is the case where the input is in a format currently * supported by the rest of the libpng write code; call it directly. */ else { png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); ptrdiff_t row_bytes = display->row_bytes; png_uint_32 y = image->height; for (; y > 0; --y) { png_write_row(png_ptr, row); row += row_bytes; } } png_write_end(png_ptr, info_ptr); return 1; } static void (PNGCBAPI image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, png_size_t size) { png_image_write_control *display = png_voidcast(png_image_write_control*, png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/); const png_alloc_size_t ob = display->output_bytes; /* Check for overflow; this should never happen: */ if (size <= ((png_alloc_size_t)-1) - ob) { /* I don't think libpng ever does this, but just in case: */ if (size > 0) { if (display->memory_bytes >= ob+size) /* writing */ memcpy(display->memory+ob, data, size); /* Always update the size: */ display->output_bytes = ob+size; } } else png_error(png_ptr, "png_image_write_to_memory: PNG too big"); } static void (PNGCBAPI image_memory_flush)(png_structp png_ptr) { PNG_UNUSED(png_ptr) } static int png_image_write_memory(png_voidp argument) { png_image_write_control *display = png_voidcast(png_image_write_control*, argument); /* The rest of the memory-specific init and write_main in an error protected * environment. This case needs to use callbacks for the write operations * since libpng has no built in support for writing to memory. */ png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/, image_memory_write, image_memory_flush); return png_image_write_main(display); } int PNGAPI png_image_write_to_memory(png_imagep image, void *memory, png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { /* Write the image to the given buffer, or count the bytes if it is NULL */ if (image != NULL && image->version == PNG_IMAGE_VERSION) { if (memory_bytes != NULL && buffer != NULL) { /* This is to give the caller an easier error detection in the NULL * case and guard against uninitialized variable problems: */ if (memory == NULL) *memory_bytes = 0; if (png_image_write_init(image) != 0) { png_image_write_control display; int result; memset(&display, 0, (sizeof display)); display.image = image; display.buffer = buffer; display.row_stride = row_stride; display.colormap = colormap; display.convert_to_8bit = convert_to_8bit; display.memory = png_voidcast(png_bytep, memory); display.memory_bytes = *memory_bytes; display.output_bytes = 0; result = png_safe_execute(image, png_image_write_memory, &display); png_image_free(image); /* write_memory returns true even if we ran out of buffer. */ if (result) { /* On out-of-buffer this function returns '0' but still updates * memory_bytes: */ if (memory != NULL && display.output_bytes > *memory_bytes) result = 0; *memory_bytes = display.output_bytes; } return result; } else return 0; } else return png_image_error(image, "png_image_write_to_memory: invalid argument"); } else if (image != NULL) return png_image_error(image, "png_image_write_to_memory: incorrect PNG_IMAGE_VERSION"); else return 0; } #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED int PNGAPI png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { /* Write the image to the given (FILE*). */ if (image != NULL && image->version == PNG_IMAGE_VERSION) { if (file != NULL && buffer != NULL) { if (png_image_write_init(image) != 0) { png_image_write_control display; int result; /* This is slightly evil, but png_init_io doesn't do anything other * than this and we haven't changed the standard IO functions so * this saves a 'safe' function. */ image->opaque->png_ptr->io_ptr = file; memset(&display, 0, (sizeof display)); display.image = image; display.buffer = buffer; display.row_stride = row_stride; display.colormap = colormap; display.convert_to_8bit = convert_to_8bit; result = png_safe_execute(image, png_image_write_main, &display); png_image_free(image); return result; } else return 0; } else return png_image_error(image, "png_image_write_to_stdio: invalid argument"); } else if (image != NULL) return png_image_error(image, "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); else return 0; } int PNGAPI png_image_write_to_file(png_imagep image, const char *file_name, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) { /* Write the image to the named file. */ if (image != NULL && image->version == PNG_IMAGE_VERSION) { if (file_name != NULL && buffer != NULL) { FILE *fp = fopen(file_name, "wb"); if (fp != NULL) { if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, row_stride, colormap) != 0) { int error; /* from fflush/fclose */ /* Make sure the file is flushed correctly. */ if (fflush(fp) == 0 && ferror(fp) == 0) { if (fclose(fp) == 0) return 1; error = errno; /* from fclose */ } else { error = errno; /* from fflush or ferror */ (void)fclose(fp); } (void)remove(file_name); /* The image has already been cleaned up; this is just used to * set the error (because the original write succeeded). */ return png_image_error(image, strerror(error)); } else { /* Clean up: just the opened file. */ (void)fclose(fp); (void)remove(file_name); return 0; } } else return png_image_error(image, strerror(errno)); } else return png_image_error(image, "png_image_write_to_file: invalid argument"); } else if (image != NULL) return png_image_error(image, "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); else return 0; } #endif /* SIMPLIFIED_WRITE_STDIO */ #endif /* SIMPLIFIED_WRITE */ #endif /* WRITE */ stella-5.1.1/src/libpng/pngwtran.c000066400000000000000000000360521324334165500170640ustar00rootroot00000000000000 /* pngwtran.c - transforms the data in a row for PNG writers * * Last changed in libpng 1.6.26 [October 20, 2016] * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED #ifdef PNG_WRITE_PACK_SUPPORTED /* Pack pixels into bytes. Pass the true bit depth in bit_depth. The * row_info bit depth should be 8 (one pixel per byte). The channels * should be 1 (this only happens on grayscale and paletted images). */ static void png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) { png_debug(1, "in png_do_pack"); if (row_info->bit_depth == 8 && row_info->channels == 1) { switch ((int)bit_depth) { case 1: { png_bytep sp, dp; int mask, v; png_uint_32 i; png_uint_32 row_width = row_info->width; sp = row; dp = row; mask = 0x80; v = 0; for (i = 0; i < row_width; i++) { if (*sp != 0) v |= mask; sp++; if (mask > 1) mask >>= 1; else { mask = 0x80; *dp = (png_byte)v; dp++; v = 0; } } if (mask != 0x80) *dp = (png_byte)v; break; } case 2: { png_bytep sp, dp; unsigned int shift; int v; png_uint_32 i; png_uint_32 row_width = row_info->width; sp = row; dp = row; shift = 6; v = 0; for (i = 0; i < row_width; i++) { png_byte value; value = (png_byte)(*sp & 0x03); v |= (value << shift); if (shift == 0) { shift = 6; *dp = (png_byte)v; dp++; v = 0; } else shift -= 2; sp++; } if (shift != 6) *dp = (png_byte)v; break; } case 4: { png_bytep sp, dp; unsigned int shift; int v; png_uint_32 i; png_uint_32 row_width = row_info->width; sp = row; dp = row; shift = 4; v = 0; for (i = 0; i < row_width; i++) { png_byte value; value = (png_byte)(*sp & 0x0f); v |= (value << shift); if (shift == 0) { shift = 4; *dp = (png_byte)v; dp++; v = 0; } else shift -= 4; sp++; } if (shift != 4) *dp = (png_byte)v; break; } default: break; } row_info->bit_depth = (png_byte)bit_depth; row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels); row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); } } #endif #ifdef PNG_WRITE_SHIFT_SUPPORTED /* Shift pixel values to take advantage of whole range. Pass the * true number of bits in bit_depth. The row should be packed * according to row_info->bit_depth. Thus, if you had a row of * bit depth 4, but the pixels only had values from 0 to 7, you * would pass 3 as bit_depth, and this routine would translate the * data to 0 to 15. */ static void png_do_shift(png_row_infop row_info, png_bytep row, png_const_color_8p bit_depth) { png_debug(1, "in png_do_shift"); if (row_info->color_type != PNG_COLOR_TYPE_PALETTE) { int shift_start[4], shift_dec[4]; unsigned int channels = 0; if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { shift_start[channels] = row_info->bit_depth - bit_depth->red; shift_dec[channels] = bit_depth->red; channels++; shift_start[channels] = row_info->bit_depth - bit_depth->green; shift_dec[channels] = bit_depth->green; channels++; shift_start[channels] = row_info->bit_depth - bit_depth->blue; shift_dec[channels] = bit_depth->blue; channels++; } else { shift_start[channels] = row_info->bit_depth - bit_depth->gray; shift_dec[channels] = bit_depth->gray; channels++; } if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) { shift_start[channels] = row_info->bit_depth - bit_depth->alpha; shift_dec[channels] = bit_depth->alpha; channels++; } /* With low row depths, could only be grayscale, so one channel */ if (row_info->bit_depth < 8) { png_bytep bp = row; png_size_t i; unsigned int mask; png_size_t row_bytes = row_info->rowbytes; if (bit_depth->gray == 1 && row_info->bit_depth == 2) mask = 0x55; else if (row_info->bit_depth == 4 && bit_depth->gray == 3) mask = 0x11; else mask = 0xff; for (i = 0; i < row_bytes; i++, bp++) { int j; unsigned int v, out; v = *bp; out = 0; for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) { if (j > 0) out |= v << j; else out |= (v >> (-j)) & mask; } *bp = (png_byte)(out & 0xff); } } else if (row_info->bit_depth == 8) { png_bytep bp = row; png_uint_32 i; png_uint_32 istop = channels * row_info->width; for (i = 0; i < istop; i++, bp++) { const unsigned int c = i%channels; int j; unsigned int v, out; v = *bp; out = 0; for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) { if (j > 0) out |= v << j; else out |= v >> (-j); } *bp = (png_byte)(out & 0xff); } } else { png_bytep bp; png_uint_32 i; png_uint_32 istop = channels * row_info->width; for (bp = row, i = 0; i < istop; i++) { const unsigned int c = i%channels; int j; unsigned int value, v; v = png_get_uint_16(bp); value = 0; for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) { if (j > 0) value |= v << j; else value |= v >> (-j); } *bp++ = (png_byte)((value >> 8) & 0xff); *bp++ = (png_byte)(value & 0xff); } } } } #endif #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED static void png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_swap_alpha"); { if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { if (row_info->bit_depth == 8) { /* This converts from ARGB to RGBA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; for (i = 0, sp = dp = row; i < row_width; i++) { png_byte save = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = save; } } #ifdef PNG_WRITE_16BIT_SUPPORTED else { /* This converts from AARRGGBB to RRGGBBAA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; for (i = 0, sp = dp = row; i < row_width; i++) { png_byte save[2]; save[0] = *(sp++); save[1] = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = save[0]; *(dp++) = save[1]; } } #endif /* WRITE_16BIT */ } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (row_info->bit_depth == 8) { /* This converts from AG to GA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; for (i = 0, sp = dp = row; i < row_width; i++) { png_byte save = *(sp++); *(dp++) = *(sp++); *(dp++) = save; } } #ifdef PNG_WRITE_16BIT_SUPPORTED else { /* This converts from AAGG to GGAA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; for (i = 0, sp = dp = row; i < row_width; i++) { png_byte save[2]; save[0] = *(sp++); save[1] = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = save[0]; *(dp++) = save[1]; } } #endif /* WRITE_16BIT */ } } } #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED static void png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_invert_alpha"); { if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { if (row_info->bit_depth == 8) { /* This inverts the alpha channel in RGBA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; for (i = 0, sp = dp = row; i < row_width; i++) { /* Does nothing *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); */ sp+=3; dp = sp; *dp = (png_byte)(255 - *(sp++)); } } #ifdef PNG_WRITE_16BIT_SUPPORTED else { /* This inverts the alpha channel in RRGGBBAA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; for (i = 0, sp = dp = row; i < row_width; i++) { /* Does nothing *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); *(dp++) = *(sp++); */ sp+=6; dp = sp; *(dp++) = (png_byte)(255 - *(sp++)); *dp = (png_byte)(255 - *(sp++)); } } #endif /* WRITE_16BIT */ } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (row_info->bit_depth == 8) { /* This inverts the alpha channel in GA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; for (i = 0, sp = dp = row; i < row_width; i++) { *(dp++) = *(sp++); *(dp++) = (png_byte)(255 - *(sp++)); } } #ifdef PNG_WRITE_16BIT_SUPPORTED else { /* This inverts the alpha channel in GGAA */ png_bytep sp, dp; png_uint_32 i; png_uint_32 row_width = row_info->width; for (i = 0, sp = dp = row; i < row_width; i++) { /* Does nothing *(dp++) = *(sp++); *(dp++) = *(sp++); */ sp+=2; dp = sp; *(dp++) = (png_byte)(255 - *(sp++)); *dp = (png_byte)(255 - *(sp++)); } } #endif /* WRITE_16BIT */ } } } #endif /* Transform the data according to the user's wishes. The order of * transformations is significant. */ void /* PRIVATE */ png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) { png_debug(1, "in png_do_write_transformations"); if (png_ptr == NULL) return; #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) if (png_ptr->write_user_transform_fn != NULL) (*(png_ptr->write_user_transform_fn)) /* User write transform function */ (png_ptr, /* png_ptr */ row_info, /* row_info: */ /* png_uint_32 width; width of row */ /* png_size_t rowbytes; number of bytes in row */ /* png_byte color_type; color type of pixels */ /* png_byte bit_depth; bit depth of samples */ /* png_byte channels; number of channels (1-4) */ /* png_byte pixel_depth; bits per pixel (depth*channels) */ png_ptr->row_buf + 1); /* start of pixel data for row */ #endif #ifdef PNG_WRITE_FILLER_SUPPORTED if ((png_ptr->transformations & PNG_FILLER) != 0) png_do_strip_channel(row_info, png_ptr->row_buf + 1, !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); #endif #ifdef PNG_WRITE_PACKSWAP_SUPPORTED if ((png_ptr->transformations & PNG_PACKSWAP) != 0) png_do_packswap(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_WRITE_PACK_SUPPORTED if ((png_ptr->transformations & PNG_PACK) != 0) png_do_pack(row_info, png_ptr->row_buf + 1, (png_uint_32)png_ptr->bit_depth); #endif #ifdef PNG_WRITE_SWAP_SUPPORTED # ifdef PNG_16BIT_SUPPORTED if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_do_swap(row_info, png_ptr->row_buf + 1); # endif #endif #ifdef PNG_WRITE_SHIFT_SUPPORTED if ((png_ptr->transformations & PNG_SHIFT) != 0) png_do_shift(row_info, png_ptr->row_buf + 1, &(png_ptr->shift)); #endif #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_WRITE_BGR_SUPPORTED if ((png_ptr->transformations & PNG_BGR) != 0) png_do_bgr(row_info, png_ptr->row_buf + 1); #endif #ifdef PNG_WRITE_INVERT_SUPPORTED if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) png_do_invert(row_info, png_ptr->row_buf + 1); #endif } #endif /* WRITE_TRANSFORMS */ #endif /* WRITE */ stella-5.1.1/src/libpng/pngwutil.c000066400000000000000000002362271324334165500171030ustar00rootroot00000000000000 /* pngwutil.c - utilities to write a PNG file * * Last changed in libpng 1.6.32 [August 24, 2017] * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED /* Place a 32-bit number into a buffer in PNG byte order. We work * with unsigned numbers for convenience, although one supported * ancillary chunk uses signed (two's complement) numbers. */ void PNGAPI png_save_uint_32(png_bytep buf, png_uint_32 i) { buf[0] = (png_byte)((i >> 24) & 0xffU); buf[1] = (png_byte)((i >> 16) & 0xffU); buf[2] = (png_byte)((i >> 8) & 0xffU); buf[3] = (png_byte)( i & 0xffU); } /* Place a 16-bit number into a buffer in PNG byte order. * The parameter is declared unsigned int, not png_uint_16, * just to avoid potential problems on pre-ANSI C compilers. */ void PNGAPI png_save_uint_16(png_bytep buf, unsigned int i) { buf[0] = (png_byte)((i >> 8) & 0xffU); buf[1] = (png_byte)( i & 0xffU); } #endif /* Simple function to write the signature. If we have already written * the magic bytes of the signature, or more likely, the PNG stream is * being embedded into another stream and doesn't need its own signature, * we should call png_set_sig_bytes() to tell libpng how many of the * bytes have already been written. */ void PNGAPI png_write_sig(png_structrp png_ptr) { png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; #ifdef PNG_IO_STATE_SUPPORTED /* Inform the I/O callback that the signature is being written */ png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE; #endif /* Write the rest of the 8 byte signature */ png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], (png_size_t)(8 - png_ptr->sig_bytes)); if (png_ptr->sig_bytes < 3) png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; } /* Write the start of a PNG chunk. The type is the chunk type. * The total_length is the sum of the lengths of all the data you will be * passing in png_write_chunk_data(). */ static void png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, png_uint_32 length) { png_byte buf[8]; #if defined(PNG_DEBUG) && (PNG_DEBUG > 0) PNG_CSTRING_FROM_CHUNK(buf, chunk_name); png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length); #endif if (png_ptr == NULL) return; #ifdef PNG_IO_STATE_SUPPORTED /* Inform the I/O callback that the chunk header is being written. * PNG_IO_CHUNK_HDR requires a single I/O call. */ png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR; #endif /* Write the length and the chunk name */ png_save_uint_32(buf, length); png_save_uint_32(buf + 4, chunk_name); png_write_data(png_ptr, buf, 8); /* Put the chunk name into png_ptr->chunk_name */ png_ptr->chunk_name = chunk_name; /* Reset the crc and run it over the chunk name */ png_reset_crc(png_ptr); png_calculate_crc(png_ptr, buf + 4, 4); #ifdef PNG_IO_STATE_SUPPORTED /* Inform the I/O callback that chunk data will (possibly) be written. * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. */ png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA; #endif } void PNGAPI png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, png_uint_32 length) { png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length); } /* Write the data of a PNG chunk started with png_write_chunk_header(). * Note that multiple calls to this function are allowed, and that the * sum of the lengths from these calls *must* add up to the total_length * given to png_write_chunk_header(). */ void PNGAPI png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) { /* Write the data, and run the CRC over it */ if (png_ptr == NULL) return; if (data != NULL && length > 0) { png_write_data(png_ptr, data, length); /* Update the CRC after writing the data, * in case the user I/O routine alters it. */ png_calculate_crc(png_ptr, data, length); } } /* Finish a chunk started with png_write_chunk_header(). */ void PNGAPI png_write_chunk_end(png_structrp png_ptr) { png_byte buf[4]; if (png_ptr == NULL) return; #ifdef PNG_IO_STATE_SUPPORTED /* Inform the I/O callback that the chunk CRC is being written. * PNG_IO_CHUNK_CRC requires a single I/O function call. */ png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC; #endif /* Write the crc in a single operation */ png_save_uint_32(buf, png_ptr->crc); png_write_data(png_ptr, buf, (png_size_t)4); } /* Write a PNG chunk all at once. The type is an array of ASCII characters * representing the chunk name. The array must be at least 4 bytes in * length, and does not need to be null terminated. To be safe, pass the * pre-defined chunk names here, and if you need a new one, define it * where the others are defined. The length is the length of the data. * All the data must be present. If that is not possible, use the * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() * functions instead. */ static void png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, png_const_bytep data, png_size_t length) { if (png_ptr == NULL) return; /* On 64-bit architectures 'length' may not fit in a png_uint_32. */ if (length > PNG_UINT_31_MAX) png_error(png_ptr, "length exceeds PNG maximum"); png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); png_write_chunk_data(png_ptr, data, length); png_write_chunk_end(png_ptr); } /* This is the API that calls the internal function above. */ void PNGAPI png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, png_const_bytep data, png_size_t length) { png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, length); } /* This is used below to find the size of an image to pass to png_deflate_claim, * so it only needs to be accurate if the size is less than 16384 bytes (the * point at which a lower LZ window size can be used.) */ static png_alloc_size_t png_image_size(png_structrp png_ptr) { /* Only return sizes up to the maximum of a png_uint_32; do this by limiting * the width and height used to 15 bits. */ png_uint_32 h = png_ptr->height; if (png_ptr->rowbytes < 32768 && h < 32768) { if (png_ptr->interlaced != 0) { /* Interlacing makes the image larger because of the replication of * both the filter byte and the padding to a byte boundary. */ png_uint_32 w = png_ptr->width; unsigned int pd = png_ptr->pixel_depth; png_alloc_size_t cb_base; int pass; for (cb_base=0, pass=0; pass<=6; ++pass) { png_uint_32 pw = PNG_PASS_COLS(w, pass); if (pw > 0) cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); } return cb_base; } else return (png_ptr->rowbytes+1) * h; } else return 0xffffffffU; } #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED /* This is the code to hack the first two bytes of the deflate stream (the * deflate header) to correct the windowBits value to match the actual data * size. Note that the second argument is the *uncompressed* size but the * first argument is the *compressed* data (and it must be deflate * compressed.) */ static void optimize_cmf(png_bytep data, png_alloc_size_t data_size) { /* Optimize the CMF field in the zlib stream. The resultant zlib stream is * still compliant to the stream specification. */ if (data_size <= 16384) /* else windowBits must be 15 */ { unsigned int z_cmf = data[0]; /* zlib compression method and flags */ if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) { unsigned int z_cinfo; unsigned int half_z_window_size; z_cinfo = z_cmf >> 4; half_z_window_size = 1U << (z_cinfo + 7); if (data_size <= half_z_window_size) /* else no change */ { unsigned int tmp; do { half_z_window_size >>= 1; --z_cinfo; } while (z_cinfo > 0 && data_size <= half_z_window_size); z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); data[0] = (png_byte)z_cmf; tmp = data[1] & 0xe0; tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; data[1] = (png_byte)tmp; } } } } #endif /* WRITE_OPTIMIZE_CMF */ /* Initialize the compressor for the appropriate type of compression. */ static int png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, png_alloc_size_t data_size) { if (png_ptr->zowner != 0) { #if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) char msg[64]; PNG_STRING_FROM_CHUNK(msg, owner); msg[4] = ':'; msg[5] = ' '; PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); /* So the message that results is " using zstream"; this is an * internal error, but is very useful for debugging. i18n requirements * are minimal. */ (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); #endif #if PNG_RELEASE_BUILD png_warning(png_ptr, msg); /* Attempt sane error recovery */ if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */ { png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); return Z_STREAM_ERROR; } png_ptr->zowner = 0; #else png_error(png_ptr, msg); #endif } { int level = png_ptr->zlib_level; int method = png_ptr->zlib_method; int windowBits = png_ptr->zlib_window_bits; int memLevel = png_ptr->zlib_mem_level; int strategy; /* set below */ int ret; /* zlib return code */ if (owner == png_IDAT) { if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0) strategy = png_ptr->zlib_strategy; else if (png_ptr->do_filter != PNG_FILTER_NONE) strategy = PNG_Z_DEFAULT_STRATEGY; else strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY; } else { #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED level = png_ptr->zlib_text_level; method = png_ptr->zlib_text_method; windowBits = png_ptr->zlib_text_window_bits; memLevel = png_ptr->zlib_text_mem_level; strategy = png_ptr->zlib_text_strategy; #else /* If customization is not supported the values all come from the * IDAT values except for the strategy, which is fixed to the * default. (This is the pre-1.6.0 behavior too, although it was * implemented in a very different way.) */ strategy = Z_DEFAULT_STRATEGY; #endif } /* Adjust 'windowBits' down if larger than 'data_size'; to stop this * happening just pass 32768 as the data_size parameter. Notice that zlib * requires an extra 262 bytes in the window in addition to the data to be * able to see the whole of the data, so if data_size+262 takes us to the * next windowBits size we need to fix up the value later. (Because even * though deflate needs the extra window, inflate does not!) */ if (data_size <= 16384) { /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to * work round a Microsoft Visual C misbehavior which, contrary to C-90, * widens the result of the following shift to 64-bits if (and, * apparently, only if) it is used in a test. */ unsigned int half_window_size = 1U << (windowBits-1); while (data_size + 262 <= half_window_size) { half_window_size >>= 1; --windowBits; } } /* Check against the previous initialized values, if any. */ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 && (png_ptr->zlib_set_level != level || png_ptr->zlib_set_method != method || png_ptr->zlib_set_window_bits != windowBits || png_ptr->zlib_set_mem_level != memLevel || png_ptr->zlib_set_strategy != strategy)) { if (deflateEnd(&png_ptr->zstream) != Z_OK) png_warning(png_ptr, "deflateEnd failed (ignored)"); png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED; } /* For safety clear out the input and output pointers (currently zlib * doesn't use them on Init, but it might in the future). */ png_ptr->zstream.next_in = NULL; png_ptr->zstream.avail_in = 0; png_ptr->zstream.next_out = NULL; png_ptr->zstream.avail_out = 0; /* Now initialize if required, setting the new parameters, otherwise just * do a simple reset to the previous parameters. */ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) ret = deflateReset(&png_ptr->zstream); else { ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, memLevel, strategy); if (ret == Z_OK) png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; } /* The return code is from either deflateReset or deflateInit2; they have * pretty much the same set of error codes. */ if (ret == Z_OK) png_ptr->zowner = owner; else png_zstream_error(png_ptr, ret); return ret; } } /* Clean up (or trim) a linked list of compression buffers. */ void /* PRIVATE */ png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) { png_compression_bufferp list = *listp; if (list != NULL) { *listp = NULL; do { png_compression_bufferp next = list->next; png_free(png_ptr, list); list = next; } while (list != NULL); } } #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED /* This pair of functions encapsulates the operation of (a) compressing a * text string, and (b) issuing it later as a series of chunk data writes. * The compression_state structure is shared context for these functions * set up by the caller to allow access to the relevant local variables. * * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size * temporary buffers. From 1.6.0 it is retained in png_struct so that it will * be correctly freed in the event of a write error (previous implementations * just leaked memory.) */ typedef struct { png_const_bytep input; /* The uncompressed input data */ png_alloc_size_t input_len; /* Its length */ png_uint_32 output_len; /* Final compressed length */ png_byte output[1024]; /* First block of output */ } compression_state; static void png_text_compress_init(compression_state *comp, png_const_bytep input, png_alloc_size_t input_len) { comp->input = input; comp->input_len = input_len; comp->output_len = 0; } /* Compress the data in the compression state input */ static int png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, compression_state *comp, png_uint_32 prefix_len) { int ret; /* To find the length of the output it is necessary to first compress the * input. The result is buffered rather than using the two-pass algorithm * that is used on the inflate side; deflate is assumed to be slower and a * PNG writer is assumed to have more memory available than a PNG reader. * * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an * upper limit on the output size, but it is always bigger than the input * size so it is likely to be more efficient to use this linked-list * approach. */ ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len); if (ret != Z_OK) return ret; /* Set up the compression buffers, we need a loop here to avoid overflowing a * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited * by the output buffer size, so there is no need to check that. Since this * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits * in size. */ { png_compression_bufferp *end = &png_ptr->zbuffer_list; png_alloc_size_t input_len = comp->input_len; /* may be zero! */ png_uint_32 output_len; /* zlib updates these for us: */ png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input); png_ptr->zstream.avail_in = 0; /* Set below */ png_ptr->zstream.next_out = comp->output; png_ptr->zstream.avail_out = (sizeof comp->output); output_len = png_ptr->zstream.avail_out; do { uInt avail_in = ZLIB_IO_MAX; if (avail_in > input_len) avail_in = (uInt)input_len; input_len -= avail_in; png_ptr->zstream.avail_in = avail_in; if (png_ptr->zstream.avail_out == 0) { png_compression_buffer *next; /* Chunk data is limited to 2^31 bytes in length, so the prefix * length must be counted here. */ if (output_len + prefix_len > PNG_UINT_31_MAX) { ret = Z_MEM_ERROR; break; } /* Need a new (malloc'ed) buffer, but there may be one present * already. */ next = *end; if (next == NULL) { next = png_voidcast(png_compression_bufferp, png_malloc_base (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); if (next == NULL) { ret = Z_MEM_ERROR; break; } /* Link in this buffer (so that it will be freed later) */ next->next = NULL; *end = next; } png_ptr->zstream.next_out = next->output; png_ptr->zstream.avail_out = png_ptr->zbuffer_size; output_len += png_ptr->zstream.avail_out; /* Move 'end' to the next buffer pointer. */ end = &next->next; } /* Compress the data */ ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : Z_FINISH); /* Claw back input data that was not consumed (because avail_in is * reset above every time round the loop). */ input_len += png_ptr->zstream.avail_in; png_ptr->zstream.avail_in = 0; /* safety */ } while (ret == Z_OK); /* There may be some space left in the last output buffer. This needs to * be subtracted from output_len. */ output_len -= png_ptr->zstream.avail_out; png_ptr->zstream.avail_out = 0; /* safety */ comp->output_len = output_len; /* Now double check the output length, put in a custom message if it is * too long. Otherwise ensure the z_stream::msg pointer is set to * something. */ if (output_len + prefix_len >= PNG_UINT_31_MAX) { png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long"); ret = Z_MEM_ERROR; } else png_zstream_error(png_ptr, ret); /* Reset zlib for another zTXt/iTXt or image data */ png_ptr->zowner = 0; /* The only success case is Z_STREAM_END, input_len must be 0; if not this * is an internal error. */ if (ret == Z_STREAM_END && input_len == 0) { #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED /* Fix up the deflate header, if required */ optimize_cmf(comp->output, comp->input_len); #endif /* But Z_OK is returned, not Z_STREAM_END; this allows the claim * function above to return Z_STREAM_END on an error (though it never * does in the current versions of zlib.) */ return Z_OK; } else return ret; } } /* Ship the compressed text out via chunk writes */ static void png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) { png_uint_32 output_len = comp->output_len; png_const_bytep output = comp->output; png_uint_32 avail = (sizeof comp->output); png_compression_buffer *next = png_ptr->zbuffer_list; for (;;) { if (avail > output_len) avail = output_len; png_write_chunk_data(png_ptr, output, avail); output_len -= avail; if (output_len == 0 || next == NULL) break; avail = png_ptr->zbuffer_size; output = next->output; next = next->next; } /* This is an internal error; 'next' must have been NULL! */ if (output_len > 0) png_error(png_ptr, "error writing ancillary chunked compressed data"); } #endif /* WRITE_COMPRESSED_TEXT */ /* Write the IHDR chunk, and update the png_struct with the necessary * information. Note that the rest of this code depends upon this * information being correct. */ void /* PRIVATE */ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int compression_type, int filter_type, int interlace_type) { png_byte buf[13]; /* Buffer to store the IHDR info */ int is_invalid_depth; png_debug(1, "in png_write_IHDR"); /* Check that we have valid input data from the application info */ switch (color_type) { case PNG_COLOR_TYPE_GRAY: switch (bit_depth) { case 1: case 2: case 4: case 8: #ifdef PNG_WRITE_16BIT_SUPPORTED case 16: #endif png_ptr->channels = 1; break; default: png_error(png_ptr, "Invalid bit depth for grayscale image"); } break; case PNG_COLOR_TYPE_RGB: is_invalid_depth = (bit_depth != 8); #ifdef PNG_WRITE_16BIT_SUPPORTED is_invalid_depth = (is_invalid_depth && bit_depth != 16); #endif if (is_invalid_depth) png_error(png_ptr, "Invalid bit depth for RGB image"); png_ptr->channels = 3; break; case PNG_COLOR_TYPE_PALETTE: switch (bit_depth) { case 1: case 2: case 4: case 8: png_ptr->channels = 1; break; default: png_error(png_ptr, "Invalid bit depth for paletted image"); } break; case PNG_COLOR_TYPE_GRAY_ALPHA: is_invalid_depth = (bit_depth != 8); #ifdef PNG_WRITE_16BIT_SUPPORTED is_invalid_depth = (is_invalid_depth && bit_depth != 16); #endif if (is_invalid_depth) png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); png_ptr->channels = 2; break; case PNG_COLOR_TYPE_RGB_ALPHA: is_invalid_depth = (bit_depth != 8); #ifdef PNG_WRITE_16BIT_SUPPORTED is_invalid_depth = (is_invalid_depth && bit_depth != 16); #endif if (is_invalid_depth) png_error(png_ptr, "Invalid bit depth for RGBA image"); png_ptr->channels = 4; break; default: png_error(png_ptr, "Invalid image color type specified"); } if (compression_type != PNG_COMPRESSION_TYPE_BASE) { png_warning(png_ptr, "Invalid compression type specified"); compression_type = PNG_COMPRESSION_TYPE_BASE; } /* Write filter_method 64 (intrapixel differencing) only if * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and * 2. Libpng did not write a PNG signature (this filter_method is only * used in PNG datastreams that are embedded in MNG datastreams) and * 3. The application called png_permit_mng_features with a mask that * included PNG_FLAG_MNG_FILTER_64 and * 4. The filter_method is 64 and * 5. The color_type is RGB or RGBA */ if ( #ifdef PNG_MNG_FEATURES_SUPPORTED !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) && (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && #endif filter_type != PNG_FILTER_TYPE_BASE) { png_warning(png_ptr, "Invalid filter type specified"); filter_type = PNG_FILTER_TYPE_BASE; } #ifdef PNG_WRITE_INTERLACING_SUPPORTED if (interlace_type != PNG_INTERLACE_NONE && interlace_type != PNG_INTERLACE_ADAM7) { png_warning(png_ptr, "Invalid interlace type specified"); interlace_type = PNG_INTERLACE_ADAM7; } #else interlace_type=PNG_INTERLACE_NONE; #endif /* Save the relevant information */ png_ptr->bit_depth = (png_byte)bit_depth; png_ptr->color_type = (png_byte)color_type; png_ptr->interlaced = (png_byte)interlace_type; #ifdef PNG_MNG_FEATURES_SUPPORTED png_ptr->filter_type = (png_byte)filter_type; #endif png_ptr->compression_type = (png_byte)compression_type; png_ptr->width = width; png_ptr->height = height; png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels); png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width); /* Set the usr info, so any transformations can modify it */ png_ptr->usr_width = png_ptr->width; png_ptr->usr_bit_depth = png_ptr->bit_depth; png_ptr->usr_channels = png_ptr->channels; /* Pack the header information into the buffer */ png_save_uint_32(buf, width); png_save_uint_32(buf + 4, height); buf[8] = (png_byte)bit_depth; buf[9] = (png_byte)color_type; buf[10] = (png_byte)compression_type; buf[11] = (png_byte)filter_type; buf[12] = (png_byte)interlace_type; /* Write the chunk */ png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); if ((png_ptr->do_filter) == PNG_NO_FILTERS) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || png_ptr->bit_depth < 8) png_ptr->do_filter = PNG_FILTER_NONE; else png_ptr->do_filter = PNG_ALL_FILTERS; } png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ } /* Write the palette. We are careful not to trust png_color to be in the * correct order for PNG, so people can redefine it to any convenient * structure. */ void /* PRIVATE */ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, png_uint_32 num_pal) { png_uint_32 max_palette_length, i; png_const_colorp pal_ptr; png_byte buf[3]; png_debug(1, "in png_write_PLTE"); max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; if (( #ifdef PNG_MNG_FEATURES_SUPPORTED (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 && #endif num_pal == 0) || num_pal > max_palette_length) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { png_error(png_ptr, "Invalid number of colors in palette"); } else { png_warning(png_ptr, "Invalid number of colors in palette"); return; } } if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) { png_warning(png_ptr, "Ignoring request to write a PLTE chunk in grayscale PNG"); return; } png_ptr->num_palette = (png_uint_16)num_pal; png_debug1(3, "num_palette = %d", png_ptr->num_palette); png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); #ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) { buf[0] = pal_ptr->red; buf[1] = pal_ptr->green; buf[2] = pal_ptr->blue; png_write_chunk_data(png_ptr, buf, (png_size_t)3); } #else /* This is a little slower but some buggy compilers need to do this * instead */ pal_ptr=palette; for (i = 0; i < num_pal; i++) { buf[0] = pal_ptr[i].red; buf[1] = pal_ptr[i].green; buf[2] = pal_ptr[i].blue; png_write_chunk_data(png_ptr, buf, (png_size_t)3); } #endif png_write_chunk_end(png_ptr); png_ptr->mode |= PNG_HAVE_PLTE; } /* This is similar to png_text_compress, above, except that it does not require * all of the data at once and, instead of buffering the compressed result, * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out * because it calls the write interface. As a result it does its own error * reporting and does not return an error code. In the event of error it will * just call png_error. The input data length may exceed 32-bits. The 'flush' * parameter is exactly the same as that to deflate, with the following * meanings: * * Z_NO_FLUSH: normal incremental output of compressed data * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up * * The routine manages the acquire and release of the png_ptr->zstream by * checking and (at the end) clearing png_ptr->zowner; it does some sanity * checks on the 'mode' flags while doing this. */ void /* PRIVATE */ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, png_alloc_size_t input_len, int flush) { if (png_ptr->zowner != png_IDAT) { /* First time. Ensure we have a temporary buffer for compression and * trim the buffer list if it has more than one entry to free memory. * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been * created at this point, but the check here is quick and safe. */ if (png_ptr->zbuffer_list == NULL) { png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); png_ptr->zbuffer_list->next = NULL; } else png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); /* It is a terminal error if we can't claim the zstream. */ if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); /* The output state is maintained in png_ptr->zstream, so it must be * initialized here after the claim. */ png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; png_ptr->zstream.avail_out = png_ptr->zbuffer_size; } /* Now loop reading and writing until all the input is consumed or an error * terminates the operation. The _out values are maintained across calls to * this function, but the input must be reset each time. */ png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); png_ptr->zstream.avail_in = 0; /* set below */ for (;;) { int ret; /* INPUT: from the row data */ uInt avail = ZLIB_IO_MAX; if (avail > input_len) avail = (uInt)input_len; /* safe because of the check */ png_ptr->zstream.avail_in = avail; input_len -= avail; ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); /* Include as-yet unconsumed input */ input_len += png_ptr->zstream.avail_in; png_ptr->zstream.avail_in = 0; /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note * that these two zstream fields are preserved across the calls, therefore * there is no need to set these up on entry to the loop. */ if (png_ptr->zstream.avail_out == 0) { png_bytep data = png_ptr->zbuffer_list->output; uInt size = png_ptr->zbuffer_size; /* Write an IDAT containing the data then reset the buffer. The * first IDAT may need deflate header optimization. */ #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) optimize_cmf(data, png_image_size(png_ptr)); #endif if (size > 0) png_write_complete_chunk(png_ptr, png_IDAT, data, size); png_ptr->mode |= PNG_HAVE_IDAT; png_ptr->zstream.next_out = data; png_ptr->zstream.avail_out = size; /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with * the same flush parameter until it has finished output, for NO_FLUSH * it doesn't matter. */ if (ret == Z_OK && flush != Z_NO_FLUSH) continue; } /* The order of these checks doesn't matter much; it just affects which * possible error might be detected if multiple things go wrong at once. */ if (ret == Z_OK) /* most likely return code! */ { /* If all the input has been consumed then just return. If Z_FINISH * was used as the flush parameter something has gone wrong if we get * here. */ if (input_len == 0) { if (flush == Z_FINISH) png_error(png_ptr, "Z_OK on Z_FINISH with output space"); return; } } else if (ret == Z_STREAM_END && flush == Z_FINISH) { /* This is the end of the IDAT data; any pending output must be * flushed. For small PNG files we may still be at the beginning. */ png_bytep data = png_ptr->zbuffer_list->output; uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; #ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) optimize_cmf(data, png_image_size(png_ptr)); #endif if (size > 0) png_write_complete_chunk(png_ptr, png_IDAT, data, size); png_ptr->zstream.avail_out = 0; png_ptr->zstream.next_out = NULL; png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; png_ptr->zowner = 0; /* Release the stream */ return; } else { /* This is an error condition. */ png_zstream_error(png_ptr, ret); png_error(png_ptr, png_ptr->zstream.msg); } } } /* Write an IEND chunk */ void /* PRIVATE */ png_write_IEND(png_structrp png_ptr) { png_debug(1, "in png_write_IEND"); png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); png_ptr->mode |= PNG_HAVE_IEND; } #ifdef PNG_WRITE_gAMA_SUPPORTED /* Write a gAMA chunk */ void /* PRIVATE */ png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) { png_byte buf[4]; png_debug(1, "in png_write_gAMA"); /* file_gamma is saved in 1/100,000ths */ png_save_uint_32(buf, (png_uint_32)file_gamma); png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); } #endif #ifdef PNG_WRITE_sRGB_SUPPORTED /* Write a sRGB chunk */ void /* PRIVATE */ png_write_sRGB(png_structrp png_ptr, int srgb_intent) { png_byte buf[1]; png_debug(1, "in png_write_sRGB"); if (srgb_intent >= PNG_sRGB_INTENT_LAST) png_warning(png_ptr, "Invalid sRGB rendering intent specified"); buf[0]=(png_byte)srgb_intent; png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); } #endif #ifdef PNG_WRITE_iCCP_SUPPORTED /* Write an iCCP chunk */ void /* PRIVATE */ png_write_iCCP(png_structrp png_ptr, png_const_charp name, png_const_bytep profile) { png_uint_32 name_len; png_uint_32 profile_len; png_byte new_name[81]; /* 1 byte for the compression byte */ compression_state comp; png_uint_32 temp; png_debug(1, "in png_write_iCCP"); /* These are all internal problems: the profile should have been checked * before when it was stored. */ if (profile == NULL) png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ profile_len = png_get_uint_32(profile); if (profile_len < 132) png_error(png_ptr, "ICC profile too short"); temp = (png_uint_32) (*(profile+8)); if (temp > 3 && (profile_len & 0x03)) png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); { png_uint_32 embedded_profile_len = png_get_uint_32(profile); if (profile_len != embedded_profile_len) png_error(png_ptr, "Profile length does not match profile"); } name_len = png_check_keyword(png_ptr, name, new_name); if (name_len == 0) png_error(png_ptr, "iCCP: invalid keyword"); new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE; /* Make sure we include the NULL after the name and the compression type */ ++name_len; png_text_compress_init(&comp, profile, profile_len); /* Allow for keyword terminator and compression byte */ if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len); png_write_chunk_data(png_ptr, new_name, name_len); png_write_compressed_data_out(png_ptr, &comp); png_write_chunk_end(png_ptr); } #endif #ifdef PNG_WRITE_sPLT_SUPPORTED /* Write a sPLT chunk */ void /* PRIVATE */ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) { png_uint_32 name_len; png_byte new_name[80]; png_byte entrybuf[10]; png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); png_size_t palette_size = entry_size * (png_size_t)spalette->nentries; png_sPLT_entryp ep; #ifndef PNG_POINTER_INDEXING_SUPPORTED int i; #endif png_debug(1, "in png_write_sPLT"); name_len = png_check_keyword(png_ptr, spalette->name, new_name); if (name_len == 0) png_error(png_ptr, "sPLT: invalid keyword"); /* Make sure we include the NULL after the name */ png_write_chunk_header(png_ptr, png_sPLT, (png_uint_32)(name_len + 2 + palette_size)); png_write_chunk_data(png_ptr, (png_bytep)new_name, (png_size_t)(name_len + 1)); png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1); /* Loop through each palette entry, writing appropriately */ #ifdef PNG_POINTER_INDEXING_SUPPORTED for (ep = spalette->entries; epentries + spalette->nentries; ep++) { if (spalette->depth == 8) { entrybuf[0] = (png_byte)ep->red; entrybuf[1] = (png_byte)ep->green; entrybuf[2] = (png_byte)ep->blue; entrybuf[3] = (png_byte)ep->alpha; png_save_uint_16(entrybuf + 4, ep->frequency); } else { png_save_uint_16(entrybuf + 0, ep->red); png_save_uint_16(entrybuf + 2, ep->green); png_save_uint_16(entrybuf + 4, ep->blue); png_save_uint_16(entrybuf + 6, ep->alpha); png_save_uint_16(entrybuf + 8, ep->frequency); } png_write_chunk_data(png_ptr, entrybuf, entry_size); } #else ep=spalette->entries; for (i = 0; i>spalette->nentries; i++) { if (spalette->depth == 8) { entrybuf[0] = (png_byte)ep[i].red; entrybuf[1] = (png_byte)ep[i].green; entrybuf[2] = (png_byte)ep[i].blue; entrybuf[3] = (png_byte)ep[i].alpha; png_save_uint_16(entrybuf + 4, ep[i].frequency); } else { png_save_uint_16(entrybuf + 0, ep[i].red); png_save_uint_16(entrybuf + 2, ep[i].green); png_save_uint_16(entrybuf + 4, ep[i].blue); png_save_uint_16(entrybuf + 6, ep[i].alpha); png_save_uint_16(entrybuf + 8, ep[i].frequency); } png_write_chunk_data(png_ptr, entrybuf, entry_size); } #endif png_write_chunk_end(png_ptr); } #endif #ifdef PNG_WRITE_sBIT_SUPPORTED /* Write the sBIT chunk */ void /* PRIVATE */ png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) { png_byte buf[4]; png_size_t size; png_debug(1, "in png_write_sBIT"); /* Make sure we don't depend upon the order of PNG_COLOR_8 */ if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { png_byte maxbits; maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 : png_ptr->usr_bit_depth); if (sbit->red == 0 || sbit->red > maxbits || sbit->green == 0 || sbit->green > maxbits || sbit->blue == 0 || sbit->blue > maxbits) { png_warning(png_ptr, "Invalid sBIT depth specified"); return; } buf[0] = sbit->red; buf[1] = sbit->green; buf[2] = sbit->blue; size = 3; } else { if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth) { png_warning(png_ptr, "Invalid sBIT depth specified"); return; } buf[0] = sbit->gray; size = 1; } if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) { if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) { png_warning(png_ptr, "Invalid sBIT depth specified"); return; } buf[size++] = sbit->alpha; } png_write_complete_chunk(png_ptr, png_sBIT, buf, size); } #endif #ifdef PNG_WRITE_cHRM_SUPPORTED /* Write the cHRM chunk */ void /* PRIVATE */ png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy) { png_byte buf[32]; png_debug(1, "in png_write_cHRM"); /* Each value is saved in 1/100,000ths */ png_save_int_32(buf, xy->whitex); png_save_int_32(buf + 4, xy->whitey); png_save_int_32(buf + 8, xy->redx); png_save_int_32(buf + 12, xy->redy); png_save_int_32(buf + 16, xy->greenx); png_save_int_32(buf + 20, xy->greeny); png_save_int_32(buf + 24, xy->bluex); png_save_int_32(buf + 28, xy->bluey); png_write_complete_chunk(png_ptr, png_cHRM, buf, 32); } #endif #ifdef PNG_WRITE_tRNS_SUPPORTED /* Write the tRNS chunk */ void /* PRIVATE */ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, png_const_color_16p tran, int num_trans, int color_type) { png_byte buf[6]; png_debug(1, "in png_write_tRNS"); if (color_type == PNG_COLOR_TYPE_PALETTE) { if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) { png_app_warning(png_ptr, "Invalid number of transparent colors specified"); return; } /* Write the chunk out as it is */ png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, (png_size_t)num_trans); } else if (color_type == PNG_COLOR_TYPE_GRAY) { /* One 16-bit value */ if (tran->gray >= (1 << png_ptr->bit_depth)) { png_app_warning(png_ptr, "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); return; } png_save_uint_16(buf, tran->gray); png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); } else if (color_type == PNG_COLOR_TYPE_RGB) { /* Three 16-bit values */ png_save_uint_16(buf, tran->red); png_save_uint_16(buf + 2, tran->green); png_save_uint_16(buf + 4, tran->blue); #ifdef PNG_WRITE_16BIT_SUPPORTED if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) #else if ((buf[0] | buf[2] | buf[4]) != 0) #endif { png_app_warning(png_ptr, "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); return; } png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); } else { png_app_warning(png_ptr, "Can't write tRNS with an alpha channel"); } } #endif #ifdef PNG_WRITE_bKGD_SUPPORTED /* Write the background chunk */ void /* PRIVATE */ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) { png_byte buf[6]; png_debug(1, "in png_write_bKGD"); if (color_type == PNG_COLOR_TYPE_PALETTE) { if ( #ifdef PNG_MNG_FEATURES_SUPPORTED (png_ptr->num_palette != 0 || (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) && #endif back->index >= png_ptr->num_palette) { png_warning(png_ptr, "Invalid background palette index"); return; } buf[0] = back->index; png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); } else if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { png_save_uint_16(buf, back->red); png_save_uint_16(buf + 2, back->green); png_save_uint_16(buf + 4, back->blue); #ifdef PNG_WRITE_16BIT_SUPPORTED if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) #else if ((buf[0] | buf[2] | buf[4]) != 0) #endif { png_warning(png_ptr, "Ignoring attempt to write 16-bit bKGD chunk " "when bit_depth is 8"); return; } png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); } else { if (back->gray >= (1 << png_ptr->bit_depth)) { png_warning(png_ptr, "Ignoring attempt to write bKGD chunk out-of-range for bit_depth"); return; } png_save_uint_16(buf, back->gray); png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); } } #endif #ifdef PNG_WRITE_eXIf_SUPPORTED /* Write the Exif data */ void /* PRIVATE */ png_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif) { int i; png_byte buf[1]; png_debug(1, "in png_write_eXIf"); png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif)); for (i = 0; i < num_exif; i++) { buf[0] = exif[i]; png_write_chunk_data(png_ptr, buf, (png_size_t)1); } png_write_chunk_end(png_ptr); } #endif #ifdef PNG_WRITE_hIST_SUPPORTED /* Write the histogram */ void /* PRIVATE */ png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) { int i; png_byte buf[3]; png_debug(1, "in png_write_hIST"); if (num_hist > (int)png_ptr->num_palette) { png_debug2(3, "num_hist = %d, num_palette = %d", num_hist, png_ptr->num_palette); png_warning(png_ptr, "Invalid number of histogram entries specified"); return; } png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2)); for (i = 0; i < num_hist; i++) { png_save_uint_16(buf, hist[i]); png_write_chunk_data(png_ptr, buf, (png_size_t)2); } png_write_chunk_end(png_ptr); } #endif #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write a tEXt chunk */ void /* PRIVATE */ png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, png_size_t text_len) { png_uint_32 key_len; png_byte new_key[80]; png_debug(1, "in png_write_tEXt"); key_len = png_check_keyword(png_ptr, key, new_key); if (key_len == 0) png_error(png_ptr, "tEXt: invalid keyword"); if (text == NULL || *text == '\0') text_len = 0; else text_len = strlen(text); if (text_len > PNG_UINT_31_MAX - (key_len+1)) png_error(png_ptr, "tEXt: text too long"); /* Make sure we include the 0 after the key */ png_write_chunk_header(png_ptr, png_tEXt, (png_uint_32)/*checked above*/(key_len + text_len + 1)); /* * We leave it to the application to meet PNG-1.0 requirements on the * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. */ png_write_chunk_data(png_ptr, new_key, key_len + 1); if (text_len != 0) png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); png_write_chunk_end(png_ptr); } #endif #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write a compressed text chunk */ void /* PRIVATE */ png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, int compression) { png_uint_32 key_len; png_byte new_key[81]; compression_state comp; png_debug(1, "in png_write_zTXt"); if (compression == PNG_TEXT_COMPRESSION_NONE) { png_write_tEXt(png_ptr, key, text, 0); return; } if (compression != PNG_TEXT_COMPRESSION_zTXt) png_error(png_ptr, "zTXt: invalid compression type"); key_len = png_check_keyword(png_ptr, key, new_key); if (key_len == 0) png_error(png_ptr, "zTXt: invalid keyword"); /* Add the compression method and 1 for the keyword separator. */ new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; ++key_len; /* Compute the compressed data; do it now for the length */ png_text_compress_init(&comp, (png_const_bytep)text, text == NULL ? 0 : strlen(text)); if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); /* Write start of chunk */ png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len); /* Write key */ png_write_chunk_data(png_ptr, new_key, key_len); /* Write the compressed data */ png_write_compressed_data_out(png_ptr, &comp); /* Close the chunk */ png_write_chunk_end(png_ptr); } #endif #ifdef PNG_WRITE_iTXt_SUPPORTED /* Write an iTXt chunk */ void /* PRIVATE */ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, png_const_charp lang, png_const_charp lang_key, png_const_charp text) { png_uint_32 key_len, prefix_len; png_size_t lang_len, lang_key_len; png_byte new_key[82]; compression_state comp; png_debug(1, "in png_write_iTXt"); key_len = png_check_keyword(png_ptr, key, new_key); if (key_len == 0) png_error(png_ptr, "iTXt: invalid keyword"); /* Set the compression flag */ switch (compression) { case PNG_ITXT_COMPRESSION_NONE: case PNG_TEXT_COMPRESSION_NONE: compression = new_key[++key_len] = 0; /* no compression */ break; case PNG_TEXT_COMPRESSION_zTXt: case PNG_ITXT_COMPRESSION_zTXt: compression = new_key[++key_len] = 1; /* compressed */ break; default: png_error(png_ptr, "iTXt: invalid compression"); } new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; ++key_len; /* for the keywod separator */ /* We leave it to the application to meet PNG-1.0 requirements on the * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of * any non-Latin-1 characters except for NEWLINE. ISO PNG, however, * specifies that the text is UTF-8 and this really doesn't require any * checking. * * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. * * TODO: validate the language tag correctly (see the spec.) */ if (lang == NULL) lang = ""; /* empty language is valid */ lang_len = strlen(lang)+1; if (lang_key == NULL) lang_key = ""; /* may be empty */ lang_key_len = strlen(lang_key)+1; if (text == NULL) text = ""; /* may be empty */ prefix_len = key_len; if (lang_len > PNG_UINT_31_MAX-prefix_len) prefix_len = PNG_UINT_31_MAX; else prefix_len = (png_uint_32)(prefix_len + lang_len); if (lang_key_len > PNG_UINT_31_MAX-prefix_len) prefix_len = PNG_UINT_31_MAX; else prefix_len = (png_uint_32)(prefix_len + lang_key_len); png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); if (compression != 0) { if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); } else { if (comp.input_len > PNG_UINT_31_MAX-prefix_len) png_error(png_ptr, "iTXt: uncompressed text too long"); /* So the string will fit in a chunk: */ comp.output_len = (png_uint_32)/*SAFE*/comp.input_len; } png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len); png_write_chunk_data(png_ptr, new_key, key_len); png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len); png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); if (compression != 0) png_write_compressed_data_out(png_ptr, &comp); else png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len); png_write_chunk_end(png_ptr); } #endif #ifdef PNG_WRITE_oFFs_SUPPORTED /* Write the oFFs chunk */ void /* PRIVATE */ png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, int unit_type) { png_byte buf[9]; png_debug(1, "in png_write_oFFs"); if (unit_type >= PNG_OFFSET_LAST) png_warning(png_ptr, "Unrecognized unit type for oFFs chunk"); png_save_int_32(buf, x_offset); png_save_int_32(buf + 4, y_offset); buf[8] = (png_byte)unit_type; png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); } #endif #ifdef PNG_WRITE_pCAL_SUPPORTED /* Write the pCAL chunk (described in the PNG extensions document) */ void /* PRIVATE */ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params) { png_uint_32 purpose_len; png_size_t units_len, total_len; png_size_tp params_len; png_byte buf[10]; png_byte new_purpose[80]; int i; png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); if (type >= PNG_EQUATION_LAST) png_error(png_ptr, "Unrecognized equation type for pCAL chunk"); purpose_len = png_check_keyword(png_ptr, purpose, new_purpose); if (purpose_len == 0) png_error(png_ptr, "pCAL: invalid keyword"); ++purpose_len; /* terminator */ png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); units_len = strlen(units) + (nparams == 0 ? 0 : 1); png_debug1(3, "pCAL units length = %d", (int)units_len); total_len = purpose_len + units_len + 10; params_len = (png_size_tp)png_malloc(png_ptr, (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (png_size_t)))); /* Find the length of each parameter, making sure we don't count the * null terminator for the last parameter. */ for (i = 0; i < nparams; i++) { params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1); png_debug2(3, "pCAL parameter %d length = %lu", i, (unsigned long)params_len[i]); total_len += params_len[i]; } png_debug1(3, "pCAL total length = %d", (int)total_len); png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len); png_write_chunk_data(png_ptr, new_purpose, purpose_len); png_save_int_32(buf, X0); png_save_int_32(buf + 4, X1); buf[8] = (png_byte)type; buf[9] = (png_byte)nparams; png_write_chunk_data(png_ptr, buf, (png_size_t)10); png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); for (i = 0; i < nparams; i++) { png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]); } png_free(png_ptr, params_len); png_write_chunk_end(png_ptr); } #endif #ifdef PNG_WRITE_sCAL_SUPPORTED /* Write the sCAL chunk */ void /* PRIVATE */ png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, png_const_charp height) { png_byte buf[64]; png_size_t wlen, hlen, total_len; png_debug(1, "in png_write_sCAL_s"); wlen = strlen(width); hlen = strlen(height); total_len = wlen + hlen + 2; if (total_len > 64) { png_warning(png_ptr, "Can't write sCAL (buffer too small)"); return; } buf[0] = (png_byte)unit; memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len); } #endif #ifdef PNG_WRITE_pHYs_SUPPORTED /* Write the pHYs chunk */ void /* PRIVATE */ png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, int unit_type) { png_byte buf[9]; png_debug(1, "in png_write_pHYs"); if (unit_type >= PNG_RESOLUTION_LAST) png_warning(png_ptr, "Unrecognized unit type for pHYs chunk"); png_save_uint_32(buf, x_pixels_per_unit); png_save_uint_32(buf + 4, y_pixels_per_unit); buf[8] = (png_byte)unit_type; png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); } #endif #ifdef PNG_WRITE_tIME_SUPPORTED /* Write the tIME chunk. Use either png_convert_from_struct_tm() * or png_convert_from_time_t(), or fill in the structure yourself. */ void /* PRIVATE */ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) { png_byte buf[7]; png_debug(1, "in png_write_tIME"); if (mod_time->month > 12 || mod_time->month < 1 || mod_time->day > 31 || mod_time->day < 1 || mod_time->hour > 23 || mod_time->second > 60) { png_warning(png_ptr, "Invalid time specified for tIME chunk"); return; } png_save_uint_16(buf, mod_time->year); buf[2] = mod_time->month; buf[3] = mod_time->day; buf[4] = mod_time->hour; buf[5] = mod_time->minute; buf[6] = mod_time->second; png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7); } #endif /* Initializes the row writing capability of libpng */ void /* PRIVATE */ png_write_start_row(png_structrp png_ptr) { #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif png_alloc_size_t buf_size; int usr_pixel_depth; #ifdef PNG_WRITE_FILTER_SUPPORTED png_byte filters; #endif png_debug(1, "in png_write_start_row"); usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1; /* 1.5.6: added to allow checking in the row write code. */ png_ptr->transformed_pixel_depth = png_ptr->pixel_depth; png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; /* Set up row buffer */ png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; #ifdef PNG_WRITE_FILTER_SUPPORTED filters = png_ptr->do_filter; if (png_ptr->height == 1) filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); if (png_ptr->width == 1) filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); if (filters == 0) filters = PNG_FILTER_NONE; png_ptr->do_filter = filters; if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG | PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL) { int num_filters = 0; png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); if (filters & PNG_FILTER_SUB) num_filters++; if (filters & PNG_FILTER_UP) num_filters++; if (filters & PNG_FILTER_AVG) num_filters++; if (filters & PNG_FILTER_PAETH) num_filters++; if (num_filters > 1) png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); } /* We only need to keep the previous row if we are using one of the following * filters. */ if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0) png_ptr->prev_row = png_voidcast(png_bytep, png_calloc(png_ptr, buf_size)); #endif /* WRITE_FILTER */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, we need to set up width and height of pass */ if (png_ptr->interlaced != 0) { if ((png_ptr->transformations & PNG_INTERLACE) == 0) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - png_pass_start[0]) / png_pass_inc[0]; } else { png_ptr->num_rows = png_ptr->height; png_ptr->usr_width = png_ptr->width; } } else #endif { png_ptr->num_rows = png_ptr->height; png_ptr->usr_width = png_ptr->width; } } /* Internal use only. Called when finished processing a row of data. */ void /* PRIVATE */ png_write_finish_row(png_structrp png_ptr) { #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif png_debug(1, "in png_write_finish_row"); /* Next row */ png_ptr->row_number++; /* See if we are done */ if (png_ptr->row_number < png_ptr->num_rows) return; #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, go to next pass */ if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; if ((png_ptr->transformations & PNG_INTERLACE) != 0) { png_ptr->pass++; } else { /* Loop until we find a non-zero width or height pass */ do { png_ptr->pass++; if (png_ptr->pass >= 7) break; png_ptr->usr_width = (png_ptr->width + png_pass_inc[png_ptr->pass] - 1 - png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; png_ptr->num_rows = (png_ptr->height + png_pass_yinc[png_ptr->pass] - 1 - png_pass_ystart[png_ptr->pass]) / png_pass_yinc[png_ptr->pass]; if ((png_ptr->transformations & PNG_INTERLACE) != 0) break; } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); } /* Reset the row above the image for the next pass */ if (png_ptr->pass < 7) { if (png_ptr->prev_row != NULL) memset(png_ptr->prev_row, 0, (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* png_ptr->usr_bit_depth, png_ptr->width)) + 1); return; } } #endif /* If we get here, we've just written the last row, so we need to flush the compressor */ png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH); } #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Pick out the correct pixels for the interlace pass. * The basic idea here is to go through the row with a source * pointer and a destination pointer (sp and dp), and copy the * correct pixels for the pass. As the row gets compacted, * sp will always be >= dp, so we should never overwrite anything. * See the default: case for the easiest code to understand. */ void /* PRIVATE */ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) { /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; png_debug(1, "in png_do_write_interlace"); /* We don't have to do anything on the last pass (6) */ if (pass < 6) { /* Each pixel depth is handled separately */ switch (row_info->pixel_depth) { case 1: { png_bytep sp; png_bytep dp; unsigned int shift; int d; int value; png_uint_32 i; png_uint_32 row_width = row_info->width; dp = row; d = 0; shift = 7; for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { sp = row + (png_size_t)(i >> 3); value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; d |= (value << shift); if (shift == 0) { shift = 7; *dp++ = (png_byte)d; d = 0; } else shift--; } if (shift != 7) *dp = (png_byte)d; break; } case 2: { png_bytep sp; png_bytep dp; unsigned int shift; int d; int value; png_uint_32 i; png_uint_32 row_width = row_info->width; dp = row; shift = 6; d = 0; for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { sp = row + (png_size_t)(i >> 2); value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; d |= (value << shift); if (shift == 0) { shift = 6; *dp++ = (png_byte)d; d = 0; } else shift -= 2; } if (shift != 6) *dp = (png_byte)d; break; } case 4: { png_bytep sp; png_bytep dp; unsigned int shift; int d; int value; png_uint_32 i; png_uint_32 row_width = row_info->width; dp = row; shift = 4; d = 0; for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { sp = row + (png_size_t)(i >> 1); value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; d |= (value << shift); if (shift == 0) { shift = 4; *dp++ = (png_byte)d; d = 0; } else shift -= 4; } if (shift != 4) *dp = (png_byte)d; break; } default: { png_bytep sp; png_bytep dp; png_uint_32 i; png_uint_32 row_width = row_info->width; png_size_t pixel_bytes; /* Start at the beginning */ dp = row; /* Find out how many bytes each pixel takes up */ pixel_bytes = (row_info->pixel_depth >> 3); /* Loop through the row, only looking at the pixels that matter */ for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { /* Find out where the original pixel is */ sp = row + (png_size_t)i * pixel_bytes; /* Move the pixel */ if (dp != sp) memcpy(dp, sp, pixel_bytes); /* Next pixel */ dp += pixel_bytes; } break; } } /* Set new row width */ row_info->width = (row_info->width + png_pass_inc[pass] - 1 - png_pass_start[pass]) / png_pass_inc[pass]; row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); } } #endif /* This filters the row, chooses which filter to use, if it has not already * been specified by the application, and then writes the row out with the * chosen filter. */ static void /* PRIVATE */ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_size_t row_bytes); #ifdef PNG_WRITE_FILTER_SUPPORTED static png_size_t /* PRIVATE */ png_setup_sub_row(png_structrp png_ptr, const png_uint_32 bpp, const png_size_t row_bytes, const png_size_t lmins) { png_bytep rp, dp, lp; png_size_t i; png_size_t sum = 0; unsigned int v; png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB; for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp; i++, rp++, dp++) { v = *dp = *rp; #ifdef PNG_USE_ABS sum += 128 - abs((int)v - 128); #else sum += (v < 128) ? v : 256 - v; #endif } for (lp = png_ptr->row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); #ifdef PNG_USE_ABS sum += 128 - abs((int)v - 128); #else sum += (v < 128) ? v : 256 - v; #endif if (sum > lmins) /* We are already worse, don't continue. */ break; } return (sum); } static void /* PRIVATE */ png_setup_sub_row_only(png_structrp png_ptr, const png_uint_32 bpp, const png_size_t row_bytes) { png_bytep rp, dp, lp; png_size_t i; png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB; for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp; i++, rp++, dp++) { *dp = *rp; } for (lp = png_ptr->row_buf + 1; i < row_bytes; i++, rp++, lp++, dp++) { *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); } } static png_size_t /* PRIVATE */ png_setup_up_row(png_structrp png_ptr, const png_size_t row_bytes, const png_size_t lmins) { png_bytep rp, dp, pp; png_size_t i; png_size_t sum = 0; unsigned int v; png_ptr->try_row[0] = PNG_FILTER_VALUE_UP; for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, pp = png_ptr->prev_row + 1; i < row_bytes; i++, rp++, pp++, dp++) { v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); #ifdef PNG_USE_ABS sum += 128 - abs((int)v - 128); #else sum += (v < 128) ? v : 256 - v; #endif if (sum > lmins) /* We are already worse, don't continue. */ break; } return (sum); } static void /* PRIVATE */ png_setup_up_row_only(png_structrp png_ptr, const png_size_t row_bytes) { png_bytep rp, dp, pp; png_size_t i; png_ptr->try_row[0] = PNG_FILTER_VALUE_UP; for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, pp = png_ptr->prev_row + 1; i < row_bytes; i++, rp++, pp++, dp++) { *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); } } static png_size_t /* PRIVATE */ png_setup_avg_row(png_structrp png_ptr, const png_uint_32 bpp, const png_size_t row_bytes, const png_size_t lmins) { png_bytep rp, dp, pp, lp; png_uint_32 i; png_size_t sum = 0; unsigned int v; png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG; for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, pp = png_ptr->prev_row + 1; i < bpp; i++) { v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); #ifdef PNG_USE_ABS sum += 128 - abs((int)v - 128); #else sum += (v < 128) ? v : 256 - v; #endif } for (lp = png_ptr->row_buf + 1; i < row_bytes; i++) { v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); #ifdef PNG_USE_ABS sum += 128 - abs((int)v - 128); #else sum += (v < 128) ? v : 256 - v; #endif if (sum > lmins) /* We are already worse, don't continue. */ break; } return (sum); } static void /* PRIVATE */ png_setup_avg_row_only(png_structrp png_ptr, const png_uint_32 bpp, const png_size_t row_bytes) { png_bytep rp, dp, pp, lp; png_uint_32 i; png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG; for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, pp = png_ptr->prev_row + 1; i < bpp; i++) { *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); } for (lp = png_ptr->row_buf + 1; i < row_bytes; i++) { *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); } } static png_size_t /* PRIVATE */ png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp, const png_size_t row_bytes, const png_size_t lmins) { png_bytep rp, dp, pp, cp, lp; png_size_t i; png_size_t sum = 0; unsigned int v; png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH; for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, pp = png_ptr->prev_row + 1; i < bpp; i++) { v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); #ifdef PNG_USE_ABS sum += 128 - abs((int)v - 128); #else sum += (v < 128) ? v : 256 - v; #endif } for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes; i++) { int a, b, c, pa, pb, pc, p; b = *pp++; c = *cp++; a = *lp++; p = b - c; pc = a - c; #ifdef PNG_USE_ABS pa = abs(p); pb = abs(pc); pc = abs(p + pc); #else pa = p < 0 ? -p : p; pb = pc < 0 ? -pc : pc; pc = (p + pc) < 0 ? -(p + pc) : p + pc; #endif p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); #ifdef PNG_USE_ABS sum += 128 - abs((int)v - 128); #else sum += (v < 128) ? v : 256 - v; #endif if (sum > lmins) /* We are already worse, don't continue. */ break; } return (sum); } static void /* PRIVATE */ png_setup_paeth_row_only(png_structrp png_ptr, const png_uint_32 bpp, const png_size_t row_bytes) { png_bytep rp, dp, pp, cp, lp; png_size_t i; png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH; for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, pp = png_ptr->prev_row + 1; i < bpp; i++) { *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); } for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes; i++) { int a, b, c, pa, pb, pc, p; b = *pp++; c = *cp++; a = *lp++; p = b - c; pc = a - c; #ifdef PNG_USE_ABS pa = abs(p); pb = abs(pc); pc = abs(p + pc); #else pa = p < 0 ? -p : p; pb = pc < 0 ? -pc : pc; pc = (p + pc) < 0 ? -(p + pc) : p + pc; #endif p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); } } #endif /* WRITE_FILTER */ void /* PRIVATE */ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) { #ifndef PNG_WRITE_FILTER_SUPPORTED png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1); #else unsigned int filter_to_do = png_ptr->do_filter; png_bytep row_buf; png_bytep best_row; png_uint_32 bpp; png_size_t mins; png_size_t row_bytes = row_info->rowbytes; png_debug(1, "in png_write_find_filter"); /* Find out how many bytes offset each pixel is */ bpp = (row_info->pixel_depth + 7) >> 3; row_buf = png_ptr->row_buf; mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the running sum */; /* The prediction method we use is to find which method provides the * smallest value when summing the absolute values of the distances * from zero, using anything >= 128 as negative numbers. This is known * as the "minimum sum of absolute differences" heuristic. Other * heuristics are the "weighted minimum sum of absolute differences" * (experimental and can in theory improve compression), and the "zlib * predictive" method (not implemented yet), which does test compressions * of lines using different filter methods, and then chooses the * (series of) filter(s) that give minimum compressed data size (VERY * computationally expensive). * * GRR 980525: consider also * * (1) minimum sum of absolute differences from running average (i.e., * keep running sum of non-absolute differences & count of bytes) * [track dispersion, too? restart average if dispersion too large?] * * (1b) minimum sum of absolute differences from sliding average, probably * with window size <= deflate window (usually 32K) * * (2) minimum sum of squared differences from zero or running average * (i.e., ~ root-mean-square approach) */ /* We don't need to test the 'no filter' case if this is the only filter * that has been chosen, as it doesn't actually do anything to the data. */ best_row = png_ptr->row_buf; if (PNG_SIZE_MAX/128 <= row_bytes) { /* Overflow can occur in the calculation, just select the lowest set * filter. */ filter_to_do &= 0U-filter_to_do; } else if ((filter_to_do & PNG_FILTER_NONE) != 0 && filter_to_do != PNG_FILTER_NONE) { /* Overflow not possible and multiple filters in the list, including the * 'none' filter. */ png_bytep rp; png_size_t sum = 0; png_size_t i; unsigned int v; { for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) { v = *rp; #ifdef PNG_USE_ABS sum += 128 - abs((int)v - 128); #else sum += (v < 128) ? v : 256 - v; #endif } } mins = sum; } /* Sub filter */ if (filter_to_do == PNG_FILTER_SUB) /* It's the only filter so no testing is needed */ { png_setup_sub_row_only(png_ptr, bpp, row_bytes); best_row = png_ptr->try_row; } else if ((filter_to_do & PNG_FILTER_SUB) != 0) { png_size_t sum; png_size_t lmins = mins; sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins); if (sum < mins) { mins = sum; best_row = png_ptr->try_row; if (png_ptr->tst_row != NULL) { png_ptr->try_row = png_ptr->tst_row; png_ptr->tst_row = best_row; } } } /* Up filter */ if (filter_to_do == PNG_FILTER_UP) { png_setup_up_row_only(png_ptr, row_bytes); best_row = png_ptr->try_row; } else if ((filter_to_do & PNG_FILTER_UP) != 0) { png_size_t sum; png_size_t lmins = mins; sum = png_setup_up_row(png_ptr, row_bytes, lmins); if (sum < mins) { mins = sum; best_row = png_ptr->try_row; if (png_ptr->tst_row != NULL) { png_ptr->try_row = png_ptr->tst_row; png_ptr->tst_row = best_row; } } } /* Avg filter */ if (filter_to_do == PNG_FILTER_AVG) { png_setup_avg_row_only(png_ptr, bpp, row_bytes); best_row = png_ptr->try_row; } else if ((filter_to_do & PNG_FILTER_AVG) != 0) { png_size_t sum; png_size_t lmins = mins; sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins); if (sum < mins) { mins = sum; best_row = png_ptr->try_row; if (png_ptr->tst_row != NULL) { png_ptr->try_row = png_ptr->tst_row; png_ptr->tst_row = best_row; } } } /* Paeth filter */ if (filter_to_do == PNG_FILTER_PAETH) { png_setup_paeth_row_only(png_ptr, bpp, row_bytes); best_row = png_ptr->try_row; } else if ((filter_to_do & PNG_FILTER_PAETH) != 0) { png_size_t sum; png_size_t lmins = mins; sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins); if (sum < mins) { best_row = png_ptr->try_row; if (png_ptr->tst_row != NULL) { png_ptr->try_row = png_ptr->tst_row; png_ptr->tst_row = best_row; } } } /* Do the actual writing of the filtered row data from the chosen filter. */ png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); #endif /* WRITE_FILTER */ } /* Do the actual writing of a previously filtered row. */ static void png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_size_t full_row_length/*includes filter byte*/) { png_debug(1, "in png_write_filtered_row"); png_debug1(2, "filter = %d", filtered_row[0]); png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); #ifdef PNG_WRITE_FILTER_SUPPORTED /* Swap the current and previous rows */ if (png_ptr->prev_row != NULL) { png_bytep tptr; tptr = png_ptr->prev_row; png_ptr->prev_row = png_ptr->row_buf; png_ptr->row_buf = tptr; } #endif /* WRITE_FILTER */ /* Finish row - updates counters and flushes zlib if last row */ png_write_finish_row(png_ptr); #ifdef PNG_WRITE_FLUSH_SUPPORTED png_ptr->flush_rows++; if (png_ptr->flush_dist > 0 && png_ptr->flush_rows >= png_ptr->flush_dist) { png_write_flush(png_ptr); } #endif /* WRITE_FLUSH */ } #endif /* WRITE */ stella-5.1.1/src/macosx/000077500000000000000000000000001324334165500150715ustar00rootroot00000000000000stella-5.1.1/src/macosx/AboutBox.h000066400000000000000000000023231324334165500167650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #import /** AboutBox window class and support functions for the Macintosh OS X SDL port of Stella. @author Mark Grebe */ @interface AboutBox : NSObject { IBOutlet NSTextField *appNameField; IBOutlet NSTextView *creditsField; IBOutlet NSTextField *versionField; NSTimer *scrollTimer; CGFloat currentPosition; CGFloat maxScrollHeight; NSTimeInterval startTime; BOOL restartAtTop; } + (AboutBox *)sharedInstance; - (IBAction)showPanel:(id)sender; - (IBAction)OK:(id)sender; @end stella-5.1.1/src/macosx/AboutBox.m000066400000000000000000000066531324334165500170040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #import "AboutBox.h" @implementation AboutBox static AboutBox *sharedInstance = nil; + (AboutBox *)sharedInstance { return sharedInstance ? sharedInstance : [[self alloc] init]; } - (id)init { if (sharedInstance) [self release]; else sharedInstance = [super init]; return sharedInstance; } /*------------------------------------------------------------------------------ * showPanel - Display the About Box. *-----------------------------------------------------------------------------*/ - (IBAction)showPanel:(id)sender { NSRect creditsBounds; if (!appNameField) { NSWindow *theWindow; NSString *creditsPath; NSAttributedString *creditsString; NSString *appName; NSString *versionString; NSDictionary *infoDictionary; CFBundleRef localInfoBundle; NSDictionary *localInfoDict; if (![NSBundle loadNibNamed:@"AboutBox" owner:self]) { NSLog( @"Failed to load AboutBox.nib" ); NSBeep(); return; } theWindow = [appNameField window]; // Get the info dictionary (Info.plist) infoDictionary = [[NSBundle mainBundle] infoDictionary]; // Get the localized info dictionary (InfoPlist.strings) localInfoBundle = CFBundleGetMainBundle(); localInfoDict = (NSDictionary *) CFBundleGetLocalInfoDictionary( localInfoBundle ); // Setup the app name field appName = @"Stella"; [appNameField setStringValue:appName]; // Set the about box window title [theWindow setTitle:[NSString stringWithFormat:@"About %@", appName]]; // Setup the version field versionString = [infoDictionary objectForKey:@"CFBundleVersion"]; [versionField setStringValue:[NSString stringWithFormat:@"Version %@", versionString]]; // Setup our credits creditsPath = [[NSBundle mainBundle] pathForResource:@"Credits" ofType:@"html"]; creditsString = [[NSAttributedString alloc] initWithPath:creditsPath documentAttributes:nil]; [creditsField replaceCharactersInRange:NSMakeRange( 0, 0 ) withRTF:[creditsString RTFFromRange: NSMakeRange( 0, [creditsString length] ) documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType}]]; // Prepare some scroll info creditsBounds = [creditsField bounds]; maxScrollHeight = creditsBounds.size.height*2.75; // Setup the window [theWindow setExcludedFromWindowsMenu:YES]; [theWindow setMenu:nil]; [theWindow center]; } if (![[appNameField window] isVisible]) { currentPosition = 0; restartAtTop = NO; [creditsField scrollPoint:NSMakePoint( 0, 0 )]; } // Show the window [NSApp runModalForWindow:[appNameField window]]; [[appNameField window] close]; } - (void)OK:(id)sender { [NSApp stopModal]; } @end stella-5.1.1/src/macosx/AboutBox.nib/000077500000000000000000000000001324334165500173635ustar00rootroot00000000000000stella-5.1.1/src/macosx/AboutBox.nib/classes.nib000066400000000000000000000005531324334165500215150ustar00rootroot00000000000000{ IBClasses = ( { ACTIONS = {OK = id; }; CLASS = AboutBox; LANGUAGE = ObjC; OUTLETS = {appNameField = id; creditsField = id; versionField = id; }; SUPERCLASS = NSObject; }, {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; } ); IBVersion = 1; }stella-5.1.1/src/macosx/AboutBox.nib/info.nib000066400000000000000000000007631324334165500210160ustar00rootroot00000000000000 IBDocumentLocation 345 699 356 240 0 0 1280 1002 IBFramework Version 437.0 IBOldestOS 2 IBOpenObjects 20 IBSystem Version 8B15 stella-5.1.1/src/macosx/AboutBox.nib/keyedobjects.nib000066400000000000000000000167561324334165500225470ustar00rootroot00000000000000bplist00 Y$archiverX$versionT$topX$objects_NSKeyedArchiver ]IB.objectdata 156<=AEMUcijz{ !#%47k@EFKLOYZ`acgjklpqv}~zz #$%(/0CDFJMNPQRSVWC\_jlwLU$null  !"#$%&'()*+,-./0_NSObjectsValues_NSAccessibilityConnectors_NSClassesValuesZNSOidsKeys[NSNamesKeys]NSClassesKeys_NSAccessibilityOidsValues\NSOidsValues_NSVisibleWindowsV$class]NSConnections]NSNamesValues]NSObjectsKeys_NSAccessibilityOidsKeys[NSFramework]NSFontManagerYNSNextOidVNSRoot>234[NSClassNameXAboutBox789:X$classesZ$classname:;^NSCustomObjectXNSObject_IBCocoaFramework>?@ZNS.objects78BCCD;\NSMutableSetUNSSet>FLGHIJK PW5NOPQRS0]NSDestinationWNSLabelXNSSource VWXYZ[\\^_`ab_NSNextResponder[NSSuperviewWNSFrameYNSEnabledXNSvFlagsVNSCell  dVXe.ghZNSSubviews]_{{69, 328}, {380, 29}}klmnopqrstuQwxy_NSBackgroundColor[NSTextColorYNSSupportZNSContents]NSControlView[NSCellFlags\NSCellFlags2 @_<>|}~VNSSizeVNSNameXNSfFlags"A\LucidaGrande78;VNSFontWNSColor[NSColorName\NSColorSpace]NSCatalogNameVSystem\controlColorWNSWhiteK0.6666666978;_controlTextColorB078[;_NSTextFieldCell\NSActionCell78;[NSTextField\%NSTextFieldYNSControlVNSView[NSResponder\appNameField78;_NSNibOutletConnector^NSNibConnectorNOPS0OVWZ.[NSFrameSizeXNSMinize\NSSharedDataYNSMaxSizeZNSDelegateYNSTVFlags[NSDragTypes_NSTextContainer- M8L N!.dVWXZ]NSNextKeyViewYNSBGColorYNSDocViewYNScvFlagsXNSCursorpnn9rq t>@"#$%&'()*+,_Apple HTML pasteboard type_Apple PICT pasteboard type_1NeXT Encapsulated PostScript v1.2 pasteboard type_*NeXT Rich Text Format v1.0 pasteboard type_Apple PDF pasteboard type_NSFilenamesPboardType_NSStringPboardType_NeXT TIFF v4.0 pasteboard type_NSColor pasteboard type_#CorePasteboardFlavorType 0x6D6F6F76_NeXT RTFD pasteboard typeZ{390, 245}WNSWidthZNSTextView_NSLayoutManagerYNSTCFlags"C/7.]NSTextStorageYNSLMFlags_NSTextContainers064 .  XNSString31YNS.stringP278 ;_NSMutableString78;_NSMutableAttributedString_NSAttributedString>Lˀ.578 ;^NSMutableArrayWNSArray78";78$;&'()*+k,-.01._NSSelectedAttributesWNSFlags_NSDefaultParagraphStyle_NSInsertionColor_NSLinkAttributes_NSMarkedAttributes: mBK95B1>89<?WNS.keys:;=?=>;_selectedTextBackgroundColorH@_selectedTextColor78MNN;\NSDictionary>8PT?QRSFGJUVWCDEA[NSUnderline[\]^_YNSHotSpot\NSCursorTypeH IW{8, -8}78bѢ;deUNSRGBF0 0 178hii;_NSTextViewSharedData\{390, 1e+07}Z{373, 245}78mno;[%NSTextViewVNSText\creditsFieldNOPrsS0QVVWXYZ[\\y_`a| R S_{{69, 310}, {380, 16}}klmnopqrsrwxyUTQ|}~"AP\versionFieldNOP0SX\_NSWindowStyleMask_NSWindowBackingYNSMinSize]NSWindowTitle]NSWindowClass\NSWindowRect\NSScreenRect\NSWindowViewYNSWTFlags[NSViewClassZ[Y px\_{{273, 279}, {531, 370}}XNSWindowTView2>LrQ^Q n~5VWXYZ[\\_`_ZNSEditable f mg_ >@ŀ`abcde2_Apple PNG pasteboard type_{{12, 310}, {48, 48}}mnpqxWNSScaleWNSStyleZNSAnimatesWNSAlignUhl2^NSResourceNamejkiWNSImage_NSApplicationIcon78ߣ;_NSCustomResource_%NSCustomResource78[;[NSImageCell\%NSImageCell78;[NSImageViewdVWXZ\\`[NSHScrollerXNSsFlags[NSVScroller]NSContentViewo |yu }>L uy5>L5_{{1, 1}, {391, 245}}[\_sIW{4, -5}78;ZNSClipViewVW XZ  `XNSTargetYNSPercentXNSActionnnnvx"?"w_{{392, 1}, {15, 245}}\_doScroller:78;ZNSScrollerVW XZ  `!"ZNSCurValuenn"?nzx"?rC{_{{-100, -100}, {87, 18}}_{{69, 55}, {408, 247}}78&'';\NSScrollViewVWXYZ[\\+_`-.  _{{224, 12}, {82, 32}}12mno3456p7q8;=>?@xAB_NSKeyEquivalent_NSAlternateImage^NSButtonFlags2_NSPeriodicInterval]NSButtonFlags_NSPeriodicDelay_NSAlternateContentsUU~@ȀROK278GHHI[;\NSButtonCell]%NSButtonCell78KLL;XNSButton_{{1, 9}, {531, 370}}78O;_{{0, 0}, {1280, 1002}}Z{213, 129}_{3.40282e+38, 3.40282e+38}78TUU;_NSWindowTemplateXdelegateNOP0YZ~78]^^;_NSNibControlConnector>`ir\QQn X~ ^78k  ;>mi\\0\\\Ӏ X n>xir0QnX~^>iQ1Q5VWindow\File's OwnerQ2Q6>i>i>i\JGHIKQr0 W Pn~ ^QX>iQF.*,-);=(&'$>L5>i>i78Ѣ;^NSIBObjectData#,1:LQVdf.J\gs",3579;=?ACEGIKMOQSUW`lnpy  1?GPRTVXu!5AKVdp}#0>@BDFHO\iq} $1;BN[dk(:<>@BDFHKMOQ~   < p  ! G c n        ! # , 6 7 9 B I [ d m  ) 1 K ^ q " $ & ( * > G L Y f m o q s z | ~ '0=IP]nprtv!#%'Xl~!*/1:EGIKMOQv'2:<>@ACHUdfhjr5AJVdfhjlnprtvx!*,.0249;S`it9;=?@BD\%')+03<>GR_mv-/135>E]fwy{}   +-/89;DEGPmoqsuwy{}   *stella-5.1.1/src/macosx/AboutBox.nib/objects.nib000066400000000000000000000053641324334165500215160ustar00rootroot00000000000000 typedstream@NSIBObjectDataNSObjectNSCustomObject)@@NSString+AboutBoxi NSTextField NSControl)NSView) NSResponder @@@@ffffffffNSMutableArrayNSArray NSImageView NSMutableSetNSSetIApple PDF pasteboard type1NeXT Encapsulated PostScript v1.2 pasteboard typeNeXT TIFF v4.0 pasteboard typeNSMutableStringNSFilenamesPboardTypeApple PICT pasteboard typeApple PNG pasteboard type 60000icc@ NSImageCell)NSCellAii@@@@NSCustomResource)NSImageNSApplicationIconNSFont$[36c]LucidaGrandef ciiiEH||NSTextFieldCell> NSActionCell@<>$LucidaGrandei:c@@NSColor@@@System controlColorff?*controlTextColor: NSScrollView✒ NSClipView:řNSTextViewTemplateƄNSViewTemplate.ș Apple HTML pasteboard typeApple PICT pasteboard type1NeXT Encapsulated PostScript v1.2 pasteboard type*NeXT Rich Text Format v1.0 pasteboard typeApple PDF pasteboard typeNSFilenamesPboardTypeNSStringPboardTypeNeXT TIFF v4.0 pasteboard typeNSColor pasteboard type#CorePasteboardFlavorType 0x6D6F6F76NeXT RTFD pasteboard typeȒ NSTextView NSDictionaryNSBackgroundColorselectedTextBackgroundColorNSColorselectedTextColorĆķuŒ˒˄@@cccۄNSCursor NSScrollerӛřŒńff:?" _doScroller:řWWŒ?rC¯E7ȒȒffffi NSButton R R  NSButtonCell?OK ssii@@@@@@ rrE6||@<>†ŞNSWindowTemplate iiffffi@@@@@crpx<>NSWindowViewffffՁ鞖ř1ń5򄘘Window File's Owner鄘NSButton2˄6NSNibOutletConnectorτNSNibConnector appNameField˄ creditsField versionField򕄘delegateNSNibControlConnector镄OK@i.*,-); =ͷ(͢&͙'͕$>IBCocoaFrameworkstella-5.1.1/src/macosx/AboutBoxTextView.h000066400000000000000000000016211324334165500204650ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #import /** AboutBoxTextView class and support functions for the Macintosh OS X SDL port of Stella. @author Mark Grebe */ @interface AboutBoxTextView : NSTextView { } @end stella-5.1.1/src/macosx/AboutBoxTextView.m000066400000000000000000000023671324334165500205020ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #import "AboutBoxTextView.h" #import "AboutBox.h" @implementation AboutBoxTextView /*------------------------------------------------------------------------------ * mouseDown - This method notifies the AboutBox class of a mouse click, then * calls the normal text view mouseDown. *-----------------------------------------------------------------------------*/ - (void)mouseDown:(NSEvent *)theEvent { if ([theEvent clickCount] >= 2) [[AboutBox sharedInstance] doubleClicked]; else [[AboutBox sharedInstance] clicked]; [super mouseDown:theEvent]; } @end stella-5.1.1/src/macosx/Cart.icns000066400000000000000000001025251324334165500166450ustar00rootroot00000000000000icnsUit32EE߂݀ ր~߂ڀ¿aހہÿĘހہ¿ހہ¾k߀ۀրk߀ۀրk߀ۀր¾j߀ہʿi߀ۀĿʿiۀʿiրüʾhހ ƿʾhހۀʾhހۀüʾg߀ ƿʾg߀ ʾg߀ۀºʾg߀ۀ ûʾg߀ۀ üʾgżʾhǾʾhʾhʾhøʾi!ùvnnʿi$Ļ{slifddegimptʿi$Ƽxsnljjklnqsvzkzwts ttvy|~kú~|} bž º ƿ H, ʁу ¿րӀ؀ր ƿڀ܀ڀ¿)ª½)Ȭǽ˰ܐä*ҷͺ˷ͻfXǤ+پ̹}\_|ʤ-ʬͼ̰Т\beWΤ,ӹôʻn^baa^Ф-ۿȮя[a``bZҤˬȵʹϴ^^a`c]դԷɿöx[a`a]tפƳū̜Z`aa``cP ڤȫԺİĹi\a` cY ۤδƴ̈Y`cS ܤҹ˲ȫia`a``bS ݤռ±ɱՕhf``a``YޤԼyqmda``KߤѺȠөttric]Yj ɱīϑyxtpgbO%lĈȆ|wsn^ &ǶK̕ņzts^&Ÿ@Zfȼ}yj&ûl+0zcȷg )ɴI'{ Ywƽ~{'ǠU(.!OjXɕ{&ϫQ.0859__ϣx&޽fB4Z{npctɤ}_Va_dfe^XWSLPipsa]ҵ&{s{pidb\YYOkjnu\?ͧ&kxqieb^Th|bjksK!æ%ɭxvunid`dfgfh7s$ӿkle[`mcebaa.5ȹ%̹W\a_`b[&#WǢ&Ƨaf]`_`dV%xϲiea^`cOD}Qgӹqaa\`EѾ|G<^]d1wػQBG;ɪsR;շr@HFH;ȳҲtJCGFFG>ѰzkAGGFGAҹc@GFB_ռeBFH< ؾk?GFAk z>H> ā;r͞dddрeddd҇ eeodddӉeee dddeeoeoee݀dddɗndd҄oeeeeeoeoedddnddeo#eeeeeeddxdoeeeeeeddӄdeeeeoeeeee񵃁dԀeeeeeeeddxdeeeeeeeeeddyeeeyeeeeeeed/fzfeeeeeyeeeeeyyddӄpfpeoeyeeeedd߄߂݀ ր~߂܀Հ¿aހہÿĘހہ¿ހہ¾k߀ۀրk߀ۀրk߀ۀր¾j߀ہʿi߀ۀĿʿiۀʿiրüʾhހ ƿʾhހۀʾhހۀüʾg߀ ƿʾg߀ ʾg߀ۀºʾg߀ۀ ûʾg߀ۀ üʾgżʾhǾʾhʾhʾhøʾi!ùvnnʿi$Ļ{slifddegimptʿi$Ƽxsnljjklnqsvzkzwts ttvy|~kú~|} bž º ƿ H, ʁс ¿րӀ ր ƻڀ܀ڀ¿)‘z|)ȥj~y}rv`ä*Ҷkvvr53Ǥپ}vwp~N//i݀ʤ-ʥhwzvvo.56.Τ,Ӹjsuo>2663@Фۿtrv~pz^/67-}Ҥ˥h{vt|r1465=դԶiqul~G160cפurvxntk/6 7- ڤȥdtszq:36 7/t ۤαaptmuW/67 ܤҹvxrrupq9467+} ݤռwo}qrp{owa>:564CޤԼtnwcnszjuGHA67)ߤѺvjw^bvrgprqCIH=660Z ɮpkv^PuqsawuXFIIE:5/%dpt_>lvwTqtxPLHIIB0t &ǵxbtu\+Qwr\Uyq~PPLHIF>&ĶbhqnS"6tozu7fwqzSSOII?}&ùzefori@jtpI5rvqxVVRNIA )ɢykdimqoP(Jwm}h/Ewtr{ZYUQHc'dž`dgikmqp[2 +souu<-Nytr}^[XUG&Ϥ^jijmqkW- ato{S44Sytsuf^ZVI&޻bonleU;"(*&Mrkyh@@:Pvttqrb^[I'p>G;/"$/40+("5nlovLDD9Gtrtqda^OL.:99853/./cpkvZ@FG97spstsqcaX dBLE=76/Rqjsl??BI8$mqqtr|fc[&?HF>9563octpposvj*Zӹ[6659&ѾkkropptL'|52;tغlorosd.#'ɦ\.+ն_psqE"'ȰұPq_(%&''&ѰX>#&&'%%ҹM'( RռQ '  ؾ['' ^ m&" vd͙ dddedddӇ eeodddӉeee dddeeoeoee݀dddɗndd҃oeeeeeoeoedddnddeo#eeeeeeddxdoeeeeeeddӄdeeeeoeeeee񵃁dԀeeeeeeeddxdeeeeeeeeeddyeeeyeeeeeeed/fzfeeeeeyeeeeeyyddӄpfpeoeyeeeedd߄߂݀ ր~߁ ׀ԀaހہÿĘހہ¿ހہ¾k߀ۀրk߀ۀրk߀ۀր¾j߀ہʿi߀ۀĿʿiۀʿiրüʾhހ ƿʾhހۀʾhހۀüʾg߀ ƿʾg߀ ʾg߀ۀºʾg߀ۀ ûʾg߀ۀ üʾgżʾhǾʾhʾhʾhøʾi!ùvnnʿi$Ļ{slifddegimptʿi$Ƽxsnljjklnqsvzkzwts ttvy|~kú~|} bž º ƿ H, ʁу ¿րӀ؀ր Ŷڀ܀ڀ¿)h*(9XP:v)țä*Ҵ  Ǥ+پ_Tʤ ʚ Τӷ ФۿcnҤ ˛ դԵ Mפ\  ڤ Ț   g ۤά   ܤ Ӹ1 tݤռE#ޤԻA ߤѹDE ɩ0 e DzG IJm l ·G  LJ{L8 @\Ϙ޶ U6ؿAoɣ% ӾP _ ̴z   Ơ x@ϭ 8YMӷ5 Ѿ<zgtػ6ɟ<մȭҰѰ Ҹ3?ջ9 ؽFN [ fU͑ dddуeddd҇ eeodddӉeee dddeeoeoee݀dddɗndd҄oeeeeeoeoedddnddeo#eeeeeeddxdoeeeeeeddӄdeeeeoeeeee񵃁dԀeeeeeeeddxdeeeeeeeeeddyeeeyeeeeeeed/fzfeeeeeyeeeeeyxddӄpfpeoeyeeeedd߄t8mk@    E   9  ,n  %6|  *>Y .EZ 1I[ 3KZ 3LZ 3LZ 3M[ 3M[ 3M[ 3M\ 3M\ 3M\ 3M\ 3M\ 3M\ 3M\ 3M[ 3M[ 3M[ 3M[ 3MZ 3MZ 3MZ 3MZ 3MY 3MG 3M'3M$ 3MD 3M' 3M03M7# 3M>( 3MC, 3MG/3MI13MJ23MK33ML33ML33ML33ML33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33MM33LL33LL33KK31II1.EE. *>>*  %6I[itz~~zti[I6%  ,;IU]befffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb]UI;,   ,6>EIKLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLKIE>6,  %*.133333333333333333333333333333333333333333333333333333333333333333333333333333331.*%    stella-5.1.1/src/macosx/Create_build.sh000077500000000000000000000021051324334165500200100ustar00rootroot00000000000000#!/bin/sh # # Creates a Stella disk image (dmg) from the command line. # usage: # Create_build.sh # # The result will be a file called ~/Desktop/Stella--macosx.dmg if [ $# != 1 ]; then echo "usage: Create_build.sh version" exit 0 fi VER="$1" DMG="Stella-${VER}-macosx.dmg" DISK="/Volumes/Stella" DEST=~/Desktop/${DMG} echo "Creating ${DMG} file ..." gunzip -c template.dmg.gz > "${DMG}" echo "Mounting ${DMG} file ..." hdiutil attach "${DMG}" echo "Copying documentation ..." ditto ../../Announce.txt ../../Changes.txt ../../Copyright.txt ../../License.txt ../../Readme.txt ../../Todo.txt "${DISK}" echo "Copying application ..." cp -r DerivedData/Build/Products/Release/Stella.app "${DISK}" echo "Updating modification times ..." touch "${DISK}"/Stella.app "${DISK}"/*.txt echo "Ejecting ${DMG} ..." hdiutil eject "${DISK}" if [ -f "${DEST}" ]; then echo "Removing duplicate image found on desktop ..." rm -f "${DEST}" fi echo "Compressing image, moving to Desktop ..." hdiutil convert "${DMG}" -format UDZO -imagekey zlib-level=9 -o "${DEST}" rm -f "${DMG}" stella-5.1.1/src/macosx/Credits.html000066400000000000000000000031301324334165500173510ustar00rootroot00000000000000 Acknowledgements

Stella

A multi-platform Atari 2600 VCS emulator

Copyright © 1995-2018 The Stella Team
https://stella-emu.github.io

Stella is now DonationWare!
https://stella-emu.github.io/donations.html

Macintosh OS X version:
Copyright © 2007-2018 Stephen Anthony
Copyright © 2005-2006 Mark Grebe

Graphics by Simple DirectMedia Layer library
http://www.libsdl.org

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation;  either version 2
of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. 
See the GNU General Public License for more details.

  You should have received a copy of the GNU General
Public License with this program; if not, write to the:
Free Software Foundation, Inc.,
59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
stella-5.1.1/src/macosx/English.lproj/000077500000000000000000000000001324334165500176075ustar00rootroot00000000000000stella-5.1.1/src/macosx/English.lproj/InfoPlist.strings000077500000000000000000000004761324334165500231430ustar00rootroot00000000000000/* Localized versions of Info.plist keys */ CFBundleName = "Stella"; CFBundleShortVersionString = "Stella version 5.1"; CFBundleGetInfoString = "Stella version 5.1"; NSHumanReadableCopyright = "Stella MacOS X version by Stephen Anthony and Mark Grebe."; "Atari 2600 Cartridge File" = "Atari 2600 Cartridge File"; stella-5.1.1/src/macosx/Info-Stella.plist000066400000000000000000000035201324334165500202630ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleDisplayName Stella CFBundleDocumentTypes CFBundleTypeExtensions bin BIN rom ROM zip ZIP a26 A26 CFBundleTypeIconFile Cart CFBundleTypeName Atari 2600 Cartridge File CFBundleTypeOSTypes Cart CFBundleTypeRole Viewer CFBundleExecutable $(EXECUTABLE_NAME) CFBundleGetInfoString Stella CFBundleHelpBookFolder docs CFBundleHelpBookName docs CFBundleIconFile Stella CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName Stella CFBundlePackageType APPL CFBundleSignature StLa CFBundleVersion 5.1 LSApplicationCategoryType public.app-category.games LSMinimumSystemVersionByArchitecture x86_64 10.7.0 NSMainNibFile SDLMain NSPrincipalClass SDLApplication stella-5.1.1/src/macosx/OSystemMACOSX.cxx000066400000000000000000000031421324334165500201330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "FSNode.hxx" #include "OSystemMACOSX.hxx" /** Each derived class is responsible for calling the following methods in its constructor: setBaseDir() setConfigFile() See OSystem.hxx for a further explanation */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystemMACOSX::OSystemMACOSX() : OSystem() { setBaseDir("~/Library/Application Support/Stella/"); // This will be overridden, as OSX uses plist files for settings setConfigFile("~/Library/Application Support/Stella/stellarc"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemMACOSX::defaultSaveDir() const { FilesystemNode desktop("~/Desktop/"); return desktop.isDirectory() ? desktop.getShortPath() : "~/"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemMACOSX::defaultLoadDir() const { return defaultSaveDir(); } stella-5.1.1/src/macosx/OSystemMACOSX.hxx000066400000000000000000000027701324334165500201460ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef OSYSTEM_MACOSX_HXX #define OSYSTEM_MACOSX_HXX #include "OSystem.hxx" /** This class defines UNIX-like OS's (MacOS X) system specific settings. @author Mark Grebe */ class OSystemMACOSX : public OSystem { public: /** Create a new MACOSX-specific operating system object */ OSystemMACOSX(); virtual ~OSystemMACOSX() = default; /** Returns the default paths for loading/saving files. */ string defaultSaveDir() const override; string defaultLoadDir() const override; private: // Following constructors and assignment operators not supported OSystemMACOSX(const OSystemMACOSX&) = delete; OSystemMACOSX(OSystemMACOSX&&) = delete; OSystemMACOSX& operator=(const OSystemMACOSX&) = delete; OSystemMACOSX& operator=(OSystemMACOSX&&) = delete; }; #endif stella-5.1.1/src/macosx/Preferences.h000066400000000000000000000021501324334165500175010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #import /** Preferences class and support functions for the Macintosh OS X SDL port of Stella. @author Mark Grebe */ @interface Preferences : NSObject { NSUserDefaults *defaults; /* Defaults pointer */ } + (Preferences *)sharedInstance; - (void)setString:(const char *)key : (const char *)value; - (void)getString:(const char *)key : (char *)value : (int)size; - (void)save; @end stella-5.1.1/src/macosx/Preferences.m000066400000000000000000000045671324334165500175240ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #import #import "Preferences.h" void prefsSetString(const char* key, const char* value) { [[Preferences sharedInstance] setString:key:value]; } void prefsGetString(const char* key, char* value, int size) { [[Preferences sharedInstance] getString:key:value:size]; } void prefsSave(void) { [[Preferences sharedInstance] save]; } @implementation Preferences static Preferences *sharedInstance = nil; + (Preferences *)sharedInstance { return sharedInstance ? sharedInstance : [[self alloc] init]; } - (id)init { if (self = [super init]) { defaults = [[NSUserDefaults standardUserDefaults] retain]; sharedInstance = self; } return(self); } - (void)dealloc { [defaults release]; if (self == sharedInstance) { sharedInstance = nil; } [super dealloc]; } - (void)setString:(const char *)key : (const char *)value { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString* theKey = [NSString stringWithCString:key encoding:NSUTF8StringEncoding]; NSString* theValue = [NSString stringWithCString:value encoding:NSUTF8StringEncoding]; [defaults setObject:theValue forKey:theKey]; [pool release]; } - (void)getString:(const char *)key : (char *)value : (int)size { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString* theKey = [NSString stringWithCString:key encoding:NSUTF8StringEncoding]; NSString* theValue = [defaults objectForKey:theKey]; if (theValue != nil) strncpy(value, [theValue cStringUsingEncoding: NSUTF8StringEncoding], size); else value[0] = 0; [pool release]; } - (void)save { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [defaults synchronize]; [pool release]; } @end stella-5.1.1/src/macosx/SDLMain.h000066400000000000000000000004271324334165500164740ustar00rootroot00000000000000/** SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn */ #import @interface SDLMain : NSObject { } + (SDLMain*) sharedInstance; @end stella-5.1.1/src/macosx/SDLMain.m000066400000000000000000000123341324334165500165010ustar00rootroot00000000000000/** SDLMain.m - main entry point for our Cocoa-ized SDL app Initial Version: Darrell Walisser Non-NIB-Code & other changes: Max Horn */ #import "SDL.h" #import "SDLMain.h" #import "Preferences.h" #define SDL_main stellaMain extern int stellaMain(int argc, char* argv[]); static int gArgc; static char** gArgv; static BOOL gFinderLaunch; static BOOL gCalledAppMainline = FALSE; // The main class of the application, the application's delegate @implementation SDLMain // ---------------------------------------------------------------------------- static SDLMain* sharedInstance = nil; + (SDLMain*) sharedInstance { return sharedInstance; } // ---------------------------------------------------------------------------- // Set the working directory to the .app's parent directory - (void) setupWorkingDirectory:(BOOL)shouldChdir { if (shouldChdir) { char parentdir[MAXPATHLEN]; CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); if (CFURLGetFileSystemRepresentation(url2, 1, (UInt8*)parentdir, MAXPATHLEN)) { chdir(parentdir); /* chdir to the binary app's parent */ } CFRelease(url); CFRelease(url2); } } // ---------------------------------------------------------------------------- /** * Catch document open requests...this lets us notice files when the app * was launched by double-clicking a document, or when a document was * dragged/dropped on the app's icon. You need to have a * CFBundleDocumentsType section in your Info.plist to get this message, * apparently. * * Files are added to gArgv, so to the app, they'll look like command line * arguments. Previously, apps launched from the finder had nothing but * an argv[0]. * * This message may be received multiple times to open several docs on launch. * * This message is ignored once the app's mainline has been called. */ - (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename { const char* temparg; size_t arglen; char* arg; char** newargv; if (!gFinderLaunch) // MacOS is passing command line args. return FALSE; if (gCalledAppMainline) // app has started, ignore this document. return FALSE; temparg = [filename UTF8String]; arglen = SDL_strlen(temparg) + 1; arg = (char*) SDL_malloc(arglen); if (arg == NULL) return FALSE; newargv = (char **) realloc(gArgv, sizeof (char*) * (gArgc + 2)); if (newargv == NULL) { SDL_free(arg); return FALSE; } gArgv = newargv; SDL_strlcpy(arg, temparg, arglen); gArgv[gArgc++] = arg; gArgv[gArgc] = NULL; return TRUE; } // ---------------------------------------------------------------------------- // Called when the internal event loop has just started running - (void) applicationDidFinishLaunching: (NSNotification *) note { int status; // Set the working directory to the .app's parent directory [self setupWorkingDirectory:gFinderLaunch]; // Hand off to main application code gCalledAppMainline = TRUE; status = SDL_main (gArgc, gArgv); // We're done, thank you for playing exit(status); } @end static int IsRootCwd() { char buf[MAXPATHLEN]; char *cwd = getcwd(buf, sizeof (buf)); return (cwd && (strcmp(cwd, "/") == 0)); } static int IsTenPointNineOrLater() { /* -instancesRespondToSelector is available in 10.9, but it says that it's available in 10.10. Either way, if it's there, we're on 10.9 or higher: just return true so we don't clobber the user's console with this. */ if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) { return 1; } /* Gestalt() is deprecated in 10.8, but I don't care. Stop using SDL 1.2. */ SInt32 major, minor; Gestalt(gestaltSystemVersionMajor, &major); Gestalt(gestaltSystemVersionMinor, &minor); return ( ((major << 16) | minor) >= ((10 << 16) | 9) ); } static int IsFinderLaunch(const int argc, char **argv) { const int bIsNewerOS = IsTenPointNineOrLater(); /* -psn_XXX is passed if we are launched from Finder in 10.8 and earlier */ if ( (!bIsNewerOS) && (argc >= 2) && (strncmp(argv[1], "-psn", 4) == 0) ) { return 1; } else if ((bIsNewerOS) && (argc == 1) && IsRootCwd()) { /* we might still be launched from the Finder; on 10.9+, you might not get the -psn command line anymore. Check version, if there's no command line, and if our current working directory is "/". */ return 1; } return 0; /* not a Finder launch. */ } #ifdef main # undef main #endif // Main entry point to executable - should *not* be SDL_main! int main (int argc, char* argv[]) { static Preferences *myPrefs; // Copy the arguments into a global variable // This is passed if we are launched by double-clicking if (IsFinderLaunch(argc, argv)) { gArgv = (char**) SDL_malloc(sizeof(char*) * 2); gArgv[0] = argv[0]; gArgv[1] = NULL; gArgc = 1; gFinderLaunch = YES; } else { gArgc = argc; gArgv = (char**) SDL_malloc(sizeof(char*) * (argc+1)); for (int i = 0; i <= argc; i++) gArgv[i] = argv[i]; gFinderLaunch = NO; } myPrefs = [Preferences sharedInstance]; NSApplicationMain (argc, (const char**)argv); return 0; } stella-5.1.1/src/macosx/SDLMain.nib/000077500000000000000000000000001324334165500170675ustar00rootroot00000000000000stella-5.1.1/src/macosx/SDLMain.nib/designable.nib000066400000000000000000000054751324334165500216710ustar00rootroot00000000000000 stella-5.1.1/src/macosx/SDLMain.nib/keyedobjects.nib000066400000000000000000000062021324334165500222340ustar00rootroot00000000000000bplist00XYX$versionX$objectsY$archiverT$topV#$*.29ADEFJO_deflmnquvyz~(=>?@ABCDEFGHIJKLMNORUU$null VNSRoot]NSConnections\NSOidsValues_NSObjectsValues]NSObjectsKeys_NSAccessibilityOidsValues_NSVisibleWindows_NSAccessibilityOidsKeys_NSAccessibilityConnectorsV$classZNSOidsKeys@>)TTSU? !"[NSClassName]NSApplication%&'(Z$classnameX$classes^NSCustomObject')XNSObject+,-ZNS.objects%&/0\NSMutableSet/1)UNSSet+384567 !(:;<>?@XNSSource]NSDestinationWNSLabel B" WSDLMainXdelegate%&GH_NSNibOutletConnectorGI)^NSNibConnector:;<KMNPQRSTUVWXYZ[\]^]NSMnemonicLocVNSMenu_NSKeyEquivModMaskYNSOnImageZNSKeyEquivWNSTitle\NSMixedImageU`abc[NSMenuItems795[Stella HelpQ?ghijk[NSClassName^NSResourceNameWNSImage_NSMenuCheckmark%&op_NSCustomResourceo)ghijt_NSMenuMixedState%&wxZNSMenuItemw)YshowHelp:%&{|_NSNibControlConnector{})^NSNibConnector:<N PQRSTUVWYZ[^`UcVNSName51/4[Quit StellaQqZterminate::;<N"%'QPSTUVZW[^$#\About StellaP "&XAboutBoxZshowPanel:%&^NSMutableArray)WNSArray+XK>*,."26 ;%= "+]NSApplication`UcB5- :+8.6(PQRSTUVWYZ[^XNSTargetYNSSubmenuXNSAction,$/0VStella^submenuAction:+8"2(PQRSTUVWYZ[^]NSIsSeparator\NSIsDisabled 3 3P\_NSAppleMenu%&VNSMenu)PQRSTUVWYZ[XXa^,$78THelp^submenuAction:+8K([_NSMainMenu "<]NSFontManager%&)+X,.,6=+XK>4567*,."26 ;% !=+)*+,-./0123456789:;ABCDEFGHIJKLMNOPQR=     +P8(+S=%&VW^NSIBObjectDataV)_NSKeyedArchiverZ[=\_IB.systemFontUpdateVersion]IB.objectdata"+5:?!(6CUc  +4CHQZefhq~$3DFHJLm{+-/19KTgly{} "$&(*,=DFHJLXZevxz|~!#%')+-/13579;=FHJXikmoqz  7ERTVWY[\^`anw~ $?ACEGIKMOQSUWY[d              ! # % ' ) + 4 5 7 @ A C L [ ` r { ] stella-5.1.1/src/macosx/SerialPortMACOSX.cxx000066400000000000000000000044711324334165500206220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #include #include #include #include #include #include #include #include "SerialPortMACOSX.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortMACOSX::SerialPortMACOSX() : SerialPort(), myHandle(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortMACOSX::~SerialPortMACOSX() { closePort(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SerialPortMACOSX::openPort(const string& device) { myHandle = open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); if(myHandle <= 0) return false; struct termios termios; tcgetattr(myHandle, &termios); memset(&termios, 0, sizeof(struct termios)); cfmakeraw(&termios); cfsetspeed(&termios, 19200); // change to 19200 baud termios.c_cflag = CREAD | CLOCAL; // turn on READ and ignore modem control lines termios.c_cflag |= CS8; // 8 bit termios.c_cflag |= CDTR_IFLOW; // inbound DTR tcsetattr(myHandle, TCSANOW, &termios); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SerialPortMACOSX::closePort() { if(myHandle) { close(myHandle); myHandle = 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SerialPortMACOSX::writeByte(const uInt8* data) { if(myHandle) { // cerr << "SerialPortMACOSX::writeByte " << (int)(*data) << endl; return write(myHandle, data, 1) == 1; } return false; } stella-5.1.1/src/macosx/SerialPortMACOSX.hxx000066400000000000000000000036671324334165500206350ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SERIALPORT_UNIX_HXX #define SERIALPORT_UNIX_HXX #include "SerialPort.hxx" /** Implement reading and writing from a serial port under OSX. For now, reading isn't actually supported at all. @author Stephen Anthony & D. Spice */ class SerialPortMACOSX : public SerialPort { public: SerialPortMACOSX(); virtual ~SerialPortMACOSX(); /** Open the given serial port with the specified attributes. @param device The name of the port @return False on any errors, else true */ bool openPort(const string& device) override; /** Close a previously opened serial port. */ void closePort() override; /** Write a byte to the serial port. @param data The byte to write to the port @return True if a byte was written, else false */ bool writeByte(const uInt8* data) override; private: // File descriptor for serial connection int myHandle; private: // Following constructors and assignment operators not supported SerialPortMACOSX(const SerialPortMACOSX&) = delete; SerialPortMACOSX(SerialPortMACOSX&&) = delete; SerialPortMACOSX& operator=(const SerialPortMACOSX&) = delete; SerialPortMACOSX& operator=(SerialPortMACOSX&&) = delete; }; #endif stella-5.1.1/src/macosx/SettingsMACOSX.cxx000066400000000000000000000033621324334165500203340ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "SettingsMACOSX.hxx" extern "C" { void prefsSetString(const char* key, const char* value); void prefsGetString(const char* key, char* value, int size); void prefsSave(void); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsMACOSX::SettingsMACOSX(OSystem& osystem) : Settings(osystem) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SettingsMACOSX::loadConfig() { string key, value; char cvalue[4096]; // Read key/value pairs from the plist file const SettingsArray& settings = getInternalSettings(); for(uInt32 i = 0; i < settings.size(); ++i) { prefsGetString(settings[i].key.c_str(), cvalue, 4090); if(cvalue[0] != 0) setInternal(settings[i].key, cvalue, i, true); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SettingsMACOSX::saveConfig() { // Write out each of the key and value pairs for(const auto& s: getInternalSettings()) prefsSetString(s.key.c_str(), s.value.toCString()); prefsSave(); } stella-5.1.1/src/macosx/SettingsMACOSX.hxx000066400000000000000000000033021324334165500203330ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SETTINGS_MAC_OSX_HXX #define SETTINGS_MAC_OSX_HXX class OSystem; #include "Settings.hxx" /** This class defines Macintosh OSX system specific settings. @author Mark Grebe */ class SettingsMACOSX : public Settings { public: /** Create a new UNIX settings object */ SettingsMACOSX(OSystem& osystem); virtual ~SettingsMACOSX() = default; public: /** This method should be called to load the current settings from the standard Mac preferences. */ void loadConfig() override; /** This method should be called to save the current settings to the standard Mac preferences. */ void saveConfig() override; private: // Following constructors and assignment operators not supported SettingsMACOSX() = delete; SettingsMACOSX(const SettingsMACOSX&) = delete; SettingsMACOSX(SettingsMACOSX&&) = delete; SettingsMACOSX& operator=(const SettingsMACOSX&) = delete; SettingsMACOSX& operator=(SettingsMACOSX&&) = delete; }; #endif stella-5.1.1/src/macosx/Stella.icns000066400000000000000000000705611324334165500172040ustar00rootroot00000000000000icnsqqic12̉PNG  IHDR@@iqsRGB~IDATxil\uϛCgHnY-[r/ڱMnq"AAE-R$iQ _o I8ٖdK$")ef޼[2)[J-[B{}wl;@kZkp\bM]owbHSOX/q0jx\Ov%i~'Hݟ|fiaUխAjbˎYzx?2>Ȟh_lcOaYuvp.W . ۑ0wᆵ~b[7{A>8oq"cmwJjX`<7*㻾dA玤+YI4V;,^6̲JqgV{n2X̳x7!nGU_[y .j3"+.ok=V[i*@Guv)c{ kt ?/}aS5 Thنz,H*j|^{yƲF{7^UYYA0NiiSC;ڻ^Lo%럤Y z5/nC sڧcCƄ7?hbZ *kR/%li5n::T໚ywSa;ݟv4|>׀[Mɛ?_}h*GU\\>,MW7lp`֝nReu:CH,M#ڢ1 ~xν,j~n߁'}QJ+/@TUI7UCy HJu uG5gBޥmx½R_d 781ʈVbs܆VP%lצ9܎/#i\~؂;L 1}8ͷnI߾|]* "%SOfmwn@[%vztm^)EASsDyxf3=E}4|](ؒ_|m:ؿ{S8/y>z6:a՛-36nsq |_OBҼiyv ~UL^n%xѻ}4LDo!!6Msn.l/gdD`sg*ԟ_ [._emwʪ|KľG[X_&[A'/}&4gS)e{u^ T3E@YI*},zjWa'@Ʈ-{y^G7ƺү}>c)( wv,ac#Q-Oh/3+#5Fr@_p\ͯ"@\ַ8xf>Y#ߛ(mjXC_xdi{YR)f qWU !ӎ6E2sw h_WtFS &ǸrL=/#lY ]XQ'N7‰J_ |:U*LLZ2s,mnq r_>v ZX}ŊQ؎DI.<{3_`,O!t|2zOb2}N0y7no^3iU}EM=擠TwX:T!ęIYs/Vg=[Gh#*a<̙x#TGjǟ`ri+^ &Gإ>de=[@qwת#  m Y@P6Eak {wVȶl ֥T2{!(]) wbѕ"Hh~*G+$*VP!;=c€s]c1[3鍧> *Rz.o~2+=l|X)1xւҘ䮝ToWZiMAI qL<} oC"Mkcz@m .Zc 7ao!Hn~Ak,sЛ L}#/?wnJMRUh`q,6)*ƜjLxF )_˚z/-72>ngpcq\l9*v5n&@U>o\_WW--)կ5.I*NAh>%h@ Aʪ8F'@=w)`ኛD}~erJפ柉9希3?1,2\7$rd];̤fz!5,ΦgW6>_٨/X6&A$}A2 %2!c;+1b]ZȬdu{x+zHc8ʛR`v3ˋ확x$[ @c2A\b߆{Fg@8| > IR.3}b[kת3 c,< @\E]}QieZ :K`j3OuMB6r`I;^/XX ^Ipp|}H6ccVŢ۶c f^iwS]4RVQ0upyJ@Eұ/X\q˓ N A0;2dCDpa6ipist' *&T`y ZNFXRU{GRIENDB`ic07EQPNG  IHDR>asRGB@IDATxWיw* $L0jFi(QCً ^i^7{a>H ȍ:Ǫ UĀ$C?P)@ ·O~xxgʆmWa¯D,EA=#Ʉ=8>_-牅\+[TQlY"Vȑ}wtq9]h'F 6$<:D#ΦBfzZA}鯁ʳ6qIs$-"%7qgtyr~"HΟI~pe~wN j5&8/}m^hr693/ V{g*lw[{isc{6*T}pV7BPLk;a|I7[\% × '4ItvwyW?{a?]9}w|AZ. ;u)-Ihw޸8hq;9UOJjs3VagR?>Y-TN@'+DN7wy}oOhxO{uJKG'Kss2 婷fi,bbƩft*5R6 x4)5sͿK3uQ|lJsC/ȧ}Udҍrk#M$U;hx95~!m]ONJJa%m.W BBxl)8; a?~ngX/gRb4f!?J~r_\L;^$Jc3R)ef 8n/Sgu%ջTN@2׋|k`PH+njR$e@|U1Swum9]MgřZ]Jx@QKNA&E)VKŝgb',LJi}^joRE'* ݕRͥ ,n~JOڞȧS311Vn>Iw$M2LWDߖ .NiwSMnWt1P_FHONDXLv睒B__qu\]OKK HEeVB<(]ǥR_ ۗvS9^-h^YOdž d]+3TK~FT / iIR([qRb9UKeE+sDg lZf>snBjOx\^O@ @:O 7tDEjuo`*on#A倠ʼnFy/R Ks —<1UF}RE;7ċԜJ6D6u&-\^LicV䅽OvR6ﮥvLVq\lǯa nR&b7DDqhV6hk֝)4R#$ "yR&?kUTZZRAp"]{=WcJ9g*rDGY HVs?~fo  [o\j/&T5.zU˥{a0S4NڽnZYHAbn' c 467wӭۉôO8LUdgY:+^zԠ<^/ .5e[>M݋g@6;&NlSNDQ.tԩTzXݫPWq@XOw"5<?.;L pDJ UK-'NF F~Z?*6@ha]m 2ASKr^9JLM`;L.ӬtMy*W?O+~G߆dosAA$PjX(QϠ$j[a߼[k4~[L9&p*崶7cV pj|>X2VƋa{/[i5BqC>*_ClӍktѯ{ 12A#[rZ m %׫ҼZl<~`>t|/g^YyЍMʹb|[D!-RTY7Yu?4svk=-H׮7ɺ1C"?@"8?c~)ӠoVgϷQylos풢?MURqAZeޠ=HufN/+tvoĐ]meHm.c~z%$h6HLBE22ކ3z+$]"RJD,X8j VP,* ʿ+߽59{P4*ܺo_0MLi++C-.$"".:SJw"_z/, bWe kοUJ;܏exb#@g~a 9^ܽ|v9SMxm:LS HH< *l^c!riN8к 0wy~Zs$,[Dpw>9W_ZVە!|D=&QI`'@'|,;W?rf?[, f\J-yIEr>ck+wip"|ǯ1; vZ BPH'kH.b] x~RNw7;r HGD%"?3 ߖ zվ;߿Ԯ§όr6WwKUteֺ k2˘{PvSp;_'V$9r!H jw"|=dv׷kD5K<'nyoC?zD7 0occPNj@@oN.TD:d?1J3ugbLILD DRB`2r}!CyPN[`r+_%"QBB'ͷ'?;?;n脢"u:VS 2El9o&&L2?{DO!^` j@ƣwxhD(aH,QõrZ "^X$*I7%k>o_Lsz<ڽǷ a`CuHPX, F QxG= #W2 @DhϾ!#gUJ>^Y_/KCŸaԜ ?x9SzY|v*uw81YO(%D;f @sɴnZ1..C,fhxy.r7(ҍqncݻF1?ߕbnQ8woCy!qe4Hǃ {t}սCCAC723j^xjj,RL0_yu?E{x?8Bq8S}ݹJ U>P+ α|f:! GDnK+~#F9K{bh1^PW<'}ƅ:F[ݟ}aٲ!Rs&on'퇯_w!Q 9>C6u8VpCg ;`ɣqo3X ^)aO Q~7WF>cSӯ{s:7՜@ZU8WrV=.ί6Pkݰ'A U kmr8YXHotu̷1H&P 6%"^z O:z >&ƛncsztB\6A|6ܩ#2ng81WM{^pΩݹi$$)6X09zX7!#:$x6F[x՝r GD9^r}%!u~CF>|ߕ驉W}}y _d)%{-k esUk NUts1?hB,%b^2jX tS:?U1nĤ$}}Z~%fmT]Ox;U_""C7ۯ*<ps6ʼ9vrjEݐ ʡ,ˑhLمX%|{k8~C&7* LJȷp2,D>1͍r< _C$k/< _ة+ͷa_Lܸj R ^$1ӳ崿c"O7 9*y| xȒ5,t&H%U;% 4XDXIs1$=^NAϜĿ7{:%bU3&u{ȚEˑrp8LԴUYPԅ;(5Bw'zҠ{6XO<}"VrİCN(bSJݝJwj@P~}fޯS,,uh~-szWYu rl W_֥rMPf*:&S>0D~ I 009jkĥa g,Cum~Б ,WIa5f:=>s6$d͑ _'g|Z+W_g3E@]ŀg- TI8_%|M*18\*b4nsp,(SKX:I!@,$}|"-EkHr`_ Fq~Rza>'\"bxU<}K5b M.x}_X ّ1BL!S (!$#EăaUGƁN~5\-{oe\-m`=Tܯ=žK~q 2Çnz,]lһ{r8c}r]X8s(!^sA8_ d&9w_8*?n@]Qn1b-* ">C$^UA,ِ7W(7_#Q`RRV*/sS mx]^~ڑ7A;'@HgCt128L@K=n`lEsrm`Mz >*[ogqNBkZoZ)/C1' zߝW?kӽпYkA>8 2FA XGmӈ&M7nJy?ݰ+lYӠ, X 6,6;磱yK">v4FKی)ؓ [W "מO_> 6Ӌ\@+0Žw~E<^T@à9,]+܅A 3TGI!pG0 D&*B8@([:B,cf'־zFY v(kB5cޤY^?X0^5} &QᏦf>@"y[0}] xa#MGJ&OFkDbN!]:"K"$󳓵 GϵB.7YLhD?Cn}"O}:D@79JM   OB_JܯVn ܶpN(:!  0vhe>Nbvhj}&R S"IhRAtqH >X"UT9T``E\TϮvC`1 4|8>7ƽlLŹ^ ]p bųStmWW0N!6V)܅0=h0[ |E84Xomp_߾ģ8=CF-!GmNTpqHsyu !);ᖒ5E*&s^=E xS^<[yg׀sS@Ǯ`kl2#5*#FQ!ZsnÕf;{x`cN81*Ѫ}WcWcAY8[EҮpRH1,!\)d$,A" Q10cXDwXN֌&$}l!MUc;osw/x @ѯw2hD=@?3#fQϯ {Wulx 9_ 80[ gh;k"1t7a#5\"r\d!rȯG뗇ݼrGݣyrC[#٩D QJ_]߁{웎҉o00fQHHJm%&=.z%{BO?|_R\)˭ܡx\"( |&k:c& D* srpxt-ǩq>/0Գ+qbQqf`@ta(M8=ʈ*t_CoT\b +b0V^9{)-T3U}Yi"*Zq@yGTnP(Rwy$ 6 H*fKO8KvRܷ+ޝѢc ~x]P)lBq$Nx =Yݽ2ߨC`MH"KqQs  vAܔ7vxW #ߜ;$*;;>3Y<2"(e@@)!Oؼ{L_o^Fk~ JDzP 1Xḝ:m_VVl2iǥ~{U9'V%m8S(: ,<AǵCL)]H&1G/W+= ZIb~q0| "9WmdcOPRPř BYQ({ :=eB$UKMS @VxhuFܣX]9am͖W1_wF;q ֳebA7?1~3J] XxD ]\H|G{8~(K$UZhg8Z;>et@eJ1- Tuaf6c>'ߧf6'A^ ޶ņ ,{udаZbۧ>rn3(Ҍrև'G{&f50,8BA";M7HbNC gNDZ I,bݽ'h`['.@'TRJj[EQUqc^a:<.I:ROC7K HΫ=r$hY$)FV-p?X}֭GN廗j D]A+W`qhbP_|{_ҘG\`>EdL$ZHpxY>[i$w+%[<$-g&HGuD>Sy "I&cDA@!5c఼]|3į%Nr;2>3P!0'=dCj-v^k'/m𪊰^_YU @'DN B̝H*QxV:Bыi_D!G2Ao"8[R/)8"O }Ff|/"_``nYs=t$%XRF)a-K?a7l+}כZ-OO ̿K~4Q܌.v06|ˀɅi~xZc"I4?Y`g.b*fnA˭zqי> ?i2}'q,[֙GOikd]!K(ux?,h~рRaP@B'?7~&ˣ0%Н` xpR09sviv>&,]:Znk%eEX1N|3Nt|q;W'bD1'Qa{"?imQjFOhÜsޛC{=rٲU_" RiAhRGH#Zw8nnL OO9H 43ވ`F]tmt^ꏞ拾g3c֏43*a'uG$X?fY .#E` x̢fHUGg*q3$cB+d'νQڈts1\%RZ=;H:FMTYFAVyfI{{[1T4g,4ٯG f1K fq~7p2D$7~ :c4?ps^>a0xvϝBZt7H,v3+}lE-"KnDQGpZO㵉p: IL]n7^=Z [ΫhwnDqUWnz;[)fYU"Y<(0*%PG3$n (H`h+DF_׳.l62lvY*RwX];jlpH|IknE%z_h$h/nckz1<"@~<N0[!`0r:U!̩v "7/rV9{T&@">0` Mu`$c&ΰ мUl6kv^LrH{WJ6ƙ5]3OSk)4\ FE$r/7}vl >PH!8toD"?Tb}r(꽧l,$V]j3RqĊ9Z&lzҧ>R A|{8&f!!Ybݺ_F e @vG8!;d1Hd=s%N]R@ Cb!D~4cԎ(͒ ?x$L~5A-[}\+8` `.<0#!#WHR,4m lӞ^kUUFwx{=Sl1evUKoT9R?7$4&Eig r-\3+$/65B8ǎ̲,##\KFo|1AF\N2 'dp%L)![D6Tf$QËM+ӬjBgQ\.3H|5 lf UGZ^o,uI&a'#IO%<)ȍozby${`(Kc~X8VAD@.M k~ EAN:Zp~D2ۡenfA6=8u D[eLG(Gj}rmIe) L'M6І2h2g?~Q1(^iZћ!־C?zfh~;ʵ@\0/{(F6C7J! 6lC \hJ ?֙m@<T}҃X+u[,}xPaD chC) lp O<< ȍ4PHvȎ!jG2՛ޘ ^vqds‚E;x=\Mls P:=,̓~j&Q p(ئC~)tfP;(A8<9z8Jc&nd#Q1X+V۝] @[x*R~QBJ;Mw<}~Ï&6*?۸!{7:2n Er _ Q_'^%ʉ\26Dž2q~ U0=D`WbX;0,ltol6_-[}ZX=`fa&|  2=N ~NlclXF!$g? ;h )cU!þV#^_'.o5FCP8,Uu[g9 |UQ YG>, K#B stX9j{}U֟F]ˇ /_)A\,%7J~ychҴLAu ̨3 |5|juǘ~7'n.L?qgiT qrz˒ F$\]@aFW1UYdÒ~61%m1ZUTK:9;*6ArF{s?Y<`?dc'mY0乂6'|ɨJEf7+`;s؜3'#ױ?9_5Z%߉"G4U7r_?& 3_@?@'w[Z DwasTG ntv>+׉rj6 px7&&y腫VJ is'x>RH~PWVsl j@O.@߃D$ďon'QaA"!GlOVއlIYf.Ywwwsl RhQT>Et{ ~ AVqUc.*$8ԏpP"s}u"{'Dz&%@ 䐽ͽT#kًH#rdU9ҿpC?u`ںCh9S5cܛ:K/z2u];'TjUT vvP[X6Fv0#C HJ^ :Ҫl4pqh:TӁ)SxGoWGr @=r߂:jzXK3m6u=zBPcmftʼ+%/GPd"בaFF">K71PJ\"^sp{-]%5U) p,8r@xA{Xڮ MA`R*&*<g3 |H=]R !m6Ax^)vJ,lkO{e3H"K[~ū۬zsc5ܯw}i?hooUڇLw#M9oJ|.dYg=z@1z qp{m("%*UЌzJ*a߽JM~q="%#^ 9z#q1:ݾϺ߫@~s}h]5 ۛV4ÚHO2qW1@ *!B:P@rAJ vd֡*3{o{*|̙"Pΐ0Z7>;)yOL-.m6Z,=-wk''2<_/zO">{_M0Qb[^4}PR‘DbѶ<|SF8N;TF'1(n& pt"_#Y{90ުU'8#ySM,שCQ…yGB ( bHȳR B$eJduT\ $m=_i`3"DfVǑi^(gFkn7IDAT&bnapo٪H뾀xձS e2Vqf@<|x6#"&ʃ8n8[€FA%D3!"oK1%zTL| ߫U?P n W[[ "@џA&>zY,4O&ND,J8!!; S0jsA.kCV7OL<;J}8Xdu=#[yB-'J,HwX>l WcF>_*z-2wO*X49.QnwݛppK$DUDĽah~<\q>/d=c0| <$smtRubr\W=$Ϗ."̜ d&49! DUvdeP1u3zp|?; ǭN%]_25W"]FEծ9RCf8!͗pkJvݙ~1`!K [@!#*HŌF)k]- @_'JNc?'mH'C@ҹf"ɜ}+9 1 r;ΡIyv} ,]ݾ Ĭ- <Tb ܯ]Uvk Mea*+Ek˜&3ɛ-pB `[>8"m,~_FZdO$C&%D8L'7^ A\oܯwuD$29#ea"^"0z;fvɕqw'L~ Ÿ0lj@1꠽w{Ewǹ_xl'o? 2DF(/|]}`O?_c,D)xr.AENU;cg%'jM aܞ@ʿFSIENDB`is32ؗZU(xYPgʸ]k2>Á\VIxn"~a phFu? =gF/g. 6oamV7 (Y}e/R|)h'ȋ [>6N>d^:H k~V..Hzv4<)}uT12/gotxK@PSXngtN< FWd=&wEqt\& '^<)l_=pxi !A8ciA2av|# 8K83wvP<V}V  V3# ,     s8mkǯY~(  {gGP 8I n_|WD+il32  _ǣ|*ʼՃ εʰ˕YY ^ʯɼg`h6 %DZσXc^b ʲƯƪYd_a` _׮n\c\i2 5ɽƮƔWe]eS õsbb^g" ˫mo]eDʒrufbCoçˆ~swCǤIÈzu@(_y[5L'3WƗ6µ}Q391z[ʦVgbHCHR=fmeƽMnZec\PUjw_sʥ Xi\\S`xRKž0tvdpceiC#9 Lga@FɎ9k]]f,)-g``@RW+`C= +?IH9+\AICLGFG9 ?P,=heo]xySjmuh*4 ;ow85: ~roU-947 flvy-9566 251WnrO7I1,vnry{cIH8Ctpb89<$lpqsy~$ 1j;6".xkun]$>45:Sxltpy<78mrlv_%14upq9$% uW"()!7"(%* )'(!$,                  l8mkT=B)&#P7y5|6 w oXk{B% !{7*FnRP& y(Ig,,keeG$2)rDuA*:-S"s;ic11PNG  IHDR szzsRGBeIDATX W[l>矙ػ+1P"lMxH^"DjJIJE*Jyk)JV%!4jc`lem{ߝ ihgv.ws%z‚?d$]OAi$jE*7(|Rg)p9y`P D!Dc=uœ'bn{U9kRʿ >Y+1`\_\|WP%m%ޖR|Æd]K0׆6>dsX}6itf+Qe3ƧVKYb>Pm|0`Pxo0XW*!r&*#3T!vq CI;>;qCZ2WtK*R&sA.ٝ0P ;7=둈PnfG"pG4ӧcujjb9ݭqpKYZAGLE2+Pou'4P^J&XZ}`yP(zM>X{T[TJYf"GTR0SUjxL.C$/瘮̪`+!}$f𼱼/߂QJ$zͺAeNlE/Y 5=:b-/n6hH0^DΨKxUfp,:]-!iD׮wVO>O<:JNQ6-f?7F&ju F59T#)AEyQ=,0On?LrVI+!Qgq<HRmL44N4IڴȘo Җ ,m#!דT#+_!$uq(Ϣ6 * =d"g1bEn]Eb{׳yG0S*JcE;cYprP]Y Nś:5 _O&.ZXݧRUѲ$h+WYtވBDEG}+D摠BȐ`i_z![يaYND;b4 o5Π{*Q=,!R +Բv ӿd;xk^~]E{dJK9G,sGS@<:\*Gt Sop=0iLO_Ÿw3 h^2W{iNhgOMҕlY4#F}=V+Ay$#*pXl$a|s"iDu{=:F Ն:TTɥ޼y{iBiFw0fkȥ ]ؾ[URUHgRte ]8W[3&@qE\z̀,Vg|MK1N1(uf)A`c,cl۵!V2$.g?鲰\O~cς ~F' *0s&SPfbsgjqvPzbM̈́v=Iux(cqRE]Is{(Ǡ_ @| B^,;sTSgɹB6:w@nOoVɱi>gXXŌt* !3]Oh9up+:{A>3 *nKQr꒣#:qm JP &'-+ڸGo'u2*XmSeFWMqb*C^wBs@Vt Ģxxocpxb>l`qm rG¤CIENDB`info bplist00X$versionX$objectsY$archiverT$topU$null WNS.keysZNS.objectsV$class TnameTiconZ$classnameX$classes\NSDictionaryXNSObject_NSKeyedArchiverTroot#-27=CJR]dfhjlnsx}stella-5.1.1/src/macosx/stella.xcodeproj/000077500000000000000000000000001324334165500203515ustar00rootroot00000000000000stella-5.1.1/src/macosx/stella.xcodeproj/project.pbxproj000066400000000000000000010574111324334165500234360ustar00rootroot00000000000000// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 2D9173CB09BA90380026E9FF /* SDLMain.h in Headers */ = {isa = PBXBuildFile; fileRef = F5A47A9D01A0482F01D3D55B /* SDLMain.h */; }; 2D9173CC09BA90380026E9FF /* Booster.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF110627AE07006BEC99 /* Booster.hxx */; }; 2D9173CD09BA90380026E9FF /* Cart.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF130627AE07006BEC99 /* Cart.hxx */; }; 2D9173CE09BA90380026E9FF /* Cart2K.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF150627AE07006BEC99 /* Cart2K.hxx */; }; 2D9173CF09BA90380026E9FF /* Cart3F.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF170627AE07006BEC99 /* Cart3F.hxx */; }; 2D9173D009BA90380026E9FF /* Cart4K.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF190627AE07006BEC99 /* Cart4K.hxx */; }; 2D9173D109BA90380026E9FF /* CartAR.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF1B0627AE07006BEC99 /* CartAR.hxx */; }; 2D9173D209BA90380026E9FF /* CartCV.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF1D0627AE07006BEC99 /* CartCV.hxx */; }; 2D9173D309BA90380026E9FF /* CartDPC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF1F0627AE07006BEC99 /* CartDPC.hxx */; }; 2D9173D409BA90380026E9FF /* CartE0.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF210627AE07006BEC99 /* CartE0.hxx */; }; 2D9173D509BA90380026E9FF /* CartE7.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF230627AE07006BEC99 /* CartE7.hxx */; }; 2D9173D609BA90380026E9FF /* CartF4.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF250627AE07006BEC99 /* CartF4.hxx */; }; 2D9173D709BA90380026E9FF /* CartF4SC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF270627AE07006BEC99 /* CartF4SC.hxx */; }; 2D9173D809BA90380026E9FF /* CartF6.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF290627AE07006BEC99 /* CartF6.hxx */; }; 2D9173D909BA90380026E9FF /* CartF6SC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF2B0627AE07006BEC99 /* CartF6SC.hxx */; }; 2D9173DA09BA90380026E9FF /* CartF8.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF2D0627AE07006BEC99 /* CartF8.hxx */; }; 2D9173DB09BA90380026E9FF /* CartF8SC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF2F0627AE07006BEC99 /* CartF8SC.hxx */; }; 2D9173DD09BA90380026E9FF /* CartFE.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF330627AE07006BEC99 /* CartFE.hxx */; }; 2D9173E009BA90380026E9FF /* Console.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF390627AE07006BEC99 /* Console.hxx */; }; 2D9173E109BA90380026E9FF /* Control.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF3B0627AE07006BEC99 /* Control.hxx */; }; 2D9173E309BA90380026E9FF /* Driving.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF3F0627AE07006BEC99 /* Driving.hxx */; }; 2D9173E409BA90380026E9FF /* Event.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF410627AE07006BEC99 /* Event.hxx */; }; 2D9173E509BA90380026E9FF /* Joystick.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF430627AE07006BEC99 /* Joystick.hxx */; }; 2D9173E609BA90380026E9FF /* Keyboard.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF450627AE07006BEC99 /* Keyboard.hxx */; }; 2D9173E709BA90380026E9FF /* M6532.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF7D0627AE33006BEC99 /* M6532.hxx */; }; 2D9173E809BA90380026E9FF /* MD5.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF7F0627AE34006BEC99 /* MD5.hxx */; }; 2D9173EA09BA90380026E9FF /* Paddles.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF830627AE34006BEC99 /* Paddles.hxx */; }; 2D9173EB09BA90380026E9FF /* Props.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF850627AE34006BEC99 /* Props.hxx */; }; 2D9173EC09BA90380026E9FF /* PropsSet.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF870627AE34006BEC99 /* PropsSet.hxx */; }; 2D9173ED09BA90380026E9FF /* Random.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF890627AE34006BEC99 /* Random.hxx */; }; 2D9173EE09BA90380026E9FF /* Serializer.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF8B0627AE34006BEC99 /* Serializer.hxx */; }; 2D9173EF09BA90380026E9FF /* Sound.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF8D0627AE34006BEC99 /* Sound.hxx */; }; 2D9173F009BA90380026E9FF /* Switches.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE2DF8F0627AE34006BEC99 /* Switches.hxx */; }; 2D9173F909BA90380026E9FF /* EventHandler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D6F062895B2006265D9 /* EventHandler.hxx */; }; 2D9173FA09BA90380026E9FF /* FrameBuffer.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D71062895B2006265D9 /* FrameBuffer.hxx */; }; 2D9173FB09BA90380026E9FF /* Settings.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D733D77062895F1006265D9 /* Settings.hxx */; }; 2D9173FC09BA90380026E9FF /* SettingsMACOSX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D94486C0629124700DD9879 /* SettingsMACOSX.hxx */; }; 2D9173FF09BA90380026E9FF /* OSystemMACOSX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEA0F0845709700812C11 /* OSystemMACOSX.hxx */; }; 2D91740009BA90380026E9FF /* AboutDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */; }; 2D91740109BA90380026E9FF /* AudioDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */; }; 2D91740209BA90380026E9FF /* BrowserDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */; }; 2D91740309BA90380026E9FF /* Command.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAAA084578BF00812C11 /* Command.hxx */; }; 2D91740409BA90380026E9FF /* Dialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAAC084578BF00812C11 /* Dialog.hxx */; }; 2D91740509BA90380026E9FF /* DialogContainer.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAAE084578BF00812C11 /* DialogContainer.hxx */; }; 2D91740609BA90380026E9FF /* GameInfoDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAB3084578BF00812C11 /* GameInfoDialog.hxx */; }; 2D91740709BA90380026E9FF /* GameList.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAB5084578BF00812C11 /* GameList.hxx */; }; 2D91740809BA90380026E9FF /* GuiObject.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAB6084578BF00812C11 /* GuiObject.hxx */; }; 2D91740A09BA90380026E9FF /* HelpDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAB9084578BF00812C11 /* HelpDialog.hxx */; }; 2D91740B09BA90380026E9FF /* Launcher.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEABB084578BF00812C11 /* Launcher.hxx */; }; 2D91740C09BA90380026E9FF /* LauncherDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEABD084578BF00812C11 /* LauncherDialog.hxx */; }; 2D91740E09BA90380026E9FF /* ListWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAC1084578BF00812C11 /* ListWidget.hxx */; }; 2D91740F09BA90380026E9FF /* Menu.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAC3084578BF00812C11 /* Menu.hxx */; }; 2D91741009BA90380026E9FF /* OptionsDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAC5084578BF00812C11 /* OptionsDialog.hxx */; }; 2D91741109BA90380026E9FF /* PopUpWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAC7084578BF00812C11 /* PopUpWidget.hxx */; }; 2D91741209BA90380026E9FF /* ProgressDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAC9084578BF00812C11 /* ProgressDialog.hxx */; }; 2D91741309BA90380026E9FF /* ScrollBarWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */; }; 2D91741609BA90380026E9FF /* TabWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */; }; 2D91741709BA90380026E9FF /* VideoDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */; }; 2D91741809BA90380026E9FF /* Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEAD5084578BF00812C11 /* Widget.hxx */; }; 2D91741909BA90380026E9FF /* CartUA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEB7108457B7D00812C11 /* CartUA.hxx */; }; 2D91741A09BA90380026E9FF /* FSNode.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEB7308457B7D00812C11 /* FSNode.hxx */; }; 2D91741B09BA90380026E9FF /* OSystem.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEB7508457B7D00812C11 /* OSystem.hxx */; }; 2D91741D09BA90380026E9FF /* Preferences.h in Headers */ = {isa = PBXBuildFile; fileRef = 2DDBEBE3084582C400812C11 /* Preferences.h */; }; 2D91741F09BA90380026E9FF /* AboutBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D1A6CD4085135F9007CDBA8 /* AboutBox.h */; }; 2D91742009BA90380026E9FF /* ConsoleFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D9217FA0857CC88001D664B /* ConsoleFont.hxx */; }; 2D91742109BA90380026E9FF /* Font.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D9217FC0857CC88001D664B /* Font.hxx */; }; 2D91742209BA90380026E9FF /* Debugger.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D659E2E085D3DD6005D96C8 /* Debugger.hxx */; }; 2D91742309BA90380026E9FF /* DebuggerParser.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D659E32085D3DD6005D96C8 /* DebuggerParser.hxx */; }; 2D91742409BA90380026E9FF /* EditableWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D403BA1086116D1001E31A1 /* EditableWidget.hxx */; }; 2D91742509BA90380026E9FF /* EditTextWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D403BA5086116D1001E31A1 /* EditTextWidget.hxx */; }; 2D91742809BA90380026E9FF /* PackedBitArray.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D403BCF08611A69001E31A1 /* PackedBitArray.hxx */; }; 2D91742909BA90380026E9FF /* TIADebug.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D30F8760868A4DB00938B9D /* TIADebug.hxx */; }; 2D91742A09BA90380026E9FF /* YaccParser.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D313F0B0879C4C0005BD3E5 /* YaccParser.hxx */; }; 2D91742B09BA90380026E9FF /* Cart3E.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D9555DA0880E78000466554 /* Cart3E.hxx */; }; 2D91742C09BA90380026E9FF /* CpuDebug.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D9555DE0880E79600466554 /* CpuDebug.hxx */; }; 2D91743609BA90380026E9FF /* DebuggerSystem.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DF971D70892CEA400F64D23 /* DebuggerSystem.hxx */; }; 2D91743A09BA90380026E9FF /* Expression.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DF971DF0892CEA400F64D23 /* Expression.hxx */; }; 2D91744F09BA90380026E9FF /* InputTextDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D02208008A301F200B9C76B /* InputTextDialog.hxx */; }; 2D91745009BA90380026E9FF /* CheckListWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DEF21F908BC033500B246B4 /* CheckListWidget.hxx */; }; 2D91745109BA90380026E9FF /* StringListWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DEF21FB08BC033500B246B4 /* StringListWidget.hxx */; }; 2D91745209BA90380026E9FF /* CommandDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D73959408C3EB4E0060BB99 /* CommandDialog.hxx */; }; 2D91745309BA90380026E9FF /* CommandMenu.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D73959608C3EB4E0060BB99 /* CommandMenu.hxx */; }; 2D91745509BA90380026E9FF /* CpuWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9E708C603EC00A73076 /* CpuWidget.hxx */; }; 2D91745609BA90380026E9FF /* DataGridOpsWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9E908C603EC00A73076 /* DataGridOpsWidget.hxx */; }; 2D91745709BA90380026E9FF /* DataGridWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9EB08C603EC00A73076 /* DataGridWidget.hxx */; }; 2D91745809BA90380026E9FF /* DebuggerDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9ED08C603EC00A73076 /* DebuggerDialog.hxx */; }; 2D91745909BA90380026E9FF /* PromptWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9EF08C603EC00A73076 /* PromptWidget.hxx */; }; 2D91745A09BA90380026E9FF /* RamWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9F108C603EC00A73076 /* RamWidget.hxx */; }; 2D91745B09BA90380026E9FF /* RomListWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9F308C603EC00A73076 /* RomListWidget.hxx */; }; 2D91745C09BA90380026E9FF /* RomWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9F508C603EC00A73076 /* RomWidget.hxx */; }; 2D91745D09BA90380026E9FF /* TiaInfoWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9F708C603EC00A73076 /* TiaInfoWidget.hxx */; }; 2D91745E09BA90380026E9FF /* TiaOutputWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9F908C603EC00A73076 /* TiaOutputWidget.hxx */; }; 2D91745F09BA90380026E9FF /* TiaWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9FB08C603EC00A73076 /* TiaWidget.hxx */; }; 2D91746009BA90380026E9FF /* ToggleBitWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9FD08C603EC00A73076 /* ToggleBitWidget.hxx */; }; 2D91746109BA90380026E9FF /* TogglePixelWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20F9FF08C603EC00A73076 /* TogglePixelWidget.hxx */; }; 2D91746209BA90380026E9FF /* ToggleWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D20FA0108C603EC00A73076 /* ToggleWidget.hxx */; }; 2D91746409BA90380026E9FF /* TiaZoomWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D6CC10408C811A600B8F642 /* TiaZoomWidget.hxx */; }; 2D91746509BA90380026E9FF /* TIASnd.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2DE7242E08CE910900C889A8 /* TIASnd.hxx */; }; 2D91746609BA90380026E9FF /* AudioWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D2331900900B5EF00613B1F /* AudioWidget.hxx */; }; 2D91746909BA90380026E9FF /* EventMappingWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D05FF5F096E269100A518FE /* EventMappingWidget.hxx */; }; 2D91746A09BA90380026E9FF /* InputDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = 2D05FF61096E269100A518FE /* InputDialog.hxx */; }; 2D91746E09BA90380026E9FF /* SDLMain.nib in Resources */ = {isa = PBXBuildFile; fileRef = B2F367C504C7ADC700A80002 /* SDLMain.nib */; }; 2D91746F09BA90380026E9FF /* Stella.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2D16A8E106324136005DF364 /* Stella.icns */; }; 2D91747009BA90380026E9FF /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = 2D7B4F6C063B513200579B93 /* Credits.html */; }; 2D91747109BA90380026E9FF /* docs in Resources */ = {isa = PBXBuildFile; fileRef = 2D113E090672BF2100317017 /* docs */; }; 2D91747209BA90380026E9FF /* AboutBox.nib in Resources */ = {isa = PBXBuildFile; fileRef = 2D1A6CD808513610007CDBA8 /* AboutBox.nib */; }; 2D91747409BA90380026E9FF /* SDLMain.m in Sources */ = {isa = PBXBuildFile; fileRef = F5A47A9E01A0483001D3D55B /* SDLMain.m */; }; 2D91747509BA90380026E9FF /* Booster.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF100627AE07006BEC99 /* Booster.cxx */; }; 2D91747609BA90380026E9FF /* Cart.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF120627AE07006BEC99 /* Cart.cxx */; }; 2D91747709BA90380026E9FF /* Cart2K.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF140627AE07006BEC99 /* Cart2K.cxx */; }; 2D91747809BA90380026E9FF /* Cart3F.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF160627AE07006BEC99 /* Cart3F.cxx */; }; 2D91747909BA90380026E9FF /* Cart4K.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF180627AE07006BEC99 /* Cart4K.cxx */; }; 2D91747A09BA90380026E9FF /* CartAR.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF1A0627AE07006BEC99 /* CartAR.cxx */; }; 2D91747B09BA90380026E9FF /* CartCV.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */; }; 2D91747C09BA90380026E9FF /* CartDPC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF1E0627AE07006BEC99 /* CartDPC.cxx */; }; 2D91747D09BA90380026E9FF /* CartE0.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF200627AE07006BEC99 /* CartE0.cxx */; }; 2D91747E09BA90380026E9FF /* CartE7.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF220627AE07006BEC99 /* CartE7.cxx */; }; 2D91747F09BA90380026E9FF /* CartF4.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF240627AE07006BEC99 /* CartF4.cxx */; }; 2D91748009BA90380026E9FF /* CartF4SC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF260627AE07006BEC99 /* CartF4SC.cxx */; }; 2D91748109BA90380026E9FF /* CartF6.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF280627AE07006BEC99 /* CartF6.cxx */; }; 2D91748209BA90380026E9FF /* CartF6SC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF2A0627AE07006BEC99 /* CartF6SC.cxx */; }; 2D91748309BA90380026E9FF /* CartF8.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF2C0627AE07006BEC99 /* CartF8.cxx */; }; 2D91748409BA90380026E9FF /* CartF8SC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF2E0627AE07006BEC99 /* CartF8SC.cxx */; }; 2D91748609BA90380026E9FF /* CartFE.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF320627AE07006BEC99 /* CartFE.cxx */; }; 2D91748909BA90380026E9FF /* Console.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF380627AE07006BEC99 /* Console.cxx */; }; 2D91748A09BA90380026E9FF /* Control.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF3A0627AE07006BEC99 /* Control.cxx */; }; 2D91748C09BA90380026E9FF /* Driving.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF3E0627AE07006BEC99 /* Driving.cxx */; }; 2D91748E09BA90380026E9FF /* Joystick.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF420627AE07006BEC99 /* Joystick.cxx */; }; 2D91748F09BA90380026E9FF /* Keyboard.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF440627AE07006BEC99 /* Keyboard.cxx */; }; 2D91749009BA90380026E9FF /* M6532.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF7C0627AE33006BEC99 /* M6532.cxx */; }; 2D91749109BA90380026E9FF /* MD5.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF7E0627AE33006BEC99 /* MD5.cxx */; }; 2D91749309BA90380026E9FF /* Paddles.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF820627AE34006BEC99 /* Paddles.cxx */; }; 2D91749409BA90380026E9FF /* Props.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF840627AE34006BEC99 /* Props.cxx */; }; 2D91749509BA90380026E9FF /* PropsSet.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF860627AE34006BEC99 /* PropsSet.cxx */; }; 2D91749709BA90380026E9FF /* Serializer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF8A0627AE34006BEC99 /* Serializer.cxx */; }; 2D91749809BA90380026E9FF /* Switches.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */; }; 2D9174A109BA90380026E9FF /* EventHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D733D6E062895B2006265D9 /* EventHandler.cxx */; }; 2D9174A209BA90380026E9FF /* FrameBuffer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D733D70062895B2006265D9 /* FrameBuffer.cxx */; }; 2D9174A309BA90380026E9FF /* Settings.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D944848062904E800DD9879 /* Settings.cxx */; }; 2D9174A409BA90380026E9FF /* SettingsMACOSX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D944866062911CD00DD9879 /* SettingsMACOSX.cxx */; }; 2D9174A809BA90380026E9FF /* FSNodePOSIX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */; }; 2D9174A909BA90380026E9FF /* OSystemMACOSX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEA0E0845709700812C11 /* OSystemMACOSX.cxx */; }; 2D9174AA09BA90380026E9FF /* AboutDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */; }; 2D9174AB09BA90380026E9FF /* AudioDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */; }; 2D9174AC09BA90380026E9FF /* BrowserDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */; }; 2D9174AD09BA90380026E9FF /* Dialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAAB084578BF00812C11 /* Dialog.cxx */; }; 2D9174AE09BA90380026E9FF /* DialogContainer.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAAD084578BF00812C11 /* DialogContainer.cxx */; }; 2D9174AF09BA90380026E9FF /* GameInfoDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAB2084578BF00812C11 /* GameInfoDialog.cxx */; }; 2D9174B009BA90380026E9FF /* GameList.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAB4084578BF00812C11 /* GameList.cxx */; }; 2D9174B109BA90380026E9FF /* HelpDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAB8084578BF00812C11 /* HelpDialog.cxx */; }; 2D9174B209BA90380026E9FF /* Launcher.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEABA084578BF00812C11 /* Launcher.cxx */; }; 2D9174B309BA90380026E9FF /* LauncherDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEABC084578BF00812C11 /* LauncherDialog.cxx */; }; 2D9174B509BA90380026E9FF /* ListWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAC0084578BF00812C11 /* ListWidget.cxx */; }; 2D9174B609BA90380026E9FF /* Menu.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAC2084578BF00812C11 /* Menu.cxx */; }; 2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAC4084578BF00812C11 /* OptionsDialog.cxx */; }; 2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAC6084578BF00812C11 /* PopUpWidget.cxx */; }; 2D9174B909BA90380026E9FF /* ProgressDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAC8084578BF00812C11 /* ProgressDialog.cxx */; }; 2D9174BA09BA90380026E9FF /* ScrollBarWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEACA084578BF00812C11 /* ScrollBarWidget.cxx */; }; 2D9174BB09BA90380026E9FF /* TabWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */; }; 2D9174BC09BA90380026E9FF /* VideoDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */; }; 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEAD4084578BF00812C11 /* Widget.cxx */; }; 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEB7008457B7D00812C11 /* CartUA.cxx */; }; 2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEB7208457B7D00812C11 /* FSNode.cxx */; }; 2D9174C009BA90380026E9FF /* OSystem.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEB7408457B7D00812C11 /* OSystem.cxx */; }; 2D9174C209BA90380026E9FF /* Preferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 2DDBEBE4084582C400812C11 /* Preferences.m */; }; 2D9174C409BA90380026E9FF /* AboutBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D1A6CD5085135F9007CDBA8 /* AboutBox.m */; }; 2D9174C509BA90380026E9FF /* Font.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D9217FB0857CC88001D664B /* Font.cxx */; }; 2D9174C609BA90380026E9FF /* Debugger.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D659E2D085D3DD6005D96C8 /* Debugger.cxx */; }; 2D9174C709BA90380026E9FF /* DebuggerParser.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D659E31085D3DD6005D96C8 /* DebuggerParser.cxx */; }; 2D9174C809BA90380026E9FF /* EditableWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D403BA0086116D1001E31A1 /* EditableWidget.cxx */; }; 2D9174C909BA90380026E9FF /* EditTextWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D403BA4086116D1001E31A1 /* EditTextWidget.cxx */; }; 2D9174CC09BA90380026E9FF /* TIADebug.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D30F8750868A4DB00938B9D /* TIADebug.cxx */; }; 2D9174CD09BA90380026E9FF /* YaccParser.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D313F0A0879C4C0005BD3E5 /* YaccParser.cxx */; }; 2D9174CE09BA90380026E9FF /* Cart3E.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D9555D90880E78000466554 /* Cart3E.cxx */; }; 2D9174CF09BA90380026E9FF /* CpuDebug.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D9555DD0880E79600466554 /* CpuDebug.cxx */; }; 2D9174F109BA90380026E9FF /* InputTextDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D02207F08A301F200B9C76B /* InputTextDialog.cxx */; }; 2D9174F209BA90380026E9FF /* CheckListWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DEF21F808BC033500B246B4 /* CheckListWidget.cxx */; }; 2D9174F309BA90380026E9FF /* StringListWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DEF21FA08BC033500B246B4 /* StringListWidget.cxx */; }; 2D9174F409BA90380026E9FF /* CommandDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D73959308C3EB4E0060BB99 /* CommandDialog.cxx */; }; 2D9174F509BA90380026E9FF /* CommandMenu.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D73959508C3EB4E0060BB99 /* CommandMenu.cxx */; }; 2D9174F709BA90380026E9FF /* CpuWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9E608C603EC00A73076 /* CpuWidget.cxx */; }; 2D9174F809BA90380026E9FF /* DataGridOpsWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9E808C603EC00A73076 /* DataGridOpsWidget.cxx */; }; 2D9174F909BA90380026E9FF /* DataGridWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9EA08C603EC00A73076 /* DataGridWidget.cxx */; }; 2D9174FA09BA90380026E9FF /* DebuggerDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9EC08C603EC00A73076 /* DebuggerDialog.cxx */; }; 2D9174FB09BA90380026E9FF /* PromptWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9EE08C603EC00A73076 /* PromptWidget.cxx */; }; 2D9174FC09BA90380026E9FF /* RamWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9F008C603EC00A73076 /* RamWidget.cxx */; }; 2D9174FD09BA90380026E9FF /* RomListWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9F208C603EC00A73076 /* RomListWidget.cxx */; }; 2D9174FE09BA90380026E9FF /* RomWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9F408C603EC00A73076 /* RomWidget.cxx */; }; 2D9174FF09BA90380026E9FF /* TiaInfoWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9F608C603EC00A73076 /* TiaInfoWidget.cxx */; }; 2D91750009BA90380026E9FF /* TiaOutputWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9F808C603EC00A73076 /* TiaOutputWidget.cxx */; }; 2D91750109BA90380026E9FF /* TiaWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9FA08C603EC00A73076 /* TiaWidget.cxx */; }; 2D91750209BA90380026E9FF /* ToggleBitWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9FC08C603EC00A73076 /* ToggleBitWidget.cxx */; }; 2D91750309BA90380026E9FF /* TogglePixelWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20F9FE08C603EC00A73076 /* TogglePixelWidget.cxx */; }; 2D91750409BA90380026E9FF /* ToggleWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D20FA0008C603EC00A73076 /* ToggleWidget.cxx */; }; 2D91750609BA90380026E9FF /* TiaZoomWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D6CC10308C811A600B8F642 /* TiaZoomWidget.cxx */; }; 2D91750709BA90380026E9FF /* TIASnd.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2DE7242D08CE910900C889A8 /* TIASnd.cxx */; }; 2D91750809BA90380026E9FF /* AudioWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D23318F0900B5EF00613B1F /* AudioWidget.cxx */; }; 2D91750B09BA90380026E9FF /* EventMappingWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D05FF5E096E269100A518FE /* EventMappingWidget.cxx */; }; 2D91750C09BA90380026E9FF /* InputDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = 2D05FF60096E269100A518FE /* InputDialog.cxx */; }; 2D91750F09BA90380026E9FF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 2D91751009BA90380026E9FF /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */; }; 2D91751209BA90380026E9FF /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */; }; 2DEFB40C09C3386F00754289 /* Cart.icns in Resources */ = {isa = PBXBuildFile; fileRef = 2DEFB40B09C3386F00754289 /* Cart.icns */; }; 55FE2A321EE4856B00078ADE /* SDL2.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCDAF4D818CA9AAB00D3865D /* SDL2.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 55FE2A501EE4880500078ADE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 55FE2A3C1EE487CA00078ADE /* InfoPlist.strings */; }; CFE3F60B1E84A9A200A8204E /* CartBUSWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CFE3F6071E84A9A200A8204E /* CartBUSWidget.cxx */; }; CFE3F60C1E84A9A200A8204E /* CartBUSWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F6081E84A9A200A8204E /* CartBUSWidget.hxx */; }; CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CFE3F6091E84A9A200A8204E /* CartCDFWidget.cxx */; }; CFE3F60E1E84A9A200A8204E /* CartCDFWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F60A1E84A9A200A8204E /* CartCDFWidget.hxx */; }; CFE3F6131E84A9CE00A8204E /* CartBUS.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CFE3F60F1E84A9CE00A8204E /* CartBUS.cxx */; }; CFE3F6141E84A9CE00A8204E /* CartBUS.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F6101E84A9CE00A8204E /* CartBUS.hxx */; }; CFE3F6151E84A9CE00A8204E /* CartCDF.cxx in Sources */ = {isa = PBXBuildFile; fileRef = CFE3F6111E84A9CE00A8204E /* CartCDF.cxx */; }; CFE3F6161E84A9CE00A8204E /* CartCDF.hxx in Headers */ = {isa = PBXBuildFile; fileRef = CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */; }; DC047FEE1A4A6F3600348F0F /* JoystickDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC047FEC1A4A6F3600348F0F /* JoystickDialog.cxx */; }; DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */; }; DC0984850D3985160073C852 /* CartSB.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0984830D3985160073C852 /* CartSB.cxx */; }; DC0984860D3985160073C852 /* CartSB.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0984840D3985160073C852 /* CartSB.hxx */; }; DC0DF8690F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC0DF8670F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx */; }; DC0DF86A0F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC0DF8680F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx */; }; DC11F78D0DB36933003B505E /* MT24LC256.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC11F78B0DB36933003B505E /* MT24LC256.cxx */; }; DC11F78E0DB36933003B505E /* MT24LC256.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC11F78C0DB36933003B505E /* MT24LC256.hxx */; }; DC13B53F176FF2F500B8B4BB /* RomListSettings.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC13B53D176FF2F500B8B4BB /* RomListSettings.cxx */; }; DC13B540176FF2F500B8B4BB /* RomListSettings.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC13B53E176FF2F500B8B4BB /* RomListSettings.hxx */; }; DC173F760E2CAC1E00320F94 /* ContextMenu.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */; }; DC173F770E2CAC1E00320F94 /* ContextMenu.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC173F750E2CAC1E00320F94 /* ContextMenu.hxx */; }; DC1B2EC41E50036100F62837 /* AmigaMouse.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EBE1E50036100F62837 /* AmigaMouse.hxx */; }; DC1B2EC61E50036100F62837 /* AtariMouse.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EC01E50036100F62837 /* AtariMouse.hxx */; }; DC1B2EC81E50036100F62837 /* TrakBall.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1B2EC21E50036100F62837 /* TrakBall.hxx */; }; DC1FC18A0DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */; }; DC1FC18B0DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */; }; DC2874071F8F2278004BF21A /* TrapArray.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2874061F8F2278004BF21A /* TrapArray.hxx */; }; DC2AADAE194F389C0026C7A4 /* CartDASH.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */; }; DC2AADAF194F389C0026C7A4 /* CartDASH.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */; }; DC2AADB0194F389C0026C7A4 /* TIASurface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADAC194F389C0026C7A4 /* TIASurface.cxx */; }; DC2AADB1194F389C0026C7A4 /* TIASurface.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2AADAD194F389C0026C7A4 /* TIASurface.hxx */; }; DC2AADB4194F390F0026C7A4 /* CartRamWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2AADB2194F390F0026C7A4 /* CartRamWidget.cxx */; }; DC2AADB5194F390F0026C7A4 /* CartRamWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2AADB3194F390F0026C7A4 /* CartRamWidget.hxx */; }; DC2B85E71EF5EF2300379EB9 /* AtariNTSC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC2B85E51EF5EF2300379EB9 /* AtariNTSC.cxx */; }; DC2B85E81EF5EF2300379EB9 /* AtariNTSC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2B85E61EF5EF2300379EB9 /* AtariNTSC.hxx */; }; DC2C5EDB1F8F2403007D2A09 /* smartmod.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC2C5EDA1F8F2403007D2A09 /* smartmod.hxx */; }; DC368F5618A2FB710084199C /* FrameBufferSDL2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC368F5018A2FB710084199C /* FrameBufferSDL2.cxx */; }; DC368F5718A2FB710084199C /* FrameBufferSDL2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC368F5118A2FB710084199C /* FrameBufferSDL2.hxx */; }; DC368F5818A2FB710084199C /* SoundSDL2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC368F5218A2FB710084199C /* SoundSDL2.cxx */; }; DC368F5918A2FB710084199C /* SoundSDL2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC368F5318A2FB710084199C /* SoundSDL2.hxx */; }; DC36D2C814CAFAB0007DC821 /* CartFA2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */; }; DC36D2C914CAFAB0007DC821 /* CartFA2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */; }; DC3DAFAC1F2E233B00A64410 /* PointingDevice.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */; }; DC3EE8561E2C0E6D00905161 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83C1E2C0E6D00905161 /* adler32.c */; }; DC3EE8571E2C0E6D00905161 /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83D1E2C0E6D00905161 /* compress.c */; }; DC3EE8581E2C0E6D00905161 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE83E1E2C0E6D00905161 /* crc32.c */; }; DC3EE8591E2C0E6D00905161 /* crc32.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE83F1E2C0E6D00905161 /* crc32.h */; }; DC3EE85A1E2C0E6D00905161 /* deflate.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8401E2C0E6D00905161 /* deflate.c */; settings = {COMPILER_FLAGS = "-Wno-conversion"; }; }; DC3EE85B1E2C0E6D00905161 /* deflate.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE8411E2C0E6D00905161 /* deflate.h */; }; DC3EE85C1E2C0E6D00905161 /* gzclose.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8421E2C0E6D00905161 /* gzclose.c */; }; DC3EE85D1E2C0E6D00905161 /* gzguts.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE8431E2C0E6D00905161 /* gzguts.h */; }; DC3EE85E1E2C0E6D00905161 /* gzlib.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8441E2C0E6D00905161 /* gzlib.c */; }; DC3EE85F1E2C0E6D00905161 /* gzread.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8451E2C0E6D00905161 /* gzread.c */; settings = {COMPILER_FLAGS = "-Wno-conversion"; }; }; DC3EE8601E2C0E6D00905161 /* gzwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8461E2C0E6D00905161 /* gzwrite.c */; settings = {COMPILER_FLAGS = "-Wno-conversion"; }; }; DC3EE8611E2C0E6D00905161 /* infback.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8471E2C0E6D00905161 /* infback.c */; }; DC3EE8621E2C0E6D00905161 /* inffast.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8481E2C0E6D00905161 /* inffast.c */; }; DC3EE8631E2C0E6D00905161 /* inffast.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE8491E2C0E6D00905161 /* inffast.h */; }; DC3EE8641E2C0E6D00905161 /* inffixed.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE84A1E2C0E6D00905161 /* inffixed.h */; }; DC3EE8651E2C0E6D00905161 /* inflate.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE84B1E2C0E6D00905161 /* inflate.c */; }; DC3EE8661E2C0E6D00905161 /* inflate.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE84C1E2C0E6D00905161 /* inflate.h */; }; DC3EE8671E2C0E6D00905161 /* inftrees.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE84D1E2C0E6D00905161 /* inftrees.c */; }; DC3EE8681E2C0E6D00905161 /* inftrees.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE84E1E2C0E6D00905161 /* inftrees.h */; }; DC3EE8691E2C0E6D00905161 /* trees.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE84F1E2C0E6D00905161 /* trees.c */; }; DC3EE86A1E2C0E6D00905161 /* trees.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE8501E2C0E6D00905161 /* trees.h */; }; DC3EE86B1E2C0E6D00905161 /* uncompr.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8511E2C0E6D00905161 /* uncompr.c */; }; DC3EE86C1E2C0E6D00905161 /* zconf.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE8521E2C0E6D00905161 /* zconf.h */; }; DC3EE86D1E2C0E6D00905161 /* zlib.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE8531E2C0E6D00905161 /* zlib.h */; }; DC3EE86E1E2C0E6D00905161 /* zutil.c in Sources */ = {isa = PBXBuildFile; fileRef = DC3EE8541E2C0E6D00905161 /* zutil.c */; }; DC3EE86F1E2C0E6D00905161 /* zutil.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3EE8551E2C0E6D00905161 /* zutil.h */; }; DC44019E1F1A5D01008C08F6 /* ColorWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC44019C1F1A5D01008C08F6 /* ColorWidget.cxx */; }; DC44019F1F1A5D01008C08F6 /* ColorWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC44019D1F1A5D01008C08F6 /* ColorWidget.hxx */; }; DC4613670D92C03600D8DAB9 /* RomAuditDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC4613650D92C03600D8DAB9 /* RomAuditDialog.cxx */; }; DC4613680D92C03600D8DAB9 /* RomAuditDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC4613660D92C03600D8DAB9 /* RomAuditDialog.hxx */; }; DC47455509C34BFA00EDDA3A /* BankRomCheat.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC47454A09C34BFA00EDDA3A /* BankRomCheat.cxx */; }; DC47455609C34BFA00EDDA3A /* BankRomCheat.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC47454B09C34BFA00EDDA3A /* BankRomCheat.hxx */; }; DC47455709C34BFA00EDDA3A /* Cheat.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC47454C09C34BFA00EDDA3A /* Cheat.hxx */; }; DC47455809C34BFA00EDDA3A /* CheatCodeDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC47454D09C34BFA00EDDA3A /* CheatCodeDialog.cxx */; }; DC47455909C34BFA00EDDA3A /* CheatCodeDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC47454E09C34BFA00EDDA3A /* CheatCodeDialog.hxx */; }; DC47455A09C34BFA00EDDA3A /* CheatManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC47454F09C34BFA00EDDA3A /* CheatManager.cxx */; }; DC47455B09C34BFA00EDDA3A /* CheatManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC47455009C34BFA00EDDA3A /* CheatManager.hxx */; }; DC47455C09C34BFA00EDDA3A /* CheetahCheat.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC47455109C34BFA00EDDA3A /* CheetahCheat.cxx */; }; DC47455D09C34BFA00EDDA3A /* CheetahCheat.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC47455209C34BFA00EDDA3A /* CheetahCheat.hxx */; }; DC47455E09C34BFA00EDDA3A /* RamCheat.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC47455309C34BFA00EDDA3A /* RamCheat.cxx */; }; DC47455F09C34BFA00EDDA3A /* RamCheat.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC47455409C34BFA00EDDA3A /* RamCheat.hxx */; }; DC487FB60DA5350900E12499 /* AtariVox.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC487FB40DA5350900E12499 /* AtariVox.cxx */; }; DC487FB70DA5350900E12499 /* AtariVox.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC487FB50DA5350900E12499 /* AtariVox.hxx */; }; DC4AC6EF0DC8DACB00CD3AD2 /* RiotWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC4AC6ED0DC8DACB00CD3AD2 /* RiotWidget.cxx */; }; DC4AC6F00DC8DACB00CD3AD2 /* RiotWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC4AC6EE0DC8DACB00CD3AD2 /* RiotWidget.hxx */; }; DC4AC6F30DC8DAEF00CD3AD2 /* SaveKey.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC4AC6F10DC8DAEF00CD3AD2 /* SaveKey.cxx */; }; DC4AC6F40DC8DAEF00CD3AD2 /* SaveKey.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC4AC6F20DC8DAEF00CD3AD2 /* SaveKey.hxx */; }; DC53B6AE1F3622DA00AA6BFB /* PointingDevice.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC53B6AD1F3622DA00AA6BFB /* PointingDevice.cxx */; }; DC56FCDE14CCCC4900A31CC3 /* MouseControl.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */; }; DC56FCDF14CCCC4900A31CC3 /* MouseControl.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */; }; DC5AAC281FCB24AB00C420A6 /* EventHandlerConstants.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5AAC261FCB24AB00C420A6 /* EventHandlerConstants.hxx */; }; DC5AAC291FCB24AB00C420A6 /* FrameBufferConstants.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5AAC271FCB24AB00C420A6 /* FrameBufferConstants.hxx */; }; DC5AAC2C1FCB24DF00C420A6 /* RadioButtonWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5AAC2A1FCB24DF00C420A6 /* RadioButtonWidget.cxx */; }; DC5AAC2D1FCB24DF00C420A6 /* RadioButtonWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5AAC2B1FCB24DF00C420A6 /* RadioButtonWidget.hxx */; }; DC5ACB5B1FBFCE8E00A213FD /* DeveloperDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5ACB591FBFCE8E00A213FD /* DeveloperDialog.cxx */; }; DC5ACB5C1FBFCE8E00A213FD /* DeveloperDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5ACB5A1FBFCE8E00A213FD /* DeveloperDialog.hxx */; }; DC5ACB5E1FBFCEB800A213FD /* CartDebugWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5ACB5D1FBFCEB800A213FD /* CartDebugWidget.cxx */; }; DC5BE4B317C913AC0091FD64 /* ConsoleBFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5BE4B117C913AC0091FD64 /* ConsoleBFont.hxx */; }; DC5BE4B417C913AC0091FD64 /* ConsoleMediumBFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5BE4B217C913AC0091FD64 /* ConsoleMediumBFont.hxx */; }; DC5C768F14C26F7C0031EBC7 /* StellaKeys.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5C768E14C26F7C0031EBC7 /* StellaKeys.hxx */; }; DC5D1AA7102C6FC900E59AC1 /* Stack.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5D1AA6102C6FC900E59AC1 /* Stack.hxx */; }; DC5D2C520F117CFD004D1660 /* Rect.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5D2C4E0F117CFD004D1660 /* Rect.hxx */; }; DC5D2C530F117CFD004D1660 /* StellaFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5D2C4F0F117CFD004D1660 /* StellaFont.hxx */; }; DC5D2C540F117CFD004D1660 /* StellaLargeFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5D2C500F117CFD004D1660 /* StellaLargeFont.hxx */; }; DC5D2C550F117CFD004D1660 /* StellaMediumFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */; }; DC5D2C600F129B1E004D1660 /* LauncherFilterDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5D2C5E0F129B1E004D1660 /* LauncherFilterDialog.cxx */; }; DC5D2C610F129B1E004D1660 /* LauncherFilterDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5D2C5F0F129B1E004D1660 /* LauncherFilterDialog.hxx */; }; DC5E473B19EC9A14000E45DF /* EventJoyHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5E473A19EC9A14000E45DF /* EventJoyHandler.cxx */; }; DC5EE7C214F7C165001C628C /* NTSCFilter.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC5EE7C014F7C165001C628C /* NTSCFilter.cxx */; }; DC5EE7C314F7C165001C628C /* NTSCFilter.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC5EE7C114F7C165001C628C /* NTSCFilter.hxx */; }; DC62E6471960E87B007AEF05 /* AtariVoxWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC62E6431960E87B007AEF05 /* AtariVoxWidget.cxx */; }; DC62E6481960E87B007AEF05 /* AtariVoxWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC62E6441960E87B007AEF05 /* AtariVoxWidget.hxx */; }; DC62E6491960E87B007AEF05 /* SaveKeyWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC62E6451960E87B007AEF05 /* SaveKeyWidget.cxx */; }; DC62E64A1960E87B007AEF05 /* SaveKeyWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC62E6461960E87B007AEF05 /* SaveKeyWidget.hxx */; }; DC67270B1556F4860023653B /* CartCTY.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6727081556F4860023653B /* CartCTY.cxx */; }; DC67270C1556F4860023653B /* CartCTY.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6727091556F4860023653B /* CartCTY.hxx */; }; DC67270D1556F4860023653B /* CartCTYTunes.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC67270A1556F4860023653B /* CartCTYTunes.hxx */; }; DC676A411729A0B000E4E73D /* Cart3EWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A251729A0B000E4E73D /* Cart3EWidget.cxx */; }; DC676A421729A0B000E4E73D /* Cart3EWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A261729A0B000E4E73D /* Cart3EWidget.hxx */; }; DC676A431729A0B000E4E73D /* Cart4A50Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A271729A0B000E4E73D /* Cart4A50Widget.cxx */; }; DC676A441729A0B000E4E73D /* Cart4A50Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A281729A0B000E4E73D /* Cart4A50Widget.hxx */; }; DC676A451729A0B000E4E73D /* CartARWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A291729A0B000E4E73D /* CartARWidget.cxx */; }; DC676A461729A0B000E4E73D /* CartARWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A2A1729A0B000E4E73D /* CartARWidget.hxx */; }; DC676A471729A0B000E4E73D /* CartCMWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A2B1729A0B000E4E73D /* CartCMWidget.cxx */; }; DC676A481729A0B000E4E73D /* CartCMWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */; }; DC676A491729A0B000E4E73D /* CartCTYWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */; }; DC676A4A1729A0B000E4E73D /* CartCTYWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A2E1729A0B000E4E73D /* CartCTYWidget.hxx */; }; DC676A4B1729A0B000E4E73D /* CartDPCPlusWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A2F1729A0B000E4E73D /* CartDPCPlusWidget.cxx */; }; DC676A4C1729A0B000E4E73D /* CartDPCPlusWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A301729A0B000E4E73D /* CartDPCPlusWidget.hxx */; }; DC676A4D1729A0B000E4E73D /* CartDPCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A311729A0B000E4E73D /* CartDPCWidget.cxx */; }; DC676A4E1729A0B000E4E73D /* CartDPCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A321729A0B000E4E73D /* CartDPCWidget.hxx */; }; DC676A4F1729A0B000E4E73D /* CartE0Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A331729A0B000E4E73D /* CartE0Widget.cxx */; }; DC676A501729A0B000E4E73D /* CartE0Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A341729A0B000E4E73D /* CartE0Widget.hxx */; }; DC676A511729A0B000E4E73D /* CartE7Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A351729A0B000E4E73D /* CartE7Widget.cxx */; }; DC676A521729A0B000E4E73D /* CartE7Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A361729A0B000E4E73D /* CartE7Widget.hxx */; }; DC676A531729A0B000E4E73D /* CartFA2Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A371729A0B000E4E73D /* CartFA2Widget.cxx */; }; DC676A541729A0B000E4E73D /* CartFA2Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A381729A0B000E4E73D /* CartFA2Widget.hxx */; }; DC676A551729A0B000E4E73D /* CartFEWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A391729A0B000E4E73D /* CartFEWidget.cxx */; }; DC676A561729A0B000E4E73D /* CartFEWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A3A1729A0B000E4E73D /* CartFEWidget.hxx */; }; DC676A591729A0B000E4E73D /* CartSBWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A3D1729A0B000E4E73D /* CartSBWidget.cxx */; }; DC676A5A1729A0B000E4E73D /* CartSBWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A3E1729A0B000E4E73D /* CartSBWidget.hxx */; }; DC676A5B1729A0B000E4E73D /* CartX07Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC676A3F1729A0B000E4E73D /* CartX07Widget.cxx */; }; DC676A5C1729A0B000E4E73D /* CartX07Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC676A401729A0B000E4E73D /* CartX07Widget.hxx */; }; DC68F8901FA64C5300F4A2CC /* TIAConstants.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC68F88F1FA64C5300F4A2CC /* TIAConstants.hxx */; }; DC69670B1361FD0A0036499D /* pngdebug.h in Headers */ = {isa = PBXBuildFile; fileRef = DC6967071361FD0A0036499D /* pngdebug.h */; }; DC69670C1361FD0A0036499D /* pnginfo.h in Headers */ = {isa = PBXBuildFile; fileRef = DC6967081361FD0A0036499D /* pnginfo.h */; }; DC69670D1361FD0A0036499D /* pnglibconf.h in Headers */ = {isa = PBXBuildFile; fileRef = DC6967091361FD0A0036499D /* pnglibconf.h */; }; DC69670E1361FD0A0036499D /* pngstruct.h in Headers */ = {isa = PBXBuildFile; fileRef = DC69670A1361FD0A0036499D /* pngstruct.h */; }; DC6A18F819B3E65500DEB242 /* CartMDMWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6A18F619B3E65500DEB242 /* CartMDMWidget.cxx */; }; DC6A18F919B3E65500DEB242 /* CartMDMWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6A18F719B3E65500DEB242 /* CartMDMWidget.hxx */; }; DC6A18FC19B3E67A00DEB242 /* CartMDM.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6A18FA19B3E67A00DEB242 /* CartMDM.cxx */; }; DC6A18FD19B3E67A00DEB242 /* CartMDM.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6A18FB19B3E67A00DEB242 /* CartMDM.hxx */; }; DC6B2BA411037FF200F199A7 /* CartDebug.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6B2BA011037FF200F199A7 /* CartDebug.cxx */; }; DC6B2BA511037FF200F199A7 /* CartDebug.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6B2BA111037FF200F199A7 /* CartDebug.hxx */; }; DC6B2BA611037FF200F199A7 /* DiStella.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6B2BA211037FF200F199A7 /* DiStella.cxx */; }; DC6B2BA711037FF200F199A7 /* DiStella.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6B2BA311037FF200F199A7 /* DiStella.hxx */; }; DC6C726213CDEA0A008A5975 /* LoggerDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6C726013CDEA0A008A5975 /* LoggerDialog.cxx */; }; DC6C726313CDEA0A008A5975 /* LoggerDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6C726113CDEA0A008A5975 /* LoggerDialog.hxx */; }; DC6D39871A3CE65000171E71 /* CartWDWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC6D39851A3CE65000171E71 /* CartWDWidget.cxx */; }; DC6D39881A3CE65000171E71 /* CartWDWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC6D39861A3CE65000171E71 /* CartWDWidget.hxx */; }; DC71EA9D1FDA06D2008827CB /* CartE78K.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC71EA991FDA06D2008827CB /* CartE78K.cxx */; }; DC71EA9E1FDA06D2008827CB /* CartE78K.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC71EA9A1FDA06D2008827CB /* CartE78K.hxx */; }; DC71EA9F1FDA06D2008827CB /* CartMNetwork.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC71EA9B1FDA06D2008827CB /* CartMNetwork.cxx */; }; DC71EAA01FDA06D2008827CB /* CartMNetwork.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC71EA9C1FDA06D2008827CB /* CartMNetwork.hxx */; }; DC71EAA51FDA070D008827CB /* CartE78KWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC71EAA11FDA070D008827CB /* CartE78KWidget.cxx */; }; DC71EAA61FDA070D008827CB /* CartE78KWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC71EAA21FDA070D008827CB /* CartE78KWidget.hxx */; }; DC71EAA71FDA070D008827CB /* CartMNetworkWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC71EAA31FDA070D008827CB /* CartMNetworkWidget.cxx */; }; DC71EAA81FDA070D008827CB /* CartMNetworkWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC71EAA41FDA070D008827CB /* CartMNetworkWidget.hxx */; }; DC73BD851915E5B1003FAFAD /* FBSurfaceSDL2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC73BD831915E5B1003FAFAD /* FBSurfaceSDL2.cxx */; }; DC73BD861915E5B1003FAFAD /* FBSurfaceSDL2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC73BD841915E5B1003FAFAD /* FBSurfaceSDL2.hxx */; }; DC73BD891915E5E3003FAFAD /* FBSurface.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC73BD871915E5E3003FAFAD /* FBSurface.cxx */; }; DC73BD8A1915E5E3003FAFAD /* FBSurface.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC73BD881915E5E3003FAFAD /* FBSurface.hxx */; }; DC74D6A2138D4D7E00F05C5C /* StringParser.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */; }; DC74E5C6198AF12700F37E36 /* CartDASHWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */; }; DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */; }; DC79F81217A88D9E00288B91 /* Base.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC79F81017A88D9E00288B91 /* Base.cxx */; }; DC79F81317A88D9E00288B91 /* Base.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC79F81117A88D9E00288B91 /* Base.hxx */; }; DC7A24D5173B1CF600B20FE9 /* Variant.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC7A24D4173B1CF600B20FE9 /* Variant.hxx */; }; DC7A24DF173B1DBC00B20FE9 /* FileListWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC7A24DD173B1DBC00B20FE9 /* FileListWidget.cxx */; }; DC7A24E0173B1DBC00B20FE9 /* FileListWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC7A24DE173B1DBC00B20FE9 /* FileListWidget.hxx */; }; DC8078DB0B4BD5F3005E9305 /* DebuggerExpressions.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8078DA0B4BD5F3005E9305 /* DebuggerExpressions.hxx */; }; DC8078EA0B4BD697005E9305 /* UIDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8078E60B4BD697005E9305 /* UIDialog.cxx */; }; DC8078EB0B4BD697005E9305 /* UIDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8078E70B4BD697005E9305 /* UIDialog.hxx */; }; DC8C1BAD14B25DE7006440EE /* CartCM.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8C1BA714B25DE7006440EE /* CartCM.cxx */; }; DC8C1BAE14B25DE7006440EE /* CartCM.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8C1BA814B25DE7006440EE /* CartCM.hxx */; }; DC8C1BAF14B25DE7006440EE /* CompuMate.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8C1BA914B25DE7006440EE /* CompuMate.cxx */; }; DC8C1BB014B25DE7006440EE /* CompuMate.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8C1BAA14B25DE7006440EE /* CompuMate.hxx */; }; DC8C1BB114B25DE7006440EE /* MindLink.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC8C1BAB14B25DE7006440EE /* MindLink.cxx */; }; DC8C1BB214B25DE7006440EE /* MindLink.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8C1BAC14B25DE7006440EE /* MindLink.hxx */; }; DC8CF9BD17C15A27004B533D /* ConsoleMediumFont.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC8CF9BC17C15A27004B533D /* ConsoleMediumFont.hxx */; }; DC932D440F278A5200FEFEFC /* DefProps.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC932D3F0F278A5200FEFEFC /* DefProps.hxx */; }; DC932D450F278A5200FEFEFC /* Serializable.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC932D400F278A5200FEFEFC /* Serializable.hxx */; }; DC932D460F278A5200FEFEFC /* SerialPort.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC932D410F278A5200FEFEFC /* SerialPort.hxx */; }; DC96162C1F817830008A2206 /* AmigaMouseWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC9616221F817830008A2206 /* AmigaMouseWidget.cxx */; }; DC96162D1F817830008A2206 /* AmigaMouseWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC9616231F817830008A2206 /* AmigaMouseWidget.hxx */; }; DC96162E1F817830008A2206 /* AtariMouseWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC9616241F817830008A2206 /* AtariMouseWidget.cxx */; }; DC96162F1F817830008A2206 /* AtariMouseWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC9616251F817830008A2206 /* AtariMouseWidget.hxx */; }; DC9616301F817830008A2206 /* FlashWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC9616261F817830008A2206 /* FlashWidget.cxx */; }; DC9616311F817830008A2206 /* FlashWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC9616271F817830008A2206 /* FlashWidget.hxx */; }; DC9616321F817830008A2206 /* PointingDeviceWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC9616281F817830008A2206 /* PointingDeviceWidget.cxx */; }; DC9616331F817830008A2206 /* PointingDeviceWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC9616291F817830008A2206 /* PointingDeviceWidget.hxx */; }; DC9616341F817830008A2206 /* TrakBallWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC96162A1F817830008A2206 /* TrakBallWidget.cxx */; }; DC9616351F817830008A2206 /* TrakBallWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC96162B1F817830008A2206 /* TrakBallWidget.hxx */; }; DC98F35611F5B56200AA520F /* MessageBox.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC98F35411F5B56200AA520F /* MessageBox.cxx */; }; DC98F35711F5B56200AA520F /* MessageBox.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC98F35511F5B56200AA520F /* MessageBox.hxx */; }; DC9EA8870F729A36000452B5 /* KidVid.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DC9EA8850F729A36000452B5 /* KidVid.cxx */; }; DC9EA8880F729A36000452B5 /* KidVid.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DC9EA8860F729A36000452B5 /* KidVid.hxx */; }; DCA00FF70DBABCAD00C3823D /* RiotDebug.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCA00FF50DBABCAD00C3823D /* RiotDebug.cxx */; }; DCA00FF80DBABCAD00C3823D /* RiotDebug.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA00FF60DBABCAD00C3823D /* RiotDebug.hxx */; }; DCA078341F8C1B04008EFEE5 /* LinkedObjectPool.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA078321F8C1B04008EFEE5 /* LinkedObjectPool.hxx */; }; DCA078351F8C1B04008EFEE5 /* SDL_lib.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA078331F8C1B04008EFEE5 /* SDL_lib.hxx */; }; DCA23AE90D75B22500F77B33 /* CartX07.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCA23AE70D75B22500F77B33 /* CartX07.cxx */; }; DCA23AEA0D75B22500F77B33 /* CartX07.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA23AE80D75B22500F77B33 /* CartX07.hxx */; }; DCA82C711FEB4E780059340F /* TimeMachine.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCA82C6D1FEB4E780059340F /* TimeMachine.cxx */; }; DCA82C721FEB4E780059340F /* TimeMachine.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA82C6E1FEB4E780059340F /* TimeMachine.hxx */; }; DCA82C731FEB4E780059340F /* TimeMachineDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCA82C6F1FEB4E780059340F /* TimeMachineDialog.cxx */; }; DCA82C741FEB4E780059340F /* TimeMachineDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCA82C701FEB4E780059340F /* TimeMachineDialog.hxx */; }; DCAACAF6188D631500A4D282 /* Cart4KSC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACAEC188D631500A4D282 /* Cart4KSC.cxx */; }; DCAACAF7188D631500A4D282 /* Cart4KSC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACAED188D631500A4D282 /* Cart4KSC.hxx */; }; DCAACAF8188D631500A4D282 /* CartBF.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACAEE188D631500A4D282 /* CartBF.cxx */; }; DCAACAF9188D631500A4D282 /* CartBF.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACAEF188D631500A4D282 /* CartBF.hxx */; }; DCAACAFA188D631500A4D282 /* CartBFSC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACAF0188D631500A4D282 /* CartBFSC.cxx */; }; DCAACAFB188D631500A4D282 /* CartBFSC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACAF1188D631500A4D282 /* CartBFSC.hxx */; }; DCAACAFC188D631500A4D282 /* CartDF.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACAF2188D631500A4D282 /* CartDF.cxx */; }; DCAACAFD188D631500A4D282 /* CartDF.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACAF3188D631500A4D282 /* CartDF.hxx */; }; DCAACAFE188D631500A4D282 /* CartDFSC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACAF4188D631500A4D282 /* CartDFSC.cxx */; }; DCAACAFF188D631500A4D282 /* CartDFSC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACAF5188D631500A4D282 /* CartDFSC.hxx */; }; DCAACB0E188D636F00A4D282 /* Cart4KSCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACB04188D636F00A4D282 /* Cart4KSCWidget.cxx */; }; DCAACB0F188D636F00A4D282 /* Cart4KSCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACB05188D636F00A4D282 /* Cart4KSCWidget.hxx */; }; DCAACB10188D636F00A4D282 /* CartBFSCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACB06188D636F00A4D282 /* CartBFSCWidget.cxx */; }; DCAACB11188D636F00A4D282 /* CartBFSCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACB07188D636F00A4D282 /* CartBFSCWidget.hxx */; }; DCAACB12188D636F00A4D282 /* CartBFWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACB08188D636F00A4D282 /* CartBFWidget.cxx */; }; DCAACB13188D636F00A4D282 /* CartBFWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACB09188D636F00A4D282 /* CartBFWidget.hxx */; }; DCAACB14188D636F00A4D282 /* CartDFSCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACB0A188D636F00A4D282 /* CartDFSCWidget.cxx */; }; DCAACB15188D636F00A4D282 /* CartDFSCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACB0B188D636F00A4D282 /* CartDFSCWidget.hxx */; }; DCAACB16188D636F00A4D282 /* CartDFWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAACB0C188D636F00A4D282 /* CartDFWidget.cxx */; }; DCAACB17188D636F00A4D282 /* CartDFWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAACB0D188D636F00A4D282 /* CartDFWidget.hxx */; }; DCAAE5D31715887B0080BB82 /* Cart2KWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5B21715887B0080BB82 /* Cart2KWidget.cxx */; }; DCAAE5D41715887B0080BB82 /* Cart2KWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5B31715887B0080BB82 /* Cart2KWidget.hxx */; }; DCAAE5D51715887B0080BB82 /* Cart3FWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5B41715887B0080BB82 /* Cart3FWidget.cxx */; }; DCAAE5D61715887B0080BB82 /* Cart3FWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5B51715887B0080BB82 /* Cart3FWidget.hxx */; }; DCAAE5D71715887B0080BB82 /* Cart4KWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5B61715887B0080BB82 /* Cart4KWidget.cxx */; }; DCAAE5D81715887B0080BB82 /* Cart4KWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5B71715887B0080BB82 /* Cart4KWidget.hxx */; }; DCAAE5D91715887B0080BB82 /* Cart0840Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5B81715887B0080BB82 /* Cart0840Widget.cxx */; }; DCAAE5DA1715887B0080BB82 /* Cart0840Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5B91715887B0080BB82 /* Cart0840Widget.hxx */; }; DCAAE5DB1715887B0080BB82 /* CartCVWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5BA1715887B0080BB82 /* CartCVWidget.cxx */; }; DCAAE5DC1715887B0080BB82 /* CartCVWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5BB1715887B0080BB82 /* CartCVWidget.hxx */; }; DCAAE5DD1715887B0080BB82 /* CartDebugWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5BC1715887B0080BB82 /* CartDebugWidget.hxx */; }; DCAAE5DE1715887B0080BB82 /* CartEFSCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5BD1715887B0080BB82 /* CartEFSCWidget.cxx */; }; DCAAE5DF1715887B0080BB82 /* CartEFSCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5BE1715887B0080BB82 /* CartEFSCWidget.hxx */; }; DCAAE5E01715887B0080BB82 /* CartEFWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5BF1715887B0080BB82 /* CartEFWidget.cxx */; }; DCAAE5E11715887B0080BB82 /* CartEFWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5C01715887B0080BB82 /* CartEFWidget.hxx */; }; DCAAE5E21715887B0080BB82 /* CartF0Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5C11715887B0080BB82 /* CartF0Widget.cxx */; }; DCAAE5E31715887B0080BB82 /* CartF0Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5C21715887B0080BB82 /* CartF0Widget.hxx */; }; DCAAE5E41715887B0080BB82 /* CartF4SCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5C31715887B0080BB82 /* CartF4SCWidget.cxx */; }; DCAAE5E51715887B0080BB82 /* CartF4SCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5C41715887B0080BB82 /* CartF4SCWidget.hxx */; }; DCAAE5E61715887B0080BB82 /* CartF4Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5C51715887B0080BB82 /* CartF4Widget.cxx */; }; DCAAE5E71715887B0080BB82 /* CartF4Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5C61715887B0080BB82 /* CartF4Widget.hxx */; }; DCAAE5E81715887B0080BB82 /* CartF6SCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5C71715887B0080BB82 /* CartF6SCWidget.cxx */; }; DCAAE5E91715887B0080BB82 /* CartF6SCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5C81715887B0080BB82 /* CartF6SCWidget.hxx */; }; DCAAE5EA1715887B0080BB82 /* CartF6Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5C91715887B0080BB82 /* CartF6Widget.cxx */; }; DCAAE5EB1715887B0080BB82 /* CartF6Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5CA1715887B0080BB82 /* CartF6Widget.hxx */; }; DCAAE5EC1715887B0080BB82 /* CartF8SCWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5CB1715887B0080BB82 /* CartF8SCWidget.cxx */; }; DCAAE5ED1715887B0080BB82 /* CartF8SCWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5CC1715887B0080BB82 /* CartF8SCWidget.hxx */; }; DCAAE5EE1715887B0080BB82 /* CartF8Widget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5CD1715887B0080BB82 /* CartF8Widget.cxx */; }; DCAAE5EF1715887B0080BB82 /* CartF8Widget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5CE1715887B0080BB82 /* CartF8Widget.hxx */; }; DCAAE5F01715887B0080BB82 /* CartFAWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5CF1715887B0080BB82 /* CartFAWidget.cxx */; }; DCAAE5F11715887B0080BB82 /* CartFAWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */; }; DCAAE5F21715887B0080BB82 /* CartUAWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */; }; DCAAE5F31715887B0080BB82 /* CartUAWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */; }; DCACBAD01C54296300703A9B /* CartCVPlusWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */; }; DCACBAD11C54296300703A9B /* CartCVPlusWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */; }; DCACBAD41C54298300703A9B /* CartCVPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCACBAD21C54298300703A9B /* CartCVPlus.cxx */; }; DCACBAD51C54298300703A9B /* CartCVPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCACBAD31C54298300703A9B /* CartCVPlus.hxx */; }; DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */; }; DCAD60A91152F8BD00BC4184 /* CartDPCPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */; }; DCB20EC71A0C506C0048F595 /* main.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB20EC61A0C506C0048F595 /* main.cxx */; }; DCB2ECAE1F0AECA3009738A6 /* BSType.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB2ECAB1F0AECA3009738A6 /* BSType.hxx */; }; DCB2ECAF1F0AECA3009738A6 /* CartDetector.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCB2ECAC1F0AECA3009738A6 /* CartDetector.cxx */; }; DCB2ECB01F0AECA3009738A6 /* CartDetector.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB2ECAD1F0AECA3009738A6 /* CartDetector.hxx */; }; DCB87E581A104C1E00BF2A3B /* MediaFactory.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCB87E571A104C1E00BF2A3B /* MediaFactory.hxx */; }; DCBDDE9A1D6A5F0E009DF1E9 /* Cart3EPlusWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCBDDE981D6A5F0E009DF1E9 /* Cart3EPlusWidget.cxx */; }; DCBDDE9B1D6A5F0E009DF1E9 /* Cart3EPlusWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCBDDE991D6A5F0E009DF1E9 /* Cart3EPlusWidget.hxx */; }; DCBDDE9E1D6A5F2F009DF1E9 /* Cart3EPlus.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCBDDE9C1D6A5F2F009DF1E9 /* Cart3EPlus.cxx */; }; DCBDDE9F1D6A5F2F009DF1E9 /* Cart3EPlus.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCBDDE9D1D6A5F2F009DF1E9 /* Cart3EPlus.hxx */; }; DCC527D110B9DA19005E1287 /* Device.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCC527C910B9DA19005E1287 /* Device.hxx */; }; DCC527D210B9DA19005E1287 /* M6502.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCC527CA10B9DA19005E1287 /* M6502.cxx */; }; DCC527D310B9DA19005E1287 /* M6502.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCC527CB10B9DA19005E1287 /* M6502.hxx */; }; DCC527D510B9DA19005E1287 /* NullDev.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCC527CD10B9DA19005E1287 /* NullDev.hxx */; }; DCC527D610B9DA19005E1287 /* System.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCC527CE10B9DA19005E1287 /* System.cxx */; }; DCC527D710B9DA19005E1287 /* System.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCC527CF10B9DA19005E1287 /* System.hxx */; }; DCC527DB10B9DA6A005E1287 /* bspf.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCC527D810B9DA6A005E1287 /* bspf.hxx */; }; DCCA26B31FA64D5E000EE4D8 /* AbstractFrameManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCA26B11FA64D5E000EE4D8 /* AbstractFrameManager.hxx */; }; DCCA26B41FA64D5E000EE4D8 /* FrameManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCA26B21FA64D5E000EE4D8 /* FrameManager.hxx */; }; DCCF47DE14B60DEE00814FAB /* ControllerWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCF47DB14B60DEE00814FAB /* ControllerWidget.hxx */; }; DCCF47DF14B60DEE00814FAB /* JoystickWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCCF47DC14B60DEE00814FAB /* JoystickWidget.cxx */; }; DCCF47E014B60DEE00814FAB /* JoystickWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCF47DD14B60DEE00814FAB /* JoystickWidget.hxx */; }; DCCF49B714B7544A00814FAB /* PaddleWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCCF49B514B7544A00814FAB /* PaddleWidget.cxx */; }; DCCF49B814B7544A00814FAB /* PaddleWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCF49B614B7544A00814FAB /* PaddleWidget.hxx */; }; DCCF4AD114B7E6C300814FAB /* BoosterWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCCF4ACE14B7E6C300814FAB /* BoosterWidget.cxx */; }; DCCF4AD214B7E6C300814FAB /* BoosterWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCF4ACF14B7E6C300814FAB /* BoosterWidget.hxx */; }; DCCF4AD314B7E6C300814FAB /* NullControlWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCF4AD014B7E6C300814FAB /* NullControlWidget.hxx */; }; DCCF4ADC14B9433100814FAB /* GenesisWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCCF4ADA14B9433100814FAB /* GenesisWidget.cxx */; }; DCCF4ADD14B9433100814FAB /* GenesisWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCF4ADB14B9433100814FAB /* GenesisWidget.hxx */; }; DCCF4B0214BA27EB00814FAB /* DrivingWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCCF4AFE14BA27EB00814FAB /* DrivingWidget.cxx */; }; DCCF4B0314BA27EB00814FAB /* DrivingWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCF4AFF14BA27EB00814FAB /* DrivingWidget.hxx */; }; DCCF4B0414BA27EB00814FAB /* KeyboardWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCCF4B0014BA27EB00814FAB /* KeyboardWidget.cxx */; }; DCCF4B0514BA27EB00814FAB /* KeyboardWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCCF4B0114BA27EB00814FAB /* KeyboardWidget.hxx */; }; DCD2839812E39F1200A808DC /* Thumbulator.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCD2839612E39F1200A808DC /* Thumbulator.cxx */; }; DCD2839912E39F1200A808DC /* Thumbulator.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCD2839712E39F1200A808DC /* Thumbulator.hxx */; }; DCD3F7C511340AAF00DBA3AE /* Genesis.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCD3F7C311340AAF00DBA3AE /* Genesis.cxx */; }; DCD3F7C611340AAF00DBA3AE /* Genesis.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCD3F7C411340AAF00DBA3AE /* Genesis.hxx */; }; DCD56D380B247D920092F9F8 /* Cart4A50.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCD56D360B247D920092F9F8 /* Cart4A50.cxx */; }; DCD56D390B247D920092F9F8 /* Cart4A50.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCD56D370B247D920092F9F8 /* Cart4A50.hxx */; }; DCD6FC7011C281ED005DA767 /* png.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC5D11C281ED005DA767 /* png.c */; }; DCD6FC7111C281ED005DA767 /* png.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD6FC5E11C281ED005DA767 /* png.h */; }; DCD6FC7211C281ED005DA767 /* pngconf.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD6FC5F11C281ED005DA767 /* pngconf.h */; }; DCD6FC7311C281ED005DA767 /* pngerror.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6011C281ED005DA767 /* pngerror.c */; }; DCD6FC7411C281ED005DA767 /* pngget.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6111C281ED005DA767 /* pngget.c */; }; DCD6FC7511C281ED005DA767 /* pngmem.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6211C281ED005DA767 /* pngmem.c */; }; DCD6FC7611C281ED005DA767 /* pngpread.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6311C281ED005DA767 /* pngpread.c */; }; DCD6FC7711C281ED005DA767 /* pngpriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD6FC6411C281ED005DA767 /* pngpriv.h */; }; DCD6FC7811C281ED005DA767 /* pngread.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6511C281ED005DA767 /* pngread.c */; }; DCD6FC7911C281ED005DA767 /* pngrio.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6611C281ED005DA767 /* pngrio.c */; }; DCD6FC7A11C281ED005DA767 /* pngrtran.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6711C281ED005DA767 /* pngrtran.c */; }; DCD6FC7B11C281ED005DA767 /* pngrutil.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6811C281ED005DA767 /* pngrutil.c */; }; DCD6FC7C11C281ED005DA767 /* pngset.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6911C281ED005DA767 /* pngset.c */; }; DCD6FC7E11C281ED005DA767 /* pngtrans.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6B11C281ED005DA767 /* pngtrans.c */; }; DCD6FC7F11C281ED005DA767 /* pngwio.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6C11C281ED005DA767 /* pngwio.c */; }; DCD6FC8011C281ED005DA767 /* pngwrite.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6D11C281ED005DA767 /* pngwrite.c */; }; DCD6FC8111C281ED005DA767 /* pngwtran.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6E11C281ED005DA767 /* pngwtran.c */; }; DCD6FC8211C281ED005DA767 /* pngwutil.c in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC6F11C281ED005DA767 /* pngwutil.c */; }; DCD6FC9311C28C6F005DA767 /* PNGLibrary.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCD6FC9111C28C6F005DA767 /* PNGLibrary.cxx */; }; DCD6FC9411C28C6F005DA767 /* PNGLibrary.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */; }; DCDA03B01A2009BB00711920 /* CartWD.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDA03AE1A2009BA00711920 /* CartWD.cxx */; }; DCDA03B11A2009BB00711920 /* CartWD.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDA03AF1A2009BB00711920 /* CartWD.hxx */; }; DCDAF4D918CA9AAB00D3865D /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCDAF4D818CA9AAB00D3865D /* SDL2.framework */; }; DCDDEAC41F5DBF0400C67366 /* RewindManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAC01F5DBF0400C67366 /* RewindManager.cxx */; }; DCDDEAC51F5DBF0400C67366 /* RewindManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDDEAC11F5DBF0400C67366 /* RewindManager.hxx */; }; DCDDEAC61F5DBF0400C67366 /* StateManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDDEAC21F5DBF0400C67366 /* StateManager.cxx */; }; DCDDEAC71F5DBF0400C67366 /* StateManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDDEAC31F5DBF0400C67366 /* StateManager.hxx */; }; DCDE17FA17724E5D00EB1AC6 /* ConfigPathDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDE17F617724E5D00EB1AC6 /* ConfigPathDialog.cxx */; }; DCDE17FB17724E5D00EB1AC6 /* ConfigPathDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDE17F717724E5D00EB1AC6 /* ConfigPathDialog.hxx */; }; DCDE17FC17724E5D00EB1AC6 /* SnapshotDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */; }; DCDE17FD17724E5D00EB1AC6 /* SnapshotDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCDE17F917724E5D00EB1AC6 /* SnapshotDialog.hxx */; }; DCE395DB16CB0B2B008DB1E5 /* FSNodePOSIX.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE395DA16CB0B2B008DB1E5 /* FSNodePOSIX.hxx */; }; DCE395EF16CB0B5F008DB1E5 /* FSNodeFactory.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE395EA16CB0B5F008DB1E5 /* FSNodeFactory.hxx */; }; DCE395F016CB0B5F008DB1E5 /* FSNodeZIP.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE395EB16CB0B5F008DB1E5 /* FSNodeZIP.cxx */; }; DCE395F116CB0B5F008DB1E5 /* FSNodeZIP.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE395EC16CB0B5F008DB1E5 /* FSNodeZIP.hxx */; }; DCE395F216CB0B5F008DB1E5 /* ZipHandler.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE395ED16CB0B5F008DB1E5 /* ZipHandler.cxx */; }; DCE395F316CB0B5F008DB1E5 /* ZipHandler.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE395EE16CB0B5F008DB1E5 /* ZipHandler.hxx */; }; DCE3BBF90C95CEDC00A671DF /* RomInfoWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE3BBF50C95CEDC00A671DF /* RomInfoWidget.cxx */; }; DCE3BBFA0C95CEDC00A671DF /* RomInfoWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE3BBF60C95CEDC00A671DF /* RomInfoWidget.hxx */; }; DCE5CDE31BA10024005CD08A /* RiotRamWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE5CDE11BA10024005CD08A /* RiotRamWidget.cxx */; }; DCE5CDE41BA10024005CD08A /* RiotRamWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE5CDE21BA10024005CD08A /* RiotRamWidget.hxx */; }; DCE8B1871E7E03B300189864 /* FrameLayout.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE8B1861E7E03B300189864 /* FrameLayout.hxx */; }; DCE9158B201543B900960CC0 /* TimeLineWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCE91589201543B900960CC0 /* TimeLineWidget.cxx */; }; DCE9158C201543B900960CC0 /* TimeLineWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCE9158A201543B900960CC0 /* TimeLineWidget.hxx */; }; DCEC58581E945125002F0246 /* DelayQueueWidget.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCEC58561E945125002F0246 /* DelayQueueWidget.cxx */; }; DCEC58591E945125002F0246 /* DelayQueueWidget.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCEC58571E945125002F0246 /* DelayQueueWidget.hxx */; }; DCEC585E1E945175002F0246 /* DelayQueueIterator.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCEC585B1E945175002F0246 /* DelayQueueIterator.hxx */; }; DCEECE560B5E5E540021D754 /* Cart0840.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCEECE540B5E5E540021D754 /* Cart0840.cxx */; }; DCEECE570B5E5E540021D754 /* Cart0840.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCEECE550B5E5E540021D754 /* Cart0840.hxx */; }; DCF3A6E71DFC75E3008A8AF3 /* Background.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6CD1DFC75E3008A8AF3 /* Background.cxx */; }; DCF3A6E81DFC75E3008A8AF3 /* Background.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6CE1DFC75E3008A8AF3 /* Background.hxx */; }; DCF3A6E91DFC75E3008A8AF3 /* Ball.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6CF1DFC75E3008A8AF3 /* Ball.cxx */; }; DCF3A6EA1DFC75E3008A8AF3 /* Ball.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6D01DFC75E3008A8AF3 /* Ball.hxx */; }; DCF3A6EC1DFC75E3008A8AF3 /* DelayQueue.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6D21DFC75E3008A8AF3 /* DelayQueue.hxx */; }; DCF3A6EE1DFC75E3008A8AF3 /* DelayQueueMember.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6D41DFC75E3008A8AF3 /* DelayQueueMember.hxx */; }; DCF3A6EF1DFC75E3008A8AF3 /* DrawCounterDecodes.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6D51DFC75E3008A8AF3 /* DrawCounterDecodes.cxx */; }; DCF3A6F01DFC75E3008A8AF3 /* DrawCounterDecodes.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6D61DFC75E3008A8AF3 /* DrawCounterDecodes.hxx */; }; DCF3A6F31DFC75E3008A8AF3 /* LatchedInput.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6D91DFC75E3008A8AF3 /* LatchedInput.cxx */; }; DCF3A6F41DFC75E3008A8AF3 /* LatchedInput.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6DA1DFC75E3008A8AF3 /* LatchedInput.hxx */; }; DCF3A6F51DFC75E3008A8AF3 /* Missile.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6DB1DFC75E3008A8AF3 /* Missile.cxx */; }; DCF3A6F61DFC75E3008A8AF3 /* Missile.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6DC1DFC75E3008A8AF3 /* Missile.hxx */; }; DCF3A6F81DFC75E3008A8AF3 /* PaddleReader.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6DE1DFC75E3008A8AF3 /* PaddleReader.cxx */; }; DCF3A6F91DFC75E3008A8AF3 /* PaddleReader.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6DF1DFC75E3008A8AF3 /* PaddleReader.hxx */; }; DCF3A6FA1DFC75E3008A8AF3 /* Player.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6E01DFC75E3008A8AF3 /* Player.cxx */; }; DCF3A6FB1DFC75E3008A8AF3 /* Player.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6E11DFC75E3008A8AF3 /* Player.hxx */; }; DCF3A6FC1DFC75E3008A8AF3 /* Playfield.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6E21DFC75E3008A8AF3 /* Playfield.cxx */; }; DCF3A6FD1DFC75E3008A8AF3 /* Playfield.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6E31DFC75E3008A8AF3 /* Playfield.hxx */; }; DCF3A6FE1DFC75E3008A8AF3 /* TIA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF3A6E41DFC75E3008A8AF3 /* TIA.cxx */; }; DCF3A6FF1DFC75E3008A8AF3 /* TIA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A6E51DFC75E3008A8AF3 /* TIA.hxx */; }; DCF3A7021DFC76BC008A8AF3 /* TIATypes.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF3A7011DFC76BC008A8AF3 /* TIATypes.hxx */; }; DCF467B80F93993B00B25D7A /* SoundNull.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF467B40F93993B00B25D7A /* SoundNull.hxx */; }; DCF467BD0F9399F500B25D7A /* Version.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF467BC0F9399F500B25D7A /* Version.hxx */; }; DCF467C20F939A1400B25D7A /* CartEF.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF467BE0F939A1400B25D7A /* CartEF.cxx */; }; DCF467C30F939A1400B25D7A /* CartEF.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF467BF0F939A1400B25D7A /* CartEF.hxx */; }; DCF467C40F939A1400B25D7A /* CartEFSC.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF467C00F939A1400B25D7A /* CartEFSC.cxx */; }; DCF467C50F939A1400B25D7A /* CartEFSC.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF467C10F939A1400B25D7A /* CartEFSC.hxx */; }; DCF4907A1A0ECE5B00A67AA9 /* Vec.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF490791A0ECE5B00A67AA9 /* Vec.hxx */; }; DCF7B0DD10A762FC007A2870 /* CartF0.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF7B0D910A762FC007A2870 /* CartF0.cxx */; }; DCF7B0DE10A762FC007A2870 /* CartF0.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF7B0DA10A762FC007A2870 /* CartF0.hxx */; }; DCF7B0DF10A762FC007A2870 /* CartFA.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCF7B0DB10A762FC007A2870 /* CartFA.cxx */; }; DCF7B0E010A762FC007A2870 /* CartFA.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCF7B0DC10A762FC007A2870 /* CartFA.hxx */; }; DCFB9FAC1ECA2609004FD69B /* DelayQueueIteratorImpl.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCFB9FAB1ECA2609004FD69B /* DelayQueueIteratorImpl.hxx */; }; DCFF14CD18B0260300A20364 /* EventHandlerSDL2.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCFF14CB18B0260300A20364 /* EventHandlerSDL2.cxx */; }; DCFF14CE18B0260300A20364 /* EventHandlerSDL2.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCFF14CC18B0260300A20364 /* EventHandlerSDL2.hxx */; }; DCFFE59D12100E1400DFA000 /* ComboDialog.cxx in Sources */ = {isa = PBXBuildFile; fileRef = DCFFE59B12100E1400DFA000 /* ComboDialog.cxx */; }; DCFFE59E12100E1400DFA000 /* ComboDialog.hxx in Headers */ = {isa = PBXBuildFile; fileRef = DCFFE59C12100E1400DFA000 /* ComboDialog.hxx */; }; E0306E0C1F93E916003DDD52 /* YStartDetector.cxx in Sources */ = {isa = PBXBuildFile; fileRef = E0306E061F93E915003DDD52 /* YStartDetector.cxx */; }; E0306E0D1F93E916003DDD52 /* FrameLayoutDetector.hxx in Headers */ = {isa = PBXBuildFile; fileRef = E0306E071F93E915003DDD52 /* FrameLayoutDetector.hxx */; }; E0306E0E1F93E916003DDD52 /* YStartDetector.hxx in Headers */ = {isa = PBXBuildFile; fileRef = E0306E081F93E915003DDD52 /* YStartDetector.hxx */; }; E0306E0F1F93E916003DDD52 /* JitterEmulation.cxx in Sources */ = {isa = PBXBuildFile; fileRef = E0306E091F93E915003DDD52 /* JitterEmulation.cxx */; }; E0306E101F93E916003DDD52 /* FrameLayoutDetector.cxx in Sources */ = {isa = PBXBuildFile; fileRef = E0306E0A1F93E916003DDD52 /* FrameLayoutDetector.cxx */; }; E0306E111F93E916003DDD52 /* JitterEmulation.hxx in Headers */ = {isa = PBXBuildFile; fileRef = E0306E0B1F93E916003DDD52 /* JitterEmulation.hxx */; }; E0406FB61F81A85400A82AE0 /* AbstractFrameManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = E0DFDD781F81A358000F3505 /* AbstractFrameManager.cxx */; }; E0406FB81F81A85400A82AE0 /* FrameManager.cxx in Sources */ = {isa = PBXBuildFile; fileRef = E0DFDD7B1F81A358000F3505 /* FrameManager.cxx */; }; /* End PBXBuildFile section */ /* Begin PBXBuildRule section */ 2D91751B09BA90380026E9FF /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.c; isEditable = 1; outputFiles = ( ); script = ""; }; DC5EE7DF14F7C32D001C628C /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.asm; isEditable = 1; outputFiles = ( ); script = ""; }; DC5EE7E014F7C32D001C628C /* PBXBuildRule */ = { isa = PBXBuildRule; compilerSpec = com.apple.compilers.llvm.clang.1_0; fileType = sourcecode.cpp; isEditable = 1; outputFiles = ( ); script = ""; }; /* End PBXBuildRule section */ /* Begin PBXCopyFilesBuildPhase section */ 2D91751309BA90380026E9FF /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 55FE2A321EE4856B00078ADE /* SDL2.framework in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; DCCC0C9609C354660088BFF1 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 7; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 2D02207F08A301F200B9C76B /* InputTextDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = InputTextDialog.cxx; sourceTree = ""; }; 2D02208008A301F200B9C76B /* InputTextDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = InputTextDialog.hxx; sourceTree = ""; }; 2D05FF5E096E269100A518FE /* EventMappingWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = EventMappingWidget.cxx; sourceTree = ""; }; 2D05FF5F096E269100A518FE /* EventMappingWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = EventMappingWidget.hxx; sourceTree = ""; }; 2D05FF60096E269100A518FE /* InputDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = InputDialog.cxx; sourceTree = ""; }; 2D05FF61096E269100A518FE /* InputDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = InputDialog.hxx; sourceTree = ""; }; 2D113E090672BF2100317017 /* docs */ = {isa = PBXFileReference; explicitFileType = folder; name = docs; path = ../../docs; sourceTree = ""; }; 2D16A8E106324136005DF364 /* Stella.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Stella.icns; sourceTree = SOURCE_ROOT; }; 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; }; 2D1A6CD4085135F9007CDBA8 /* AboutBox.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AboutBox.h; sourceTree = SOURCE_ROOT; }; 2D1A6CD5085135F9007CDBA8 /* AboutBox.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AboutBox.m; sourceTree = SOURCE_ROOT; }; 2D1A6CD808513610007CDBA8 /* AboutBox.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = AboutBox.nib; sourceTree = SOURCE_ROOT; }; 2D20F9E608C603EC00A73076 /* CpuWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CpuWidget.cxx; sourceTree = ""; }; 2D20F9E708C603EC00A73076 /* CpuWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CpuWidget.hxx; sourceTree = ""; }; 2D20F9E808C603EC00A73076 /* DataGridOpsWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DataGridOpsWidget.cxx; sourceTree = ""; }; 2D20F9E908C603EC00A73076 /* DataGridOpsWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = DataGridOpsWidget.hxx; sourceTree = ""; }; 2D20F9EA08C603EC00A73076 /* DataGridWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DataGridWidget.cxx; sourceTree = ""; }; 2D20F9EB08C603EC00A73076 /* DataGridWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = DataGridWidget.hxx; sourceTree = ""; }; 2D20F9EC08C603EC00A73076 /* DebuggerDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerDialog.cxx; sourceTree = ""; }; 2D20F9ED08C603EC00A73076 /* DebuggerDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = DebuggerDialog.hxx; sourceTree = ""; }; 2D20F9EE08C603EC00A73076 /* PromptWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PromptWidget.cxx; sourceTree = ""; }; 2D20F9EF08C603EC00A73076 /* PromptWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = PromptWidget.hxx; sourceTree = ""; }; 2D20F9F008C603EC00A73076 /* RamWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RamWidget.cxx; sourceTree = ""; }; 2D20F9F108C603EC00A73076 /* RamWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RamWidget.hxx; sourceTree = ""; }; 2D20F9F208C603EC00A73076 /* RomListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RomListWidget.cxx; sourceTree = ""; }; 2D20F9F308C603EC00A73076 /* RomListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RomListWidget.hxx; sourceTree = ""; }; 2D20F9F408C603EC00A73076 /* RomWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RomWidget.cxx; sourceTree = ""; }; 2D20F9F508C603EC00A73076 /* RomWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RomWidget.hxx; sourceTree = ""; }; 2D20F9F608C603EC00A73076 /* TiaInfoWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TiaInfoWidget.cxx; sourceTree = ""; }; 2D20F9F708C603EC00A73076 /* TiaInfoWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TiaInfoWidget.hxx; sourceTree = ""; }; 2D20F9F808C603EC00A73076 /* TiaOutputWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TiaOutputWidget.cxx; sourceTree = ""; }; 2D20F9F908C603EC00A73076 /* TiaOutputWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TiaOutputWidget.hxx; sourceTree = ""; }; 2D20F9FA08C603EC00A73076 /* TiaWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TiaWidget.cxx; sourceTree = ""; }; 2D20F9FB08C603EC00A73076 /* TiaWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TiaWidget.hxx; sourceTree = ""; }; 2D20F9FC08C603EC00A73076 /* ToggleBitWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ToggleBitWidget.cxx; sourceTree = ""; }; 2D20F9FD08C603EC00A73076 /* ToggleBitWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ToggleBitWidget.hxx; sourceTree = ""; }; 2D20F9FE08C603EC00A73076 /* TogglePixelWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TogglePixelWidget.cxx; sourceTree = ""; }; 2D20F9FF08C603EC00A73076 /* TogglePixelWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TogglePixelWidget.hxx; sourceTree = ""; }; 2D20FA0008C603EC00A73076 /* ToggleWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ToggleWidget.cxx; sourceTree = ""; }; 2D20FA0108C603EC00A73076 /* ToggleWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ToggleWidget.hxx; sourceTree = ""; }; 2D23318F0900B5EF00613B1F /* AudioWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AudioWidget.cxx; sourceTree = ""; }; 2D2331900900B5EF00613B1F /* AudioWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = AudioWidget.hxx; sourceTree = ""; }; 2D30F8750868A4DB00938B9D /* TIADebug.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TIADebug.cxx; sourceTree = ""; }; 2D30F8760868A4DB00938B9D /* TIADebug.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TIADebug.hxx; sourceTree = ""; }; 2D313F0A0879C4C0005BD3E5 /* YaccParser.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = YaccParser.cxx; sourceTree = ""; }; 2D313F0B0879C4C0005BD3E5 /* YaccParser.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = YaccParser.hxx; sourceTree = ""; }; 2D403BA0086116D1001E31A1 /* EditableWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; path = EditableWidget.cxx; sourceTree = ""; tabWidth = 2; }; 2D403BA1086116D1001E31A1 /* EditableWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = EditableWidget.hxx; sourceTree = ""; }; 2D403BA4086116D1001E31A1 /* EditTextWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = EditTextWidget.cxx; sourceTree = ""; }; 2D403BA5086116D1001E31A1 /* EditTextWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = EditTextWidget.hxx; sourceTree = ""; }; 2D403BCF08611A69001E31A1 /* PackedBitArray.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = PackedBitArray.hxx; sourceTree = ""; }; 2D659E2D085D3DD6005D96C8 /* Debugger.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Debugger.cxx; sourceTree = ""; }; 2D659E2E085D3DD6005D96C8 /* Debugger.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Debugger.hxx; sourceTree = ""; }; 2D659E31085D3DD6005D96C8 /* DebuggerParser.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerParser.cxx; sourceTree = ""; }; 2D659E32085D3DD6005D96C8 /* DebuggerParser.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = DebuggerParser.hxx; sourceTree = ""; }; 2D6CC10308C811A600B8F642 /* TiaZoomWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = TiaZoomWidget.cxx; path = gui/TiaZoomWidget.cxx; sourceTree = ""; }; 2D6CC10408C811A600B8F642 /* TiaZoomWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; name = TiaZoomWidget.hxx; path = gui/TiaZoomWidget.hxx; sourceTree = ""; }; 2D733D6E062895B2006265D9 /* EventHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = EventHandler.cxx; sourceTree = ""; }; 2D733D6F062895B2006265D9 /* EventHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 2; lastKnownFileType = sourcecode.cpp.h; path = EventHandler.hxx; sourceTree = ""; tabWidth = 2; }; 2D733D70062895B2006265D9 /* FrameBuffer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FrameBuffer.cxx; sourceTree = ""; }; 2D733D71062895B2006265D9 /* FrameBuffer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = FrameBuffer.hxx; sourceTree = ""; }; 2D733D77062895F1006265D9 /* Settings.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Settings.hxx; sourceTree = ""; }; 2D73959308C3EB4E0060BB99 /* CommandDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CommandDialog.cxx; sourceTree = ""; }; 2D73959408C3EB4E0060BB99 /* CommandDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CommandDialog.hxx; sourceTree = ""; }; 2D73959508C3EB4E0060BB99 /* CommandMenu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CommandMenu.cxx; sourceTree = ""; }; 2D73959608C3EB4E0060BB99 /* CommandMenu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CommandMenu.hxx; sourceTree = ""; }; 2D7B4F6C063B513200579B93 /* Credits.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; path = Credits.html; sourceTree = SOURCE_ROOT; }; 2D9217FA0857CC88001D664B /* ConsoleFont.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ConsoleFont.hxx; sourceTree = ""; }; 2D9217FB0857CC88001D664B /* Font.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Font.cxx; sourceTree = ""; }; 2D9217FC0857CC88001D664B /* Font.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Font.hxx; sourceTree = ""; }; 2D944848062904E800DD9879 /* Settings.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Settings.cxx; sourceTree = ""; }; 2D944866062911CD00DD9879 /* SettingsMACOSX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SettingsMACOSX.cxx; sourceTree = ""; }; 2D94486C0629124700DD9879 /* SettingsMACOSX.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = SettingsMACOSX.hxx; sourceTree = ""; }; 2D9555D90880E78000466554 /* Cart3E.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Cart3E.cxx; sourceTree = ""; }; 2D9555DA0880E78000466554 /* Cart3E.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Cart3E.hxx; sourceTree = ""; }; 2D9555DD0880E79600466554 /* CpuDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CpuDebug.cxx; sourceTree = ""; }; 2D9555DE0880E79600466554 /* CpuDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CpuDebug.hxx; sourceTree = ""; }; 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FSNodePOSIX.cxx; sourceTree = ""; }; 2DDBEA0E0845709700812C11 /* OSystemMACOSX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = OSystemMACOSX.cxx; sourceTree = ""; }; 2DDBEA0F0845709700812C11 /* OSystemMACOSX.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = OSystemMACOSX.hxx; sourceTree = ""; }; 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AboutDialog.cxx; sourceTree = ""; }; 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = AboutDialog.hxx; sourceTree = ""; }; 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AudioDialog.cxx; sourceTree = ""; }; 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = AudioDialog.hxx; sourceTree = ""; }; 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = BrowserDialog.cxx; sourceTree = ""; }; 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = BrowserDialog.hxx; sourceTree = ""; }; 2DDBEAAA084578BF00812C11 /* Command.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Command.hxx; sourceTree = ""; }; 2DDBEAAB084578BF00812C11 /* Dialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Dialog.cxx; sourceTree = ""; }; 2DDBEAAC084578BF00812C11 /* Dialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Dialog.hxx; sourceTree = ""; }; 2DDBEAAD084578BF00812C11 /* DialogContainer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DialogContainer.cxx; sourceTree = ""; }; 2DDBEAAE084578BF00812C11 /* DialogContainer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = DialogContainer.hxx; sourceTree = ""; }; 2DDBEAB2084578BF00812C11 /* GameInfoDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GameInfoDialog.cxx; sourceTree = ""; }; 2DDBEAB3084578BF00812C11 /* GameInfoDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = GameInfoDialog.hxx; sourceTree = ""; }; 2DDBEAB4084578BF00812C11 /* GameList.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GameList.cxx; sourceTree = ""; }; 2DDBEAB5084578BF00812C11 /* GameList.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = GameList.hxx; sourceTree = ""; }; 2DDBEAB6084578BF00812C11 /* GuiObject.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = GuiObject.hxx; sourceTree = ""; }; 2DDBEAB8084578BF00812C11 /* HelpDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = HelpDialog.cxx; sourceTree = ""; }; 2DDBEAB9084578BF00812C11 /* HelpDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = HelpDialog.hxx; sourceTree = ""; }; 2DDBEABA084578BF00812C11 /* Launcher.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Launcher.cxx; sourceTree = ""; }; 2DDBEABB084578BF00812C11 /* Launcher.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Launcher.hxx; sourceTree = ""; }; 2DDBEABC084578BF00812C11 /* LauncherDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LauncherDialog.cxx; sourceTree = ""; }; 2DDBEABD084578BF00812C11 /* LauncherDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = LauncherDialog.hxx; sourceTree = ""; }; 2DDBEAC0084578BF00812C11 /* ListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ListWidget.cxx; sourceTree = ""; }; 2DDBEAC1084578BF00812C11 /* ListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ListWidget.hxx; sourceTree = ""; }; 2DDBEAC2084578BF00812C11 /* Menu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Menu.cxx; sourceTree = ""; }; 2DDBEAC3084578BF00812C11 /* Menu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Menu.hxx; sourceTree = ""; }; 2DDBEAC4084578BF00812C11 /* OptionsDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = OptionsDialog.cxx; sourceTree = ""; }; 2DDBEAC5084578BF00812C11 /* OptionsDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = OptionsDialog.hxx; sourceTree = ""; }; 2DDBEAC6084578BF00812C11 /* PopUpWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PopUpWidget.cxx; sourceTree = ""; }; 2DDBEAC7084578BF00812C11 /* PopUpWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = PopUpWidget.hxx; sourceTree = ""; }; 2DDBEAC8084578BF00812C11 /* ProgressDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ProgressDialog.cxx; sourceTree = ""; }; 2DDBEAC9084578BF00812C11 /* ProgressDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ProgressDialog.hxx; sourceTree = ""; }; 2DDBEACA084578BF00812C11 /* ScrollBarWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollBarWidget.cxx; sourceTree = ""; }; 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ScrollBarWidget.hxx; sourceTree = ""; }; 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TabWidget.cxx; sourceTree = ""; }; 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TabWidget.hxx; sourceTree = ""; }; 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = VideoDialog.cxx; sourceTree = ""; }; 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = VideoDialog.hxx; sourceTree = ""; }; 2DDBEAD4084578BF00812C11 /* Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Widget.cxx; sourceTree = ""; }; 2DDBEAD5084578BF00812C11 /* Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Widget.hxx; sourceTree = ""; }; 2DDBEB7008457B7D00812C11 /* CartUA.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartUA.cxx; sourceTree = ""; }; 2DDBEB7108457B7D00812C11 /* CartUA.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartUA.hxx; sourceTree = ""; }; 2DDBEB7208457B7D00812C11 /* FSNode.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FSNode.cxx; sourceTree = ""; }; 2DDBEB7308457B7D00812C11 /* FSNode.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = FSNode.hxx; sourceTree = ""; }; 2DDBEB7408457B7D00812C11 /* OSystem.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = OSystem.cxx; sourceTree = ""; }; 2DDBEB7508457B7D00812C11 /* OSystem.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = OSystem.hxx; sourceTree = ""; }; 2DDBEBE3084582C400812C11 /* Preferences.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = SOURCE_ROOT; }; 2DDBEBE4084582C400812C11 /* Preferences.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = Preferences.m; sourceTree = SOURCE_ROOT; }; 2DE2DF100627AE07006BEC99 /* Booster.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Booster.cxx; sourceTree = ""; }; 2DE2DF110627AE07006BEC99 /* Booster.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Booster.hxx; sourceTree = ""; }; 2DE2DF120627AE07006BEC99 /* Cart.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Cart.cxx; sourceTree = ""; }; 2DE2DF130627AE07006BEC99 /* Cart.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Cart.hxx; sourceTree = ""; }; 2DE2DF140627AE07006BEC99 /* Cart2K.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Cart2K.cxx; sourceTree = ""; }; 2DE2DF150627AE07006BEC99 /* Cart2K.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Cart2K.hxx; sourceTree = ""; }; 2DE2DF160627AE07006BEC99 /* Cart3F.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Cart3F.cxx; sourceTree = ""; }; 2DE2DF170627AE07006BEC99 /* Cart3F.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Cart3F.hxx; sourceTree = ""; }; 2DE2DF180627AE07006BEC99 /* Cart4K.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Cart4K.cxx; sourceTree = ""; }; 2DE2DF190627AE07006BEC99 /* Cart4K.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Cart4K.hxx; sourceTree = ""; }; 2DE2DF1A0627AE07006BEC99 /* CartAR.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartAR.cxx; sourceTree = ""; }; 2DE2DF1B0627AE07006BEC99 /* CartAR.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartAR.hxx; sourceTree = ""; }; 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartCV.cxx; sourceTree = ""; }; 2DE2DF1D0627AE07006BEC99 /* CartCV.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartCV.hxx; sourceTree = ""; }; 2DE2DF1E0627AE07006BEC99 /* CartDPC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartDPC.cxx; sourceTree = ""; }; 2DE2DF1F0627AE07006BEC99 /* CartDPC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartDPC.hxx; sourceTree = ""; }; 2DE2DF200627AE07006BEC99 /* CartE0.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartE0.cxx; sourceTree = ""; }; 2DE2DF210627AE07006BEC99 /* CartE0.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartE0.hxx; sourceTree = ""; }; 2DE2DF220627AE07006BEC99 /* CartE7.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartE7.cxx; sourceTree = ""; }; 2DE2DF230627AE07006BEC99 /* CartE7.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartE7.hxx; sourceTree = ""; }; 2DE2DF240627AE07006BEC99 /* CartF4.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartF4.cxx; sourceTree = ""; }; 2DE2DF250627AE07006BEC99 /* CartF4.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartF4.hxx; sourceTree = ""; }; 2DE2DF260627AE07006BEC99 /* CartF4SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartF4SC.cxx; sourceTree = ""; }; 2DE2DF270627AE07006BEC99 /* CartF4SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartF4SC.hxx; sourceTree = ""; }; 2DE2DF280627AE07006BEC99 /* CartF6.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartF6.cxx; sourceTree = ""; }; 2DE2DF290627AE07006BEC99 /* CartF6.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartF6.hxx; sourceTree = ""; }; 2DE2DF2A0627AE07006BEC99 /* CartF6SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartF6SC.cxx; sourceTree = ""; }; 2DE2DF2B0627AE07006BEC99 /* CartF6SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartF6SC.hxx; sourceTree = ""; }; 2DE2DF2C0627AE07006BEC99 /* CartF8.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartF8.cxx; sourceTree = ""; }; 2DE2DF2D0627AE07006BEC99 /* CartF8.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartF8.hxx; sourceTree = ""; }; 2DE2DF2E0627AE07006BEC99 /* CartF8SC.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartF8SC.cxx; sourceTree = ""; }; 2DE2DF2F0627AE07006BEC99 /* CartF8SC.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartF8SC.hxx; sourceTree = ""; }; 2DE2DF320627AE07006BEC99 /* CartFE.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartFE.cxx; sourceTree = ""; }; 2DE2DF330627AE07006BEC99 /* CartFE.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartFE.hxx; sourceTree = ""; }; 2DE2DF380627AE07006BEC99 /* Console.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Console.cxx; sourceTree = ""; }; 2DE2DF390627AE07006BEC99 /* Console.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Console.hxx; sourceTree = ""; }; 2DE2DF3A0627AE07006BEC99 /* Control.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Control.cxx; sourceTree = ""; }; 2DE2DF3B0627AE07006BEC99 /* Control.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Control.hxx; sourceTree = ""; }; 2DE2DF3E0627AE07006BEC99 /* Driving.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Driving.cxx; sourceTree = ""; }; 2DE2DF3F0627AE07006BEC99 /* Driving.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Driving.hxx; sourceTree = ""; }; 2DE2DF410627AE07006BEC99 /* Event.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Event.hxx; sourceTree = ""; }; 2DE2DF420627AE07006BEC99 /* Joystick.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Joystick.cxx; sourceTree = ""; }; 2DE2DF430627AE07006BEC99 /* Joystick.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Joystick.hxx; sourceTree = ""; }; 2DE2DF440627AE07006BEC99 /* Keyboard.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cxx; sourceTree = ""; }; 2DE2DF450627AE07006BEC99 /* Keyboard.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hxx; sourceTree = ""; }; 2DE2DF7C0627AE33006BEC99 /* M6532.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = M6532.cxx; sourceTree = ""; }; 2DE2DF7D0627AE33006BEC99 /* M6532.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = M6532.hxx; sourceTree = ""; }; 2DE2DF7E0627AE33006BEC99 /* MD5.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MD5.cxx; sourceTree = ""; }; 2DE2DF7F0627AE34006BEC99 /* MD5.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MD5.hxx; sourceTree = ""; }; 2DE2DF820627AE34006BEC99 /* Paddles.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Paddles.cxx; sourceTree = ""; }; 2DE2DF830627AE34006BEC99 /* Paddles.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Paddles.hxx; sourceTree = ""; }; 2DE2DF840627AE34006BEC99 /* Props.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Props.cxx; sourceTree = ""; }; 2DE2DF850627AE34006BEC99 /* Props.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Props.hxx; sourceTree = ""; }; 2DE2DF860627AE34006BEC99 /* PropsSet.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PropsSet.cxx; sourceTree = ""; }; 2DE2DF870627AE34006BEC99 /* PropsSet.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = PropsSet.hxx; sourceTree = ""; }; 2DE2DF890627AE34006BEC99 /* Random.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Random.hxx; sourceTree = ""; }; 2DE2DF8A0627AE34006BEC99 /* Serializer.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Serializer.cxx; sourceTree = ""; }; 2DE2DF8B0627AE34006BEC99 /* Serializer.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Serializer.hxx; sourceTree = ""; }; 2DE2DF8D0627AE34006BEC99 /* Sound.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Sound.hxx; sourceTree = ""; }; 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Switches.cxx; sourceTree = ""; }; 2DE2DF8F0627AE34006BEC99 /* Switches.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Switches.hxx; sourceTree = ""; }; 2DE7242D08CE910900C889A8 /* TIASnd.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TIASnd.cxx; sourceTree = ""; }; 2DE7242E08CE910900C889A8 /* TIASnd.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = TIASnd.hxx; sourceTree = ""; }; 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; 2DEF21F808BC033500B246B4 /* CheckListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CheckListWidget.cxx; sourceTree = ""; }; 2DEF21F908BC033500B246B4 /* CheckListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CheckListWidget.hxx; sourceTree = ""; }; 2DEF21FA08BC033500B246B4 /* StringListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = StringListWidget.cxx; sourceTree = ""; }; 2DEF21FB08BC033500B246B4 /* StringListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = StringListWidget.hxx; sourceTree = ""; }; 2DEFB40B09C3386F00754289 /* Cart.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Cart.icns; sourceTree = SOURCE_ROOT; }; 2DF971D70892CEA400F64D23 /* DebuggerSystem.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = DebuggerSystem.hxx; sourceTree = ""; }; 2DF971DF0892CEA400F64D23 /* Expression.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Expression.hxx; sourceTree = ""; }; 55FE2A3D1EE487CA00078ADE /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; B2F367C504C7ADC700A80002 /* SDLMain.nib */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; path = SDLMain.nib; sourceTree = ""; }; CFE3F6071E84A9A200A8204E /* CartBUSWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartBUSWidget.cxx; sourceTree = ""; }; CFE3F6081E84A9A200A8204E /* CartBUSWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartBUSWidget.hxx; sourceTree = ""; }; CFE3F6091E84A9A200A8204E /* CartCDFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCDFWidget.cxx; sourceTree = ""; }; CFE3F60A1E84A9A200A8204E /* CartCDFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCDFWidget.hxx; sourceTree = ""; }; CFE3F60F1E84A9CE00A8204E /* CartBUS.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartBUS.cxx; sourceTree = ""; }; CFE3F6101E84A9CE00A8204E /* CartBUS.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartBUS.hxx; sourceTree = ""; }; CFE3F6111E84A9CE00A8204E /* CartCDF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCDF.cxx; sourceTree = ""; }; CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCDF.hxx; sourceTree = ""; }; DC047FEC1A4A6F3600348F0F /* JoystickDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JoystickDialog.cxx; sourceTree = ""; }; DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = JoystickDialog.hxx; sourceTree = ""; }; DC0984830D3985160073C852 /* CartSB.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartSB.cxx; sourceTree = ""; }; DC0984840D3985160073C852 /* CartSB.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartSB.hxx; sourceTree = ""; }; DC0DF8670F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GlobalPropsDialog.cxx; sourceTree = ""; }; DC0DF8680F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GlobalPropsDialog.hxx; sourceTree = ""; }; DC11F78B0DB36933003B505E /* MT24LC256.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MT24LC256.cxx; sourceTree = ""; }; DC11F78C0DB36933003B505E /* MT24LC256.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = MT24LC256.hxx; sourceTree = ""; }; DC13B53D176FF2F500B8B4BB /* RomListSettings.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RomListSettings.cxx; sourceTree = ""; }; DC13B53E176FF2F500B8B4BB /* RomListSettings.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RomListSettings.hxx; sourceTree = ""; }; DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = ContextMenu.cxx; sourceTree = ""; }; DC173F750E2CAC1E00320F94 /* ContextMenu.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = ContextMenu.hxx; sourceTree = ""; }; DC1B2EBE1E50036100F62837 /* AmigaMouse.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AmigaMouse.hxx; sourceTree = ""; }; DC1B2EC01E50036100F62837 /* AtariMouse.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AtariMouse.hxx; sourceTree = ""; }; DC1B2EC21E50036100F62837 /* TrakBall.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrakBall.hxx; sourceTree = ""; }; DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SerialPortMACOSX.cxx; sourceTree = ""; }; DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = SerialPortMACOSX.hxx; sourceTree = ""; }; DC2874061F8F2278004BF21A /* TrapArray.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrapArray.hxx; sourceTree = ""; }; DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDASH.cxx; sourceTree = ""; }; DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDASH.hxx; sourceTree = ""; }; DC2AADAC194F389C0026C7A4 /* TIASurface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIASurface.cxx; sourceTree = ""; }; DC2AADAD194F389C0026C7A4 /* TIASurface.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIASurface.hxx; sourceTree = ""; }; DC2AADB2194F390F0026C7A4 /* CartRamWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartRamWidget.cxx; sourceTree = ""; }; DC2AADB3194F390F0026C7A4 /* CartRamWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartRamWidget.hxx; sourceTree = ""; }; DC2B85E51EF5EF2300379EB9 /* AtariNTSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AtariNTSC.cxx; sourceTree = ""; }; DC2B85E61EF5EF2300379EB9 /* AtariNTSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AtariNTSC.hxx; sourceTree = ""; }; DC2C5EDA1F8F2403007D2A09 /* smartmod.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = smartmod.hxx; sourceTree = ""; }; DC368F5018A2FB710084199C /* FrameBufferSDL2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameBufferSDL2.cxx; sourceTree = ""; }; DC368F5118A2FB710084199C /* FrameBufferSDL2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FrameBufferSDL2.hxx; sourceTree = ""; }; DC368F5218A2FB710084199C /* SoundSDL2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SoundSDL2.cxx; sourceTree = ""; }; DC368F5318A2FB710084199C /* SoundSDL2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SoundSDL2.hxx; sourceTree = ""; }; DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFA2.cxx; sourceTree = ""; }; DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFA2.hxx; sourceTree = ""; }; DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PointingDevice.hxx; sourceTree = ""; }; DC3EE83C1E2C0E6D00905161 /* adler32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adler32.c; sourceTree = ""; }; DC3EE83D1E2C0E6D00905161 /* compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compress.c; sourceTree = ""; }; DC3EE83E1E2C0E6D00905161 /* crc32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = crc32.c; sourceTree = ""; }; DC3EE83F1E2C0E6D00905161 /* crc32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crc32.h; sourceTree = ""; }; DC3EE8401E2C0E6D00905161 /* deflate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = deflate.c; sourceTree = ""; }; DC3EE8411E2C0E6D00905161 /* deflate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = deflate.h; sourceTree = ""; }; DC3EE8421E2C0E6D00905161 /* gzclose.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gzclose.c; sourceTree = ""; }; DC3EE8431E2C0E6D00905161 /* gzguts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gzguts.h; sourceTree = ""; }; DC3EE8441E2C0E6D00905161 /* gzlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gzlib.c; sourceTree = ""; }; DC3EE8451E2C0E6D00905161 /* gzread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gzread.c; sourceTree = ""; }; DC3EE8461E2C0E6D00905161 /* gzwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gzwrite.c; sourceTree = ""; }; DC3EE8471E2C0E6D00905161 /* infback.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = infback.c; sourceTree = ""; }; DC3EE8481E2C0E6D00905161 /* inffast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inffast.c; sourceTree = ""; }; DC3EE8491E2C0E6D00905161 /* inffast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inffast.h; sourceTree = ""; }; DC3EE84A1E2C0E6D00905161 /* inffixed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inffixed.h; sourceTree = ""; }; DC3EE84B1E2C0E6D00905161 /* inflate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inflate.c; sourceTree = ""; }; DC3EE84C1E2C0E6D00905161 /* inflate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inflate.h; sourceTree = ""; }; DC3EE84D1E2C0E6D00905161 /* inftrees.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inftrees.c; sourceTree = ""; }; DC3EE84E1E2C0E6D00905161 /* inftrees.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inftrees.h; sourceTree = ""; }; DC3EE84F1E2C0E6D00905161 /* trees.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trees.c; sourceTree = ""; }; DC3EE8501E2C0E6D00905161 /* trees.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trees.h; sourceTree = ""; }; DC3EE8511E2C0E6D00905161 /* uncompr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uncompr.c; sourceTree = ""; }; DC3EE8521E2C0E6D00905161 /* zconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zconf.h; sourceTree = ""; }; DC3EE8531E2C0E6D00905161 /* zlib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zlib.h; sourceTree = ""; }; DC3EE8541E2C0E6D00905161 /* zutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zutil.c; sourceTree = ""; }; DC3EE8551E2C0E6D00905161 /* zutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zutil.h; sourceTree = ""; }; DC44019C1F1A5D01008C08F6 /* ColorWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColorWidget.cxx; sourceTree = ""; }; DC44019D1F1A5D01008C08F6 /* ColorWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ColorWidget.hxx; sourceTree = ""; }; DC4613650D92C03600D8DAB9 /* RomAuditDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RomAuditDialog.cxx; sourceTree = ""; }; DC4613660D92C03600D8DAB9 /* RomAuditDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RomAuditDialog.hxx; sourceTree = ""; }; DC47454A09C34BFA00EDDA3A /* BankRomCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = BankRomCheat.cxx; sourceTree = ""; }; DC47454B09C34BFA00EDDA3A /* BankRomCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = BankRomCheat.hxx; sourceTree = ""; }; DC47454C09C34BFA00EDDA3A /* Cheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Cheat.hxx; sourceTree = ""; }; DC47454D09C34BFA00EDDA3A /* CheatCodeDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CheatCodeDialog.cxx; sourceTree = ""; }; DC47454E09C34BFA00EDDA3A /* CheatCodeDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CheatCodeDialog.hxx; sourceTree = ""; }; DC47454F09C34BFA00EDDA3A /* CheatManager.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CheatManager.cxx; sourceTree = ""; }; DC47455009C34BFA00EDDA3A /* CheatManager.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CheatManager.hxx; sourceTree = ""; }; DC47455109C34BFA00EDDA3A /* CheetahCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CheetahCheat.cxx; sourceTree = ""; }; DC47455209C34BFA00EDDA3A /* CheetahCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CheetahCheat.hxx; sourceTree = ""; }; DC47455309C34BFA00EDDA3A /* RamCheat.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RamCheat.cxx; sourceTree = ""; }; DC47455409C34BFA00EDDA3A /* RamCheat.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RamCheat.hxx; sourceTree = ""; }; DC487FB40DA5350900E12499 /* AtariVox.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AtariVox.cxx; sourceTree = ""; }; DC487FB50DA5350900E12499 /* AtariVox.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = AtariVox.hxx; sourceTree = ""; }; DC4AC6ED0DC8DACB00CD3AD2 /* RiotWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RiotWidget.cxx; sourceTree = ""; }; DC4AC6EE0DC8DACB00CD3AD2 /* RiotWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RiotWidget.hxx; sourceTree = ""; }; DC4AC6F10DC8DAEF00CD3AD2 /* SaveKey.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SaveKey.cxx; sourceTree = ""; }; DC4AC6F20DC8DAEF00CD3AD2 /* SaveKey.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = SaveKey.hxx; sourceTree = ""; }; DC53B6AD1F3622DA00AA6BFB /* PointingDevice.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PointingDevice.cxx; sourceTree = ""; }; DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MouseControl.cxx; sourceTree = ""; }; DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MouseControl.hxx; sourceTree = ""; }; DC5AAC261FCB24AB00C420A6 /* EventHandlerConstants.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = EventHandlerConstants.hxx; sourceTree = ""; }; DC5AAC271FCB24AB00C420A6 /* FrameBufferConstants.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FrameBufferConstants.hxx; sourceTree = ""; }; DC5AAC2A1FCB24DF00C420A6 /* RadioButtonWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RadioButtonWidget.cxx; sourceTree = ""; }; DC5AAC2B1FCB24DF00C420A6 /* RadioButtonWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RadioButtonWidget.hxx; sourceTree = ""; }; DC5ACB591FBFCE8E00A213FD /* DeveloperDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeveloperDialog.cxx; sourceTree = ""; }; DC5ACB5A1FBFCE8E00A213FD /* DeveloperDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DeveloperDialog.hxx; sourceTree = ""; }; DC5ACB5D1FBFCEB800A213FD /* CartDebugWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDebugWidget.cxx; sourceTree = ""; }; DC5BE4B117C913AC0091FD64 /* ConsoleBFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConsoleBFont.hxx; sourceTree = ""; }; DC5BE4B217C913AC0091FD64 /* ConsoleMediumBFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConsoleMediumBFont.hxx; sourceTree = ""; }; DC5C768E14C26F7C0031EBC7 /* StellaKeys.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StellaKeys.hxx; sourceTree = ""; }; DC5D1AA6102C6FC900E59AC1 /* Stack.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stack.hxx; sourceTree = ""; }; DC5D2C4E0F117CFD004D1660 /* Rect.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Rect.hxx; sourceTree = ""; }; DC5D2C4F0F117CFD004D1660 /* StellaFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StellaFont.hxx; sourceTree = ""; }; DC5D2C500F117CFD004D1660 /* StellaLargeFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StellaLargeFont.hxx; sourceTree = ""; }; DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StellaMediumFont.hxx; sourceTree = ""; }; DC5D2C5E0F129B1E004D1660 /* LauncherFilterDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LauncherFilterDialog.cxx; sourceTree = ""; }; DC5D2C5F0F129B1E004D1660 /* LauncherFilterDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LauncherFilterDialog.hxx; sourceTree = ""; }; DC5E473A19EC9A14000E45DF /* EventJoyHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventJoyHandler.cxx; sourceTree = ""; }; DC5EE7C014F7C165001C628C /* NTSCFilter.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NTSCFilter.cxx; sourceTree = ""; }; DC5EE7C114F7C165001C628C /* NTSCFilter.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = NTSCFilter.hxx; sourceTree = ""; }; DC62E6431960E87B007AEF05 /* AtariVoxWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AtariVoxWidget.cxx; sourceTree = ""; }; DC62E6441960E87B007AEF05 /* AtariVoxWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AtariVoxWidget.hxx; sourceTree = ""; }; DC62E6451960E87B007AEF05 /* SaveKeyWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SaveKeyWidget.cxx; sourceTree = ""; }; DC62E6461960E87B007AEF05 /* SaveKeyWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SaveKeyWidget.hxx; sourceTree = ""; }; DC6727081556F4860023653B /* CartCTY.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCTY.cxx; sourceTree = ""; }; DC6727091556F4860023653B /* CartCTY.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCTY.hxx; sourceTree = ""; }; DC67270A1556F4860023653B /* CartCTYTunes.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCTYTunes.hxx; sourceTree = ""; }; DC676A251729A0B000E4E73D /* Cart3EWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart3EWidget.cxx; sourceTree = ""; }; DC676A261729A0B000E4E73D /* Cart3EWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart3EWidget.hxx; sourceTree = ""; }; DC676A271729A0B000E4E73D /* Cart4A50Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart4A50Widget.cxx; sourceTree = ""; }; DC676A281729A0B000E4E73D /* Cart4A50Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart4A50Widget.hxx; sourceTree = ""; }; DC676A291729A0B000E4E73D /* CartARWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartARWidget.cxx; sourceTree = ""; }; DC676A2A1729A0B000E4E73D /* CartARWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartARWidget.hxx; sourceTree = ""; }; DC676A2B1729A0B000E4E73D /* CartCMWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCMWidget.cxx; sourceTree = ""; }; DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCMWidget.hxx; sourceTree = ""; }; DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCTYWidget.cxx; sourceTree = ""; }; DC676A2E1729A0B000E4E73D /* CartCTYWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCTYWidget.hxx; sourceTree = ""; }; DC676A2F1729A0B000E4E73D /* CartDPCPlusWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDPCPlusWidget.cxx; sourceTree = ""; }; DC676A301729A0B000E4E73D /* CartDPCPlusWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDPCPlusWidget.hxx; sourceTree = ""; }; DC676A311729A0B000E4E73D /* CartDPCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDPCWidget.cxx; sourceTree = ""; }; DC676A321729A0B000E4E73D /* CartDPCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDPCWidget.hxx; sourceTree = ""; }; DC676A331729A0B000E4E73D /* CartE0Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartE0Widget.cxx; sourceTree = ""; }; DC676A341729A0B000E4E73D /* CartE0Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartE0Widget.hxx; sourceTree = ""; }; DC676A351729A0B000E4E73D /* CartE7Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartE7Widget.cxx; sourceTree = ""; }; DC676A361729A0B000E4E73D /* CartE7Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartE7Widget.hxx; sourceTree = ""; }; DC676A371729A0B000E4E73D /* CartFA2Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFA2Widget.cxx; sourceTree = ""; }; DC676A381729A0B000E4E73D /* CartFA2Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFA2Widget.hxx; sourceTree = ""; }; DC676A391729A0B000E4E73D /* CartFEWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFEWidget.cxx; sourceTree = ""; }; DC676A3A1729A0B000E4E73D /* CartFEWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFEWidget.hxx; sourceTree = ""; }; DC676A3D1729A0B000E4E73D /* CartSBWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartSBWidget.cxx; sourceTree = ""; }; DC676A3E1729A0B000E4E73D /* CartSBWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartSBWidget.hxx; sourceTree = ""; }; DC676A3F1729A0B000E4E73D /* CartX07Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartX07Widget.cxx; sourceTree = ""; }; DC676A401729A0B000E4E73D /* CartX07Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartX07Widget.hxx; sourceTree = ""; }; DC68F88F1FA64C5300F4A2CC /* TIAConstants.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIAConstants.hxx; sourceTree = ""; }; DC6967071361FD0A0036499D /* pngdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngdebug.h; sourceTree = ""; }; DC6967081361FD0A0036499D /* pnginfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pnginfo.h; sourceTree = ""; }; DC6967091361FD0A0036499D /* pnglibconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pnglibconf.h; sourceTree = ""; }; DC69670A1361FD0A0036499D /* pngstruct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngstruct.h; sourceTree = ""; }; DC6A18F619B3E65500DEB242 /* CartMDMWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartMDMWidget.cxx; sourceTree = ""; }; DC6A18F719B3E65500DEB242 /* CartMDMWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartMDMWidget.hxx; sourceTree = ""; }; DC6A18FA19B3E67A00DEB242 /* CartMDM.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartMDM.cxx; sourceTree = ""; }; DC6A18FB19B3E67A00DEB242 /* CartMDM.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartMDM.hxx; sourceTree = ""; }; DC6B2BA011037FF200F199A7 /* CartDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDebug.cxx; sourceTree = ""; }; DC6B2BA111037FF200F199A7 /* CartDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDebug.hxx; sourceTree = ""; }; DC6B2BA211037FF200F199A7 /* DiStella.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiStella.cxx; sourceTree = ""; }; DC6B2BA311037FF200F199A7 /* DiStella.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiStella.hxx; sourceTree = ""; }; DC6C726013CDEA0A008A5975 /* LoggerDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoggerDialog.cxx; sourceTree = ""; }; DC6C726113CDEA0A008A5975 /* LoggerDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LoggerDialog.hxx; sourceTree = ""; }; DC6D39851A3CE65000171E71 /* CartWDWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartWDWidget.cxx; sourceTree = ""; }; DC6D39861A3CE65000171E71 /* CartWDWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartWDWidget.hxx; sourceTree = ""; }; DC71EA991FDA06D2008827CB /* CartE78K.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartE78K.cxx; sourceTree = ""; }; DC71EA9A1FDA06D2008827CB /* CartE78K.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartE78K.hxx; sourceTree = ""; }; DC71EA9B1FDA06D2008827CB /* CartMNetwork.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartMNetwork.cxx; sourceTree = ""; }; DC71EA9C1FDA06D2008827CB /* CartMNetwork.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartMNetwork.hxx; sourceTree = ""; }; DC71EAA11FDA070D008827CB /* CartE78KWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartE78KWidget.cxx; sourceTree = ""; }; DC71EAA21FDA070D008827CB /* CartE78KWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartE78KWidget.hxx; sourceTree = ""; }; DC71EAA31FDA070D008827CB /* CartMNetworkWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartMNetworkWidget.cxx; sourceTree = ""; }; DC71EAA41FDA070D008827CB /* CartMNetworkWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartMNetworkWidget.hxx; sourceTree = ""; }; DC73BD831915E5B1003FAFAD /* FBSurfaceSDL2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FBSurfaceSDL2.cxx; sourceTree = ""; }; DC73BD841915E5B1003FAFAD /* FBSurfaceSDL2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FBSurfaceSDL2.hxx; sourceTree = ""; }; DC73BD871915E5E3003FAFAD /* FBSurface.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FBSurface.cxx; sourceTree = ""; }; DC73BD881915E5E3003FAFAD /* FBSurface.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FBSurface.hxx; sourceTree = ""; }; DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StringParser.hxx; sourceTree = ""; }; DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDASHWidget.cxx; sourceTree = ""; }; DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDASHWidget.hxx; sourceTree = ""; }; DC79F81017A88D9E00288B91 /* Base.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Base.cxx; sourceTree = ""; }; DC79F81117A88D9E00288B91 /* Base.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Base.hxx; sourceTree = ""; }; DC7A24D4173B1CF600B20FE9 /* Variant.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Variant.hxx; sourceTree = ""; }; DC7A24DD173B1DBC00B20FE9 /* FileListWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileListWidget.cxx; sourceTree = ""; }; DC7A24DE173B1DBC00B20FE9 /* FileListWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FileListWidget.hxx; sourceTree = ""; }; DC8078DA0B4BD5F3005E9305 /* DebuggerExpressions.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = DebuggerExpressions.hxx; sourceTree = ""; }; DC8078E60B4BD697005E9305 /* UIDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = UIDialog.cxx; sourceTree = ""; }; DC8078E70B4BD697005E9305 /* UIDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = UIDialog.hxx; sourceTree = ""; }; DC8C1BA714B25DE7006440EE /* CartCM.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCM.cxx; sourceTree = ""; }; DC8C1BA814B25DE7006440EE /* CartCM.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCM.hxx; sourceTree = ""; }; DC8C1BA914B25DE7006440EE /* CompuMate.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CompuMate.cxx; sourceTree = ""; }; DC8C1BAA14B25DE7006440EE /* CompuMate.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CompuMate.hxx; sourceTree = ""; }; DC8C1BAB14B25DE7006440EE /* MindLink.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MindLink.cxx; sourceTree = ""; }; DC8C1BAC14B25DE7006440EE /* MindLink.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MindLink.hxx; sourceTree = ""; }; DC8CF9BC17C15A27004B533D /* ConsoleMediumFont.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConsoleMediumFont.hxx; sourceTree = ""; }; DC932D3F0F278A5200FEFEFC /* DefProps.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DefProps.hxx; sourceTree = ""; }; DC932D400F278A5200FEFEFC /* Serializable.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Serializable.hxx; sourceTree = ""; }; DC932D410F278A5200FEFEFC /* SerialPort.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SerialPort.hxx; sourceTree = ""; }; DC9616221F817830008A2206 /* AmigaMouseWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AmigaMouseWidget.cxx; sourceTree = ""; }; DC9616231F817830008A2206 /* AmigaMouseWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AmigaMouseWidget.hxx; sourceTree = ""; }; DC9616241F817830008A2206 /* AtariMouseWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AtariMouseWidget.cxx; sourceTree = ""; }; DC9616251F817830008A2206 /* AtariMouseWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AtariMouseWidget.hxx; sourceTree = ""; }; DC9616261F817830008A2206 /* FlashWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FlashWidget.cxx; sourceTree = ""; }; DC9616271F817830008A2206 /* FlashWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FlashWidget.hxx; sourceTree = ""; }; DC9616281F817830008A2206 /* PointingDeviceWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PointingDeviceWidget.cxx; sourceTree = ""; }; DC9616291F817830008A2206 /* PointingDeviceWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PointingDeviceWidget.hxx; sourceTree = ""; }; DC96162A1F817830008A2206 /* TrakBallWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TrakBallWidget.cxx; sourceTree = ""; }; DC96162B1F817830008A2206 /* TrakBallWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TrakBallWidget.hxx; sourceTree = ""; }; DC98F35411F5B56200AA520F /* MessageBox.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MessageBox.cxx; sourceTree = ""; }; DC98F35511F5B56200AA520F /* MessageBox.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MessageBox.hxx; sourceTree = ""; }; DC9EA8850F729A36000452B5 /* KidVid.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KidVid.cxx; sourceTree = ""; }; DC9EA8860F729A36000452B5 /* KidVid.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = KidVid.hxx; sourceTree = ""; }; DCA00FF50DBABCAD00C3823D /* RiotDebug.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RiotDebug.cxx; sourceTree = ""; }; DCA00FF60DBABCAD00C3823D /* RiotDebug.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RiotDebug.hxx; sourceTree = ""; }; DCA078321F8C1B04008EFEE5 /* LinkedObjectPool.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LinkedObjectPool.hxx; sourceTree = ""; }; DCA078331F8C1B04008EFEE5 /* SDL_lib.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SDL_lib.hxx; sourceTree = ""; }; DCA23AE70D75B22500F77B33 /* CartX07.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CartX07.cxx; sourceTree = ""; }; DCA23AE80D75B22500F77B33 /* CartX07.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CartX07.hxx; sourceTree = ""; }; DCA43BFF10DED5890070CEFD /* Info-Stella.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Stella.plist"; sourceTree = ""; }; DCA82C6D1FEB4E780059340F /* TimeMachine.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeMachine.cxx; sourceTree = ""; }; DCA82C6E1FEB4E780059340F /* TimeMachine.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimeMachine.hxx; sourceTree = ""; }; DCA82C6F1FEB4E780059340F /* TimeMachineDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeMachineDialog.cxx; sourceTree = ""; }; DCA82C701FEB4E780059340F /* TimeMachineDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimeMachineDialog.hxx; sourceTree = ""; }; DCAACAEC188D631500A4D282 /* Cart4KSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart4KSC.cxx; sourceTree = ""; }; DCAACAED188D631500A4D282 /* Cart4KSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart4KSC.hxx; sourceTree = ""; }; DCAACAEE188D631500A4D282 /* CartBF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartBF.cxx; sourceTree = ""; }; DCAACAEF188D631500A4D282 /* CartBF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartBF.hxx; sourceTree = ""; }; DCAACAF0188D631500A4D282 /* CartBFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartBFSC.cxx; sourceTree = ""; }; DCAACAF1188D631500A4D282 /* CartBFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartBFSC.hxx; sourceTree = ""; }; DCAACAF2188D631500A4D282 /* CartDF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDF.cxx; sourceTree = ""; }; DCAACAF3188D631500A4D282 /* CartDF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDF.hxx; sourceTree = ""; }; DCAACAF4188D631500A4D282 /* CartDFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDFSC.cxx; sourceTree = ""; }; DCAACAF5188D631500A4D282 /* CartDFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDFSC.hxx; sourceTree = ""; }; DCAACB04188D636F00A4D282 /* Cart4KSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart4KSCWidget.cxx; sourceTree = ""; }; DCAACB05188D636F00A4D282 /* Cart4KSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart4KSCWidget.hxx; sourceTree = ""; }; DCAACB06188D636F00A4D282 /* CartBFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartBFSCWidget.cxx; sourceTree = ""; }; DCAACB07188D636F00A4D282 /* CartBFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartBFSCWidget.hxx; sourceTree = ""; }; DCAACB08188D636F00A4D282 /* CartBFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartBFWidget.cxx; sourceTree = ""; }; DCAACB09188D636F00A4D282 /* CartBFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartBFWidget.hxx; sourceTree = ""; }; DCAACB0A188D636F00A4D282 /* CartDFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDFSCWidget.cxx; sourceTree = ""; }; DCAACB0B188D636F00A4D282 /* CartDFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDFSCWidget.hxx; sourceTree = ""; }; DCAACB0C188D636F00A4D282 /* CartDFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDFWidget.cxx; sourceTree = ""; }; DCAACB0D188D636F00A4D282 /* CartDFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDFWidget.hxx; sourceTree = ""; }; DCAAE5B21715887B0080BB82 /* Cart2KWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart2KWidget.cxx; sourceTree = ""; }; DCAAE5B31715887B0080BB82 /* Cart2KWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart2KWidget.hxx; sourceTree = ""; }; DCAAE5B41715887B0080BB82 /* Cart3FWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart3FWidget.cxx; sourceTree = ""; }; DCAAE5B51715887B0080BB82 /* Cart3FWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart3FWidget.hxx; sourceTree = ""; }; DCAAE5B61715887B0080BB82 /* Cart4KWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart4KWidget.cxx; sourceTree = ""; }; DCAAE5B71715887B0080BB82 /* Cart4KWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart4KWidget.hxx; sourceTree = ""; }; DCAAE5B81715887B0080BB82 /* Cart0840Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart0840Widget.cxx; sourceTree = ""; }; DCAAE5B91715887B0080BB82 /* Cart0840Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart0840Widget.hxx; sourceTree = ""; }; DCAAE5BA1715887B0080BB82 /* CartCVWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCVWidget.cxx; sourceTree = ""; }; DCAAE5BB1715887B0080BB82 /* CartCVWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCVWidget.hxx; sourceTree = ""; }; DCAAE5BC1715887B0080BB82 /* CartDebugWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDebugWidget.hxx; sourceTree = ""; }; DCAAE5BD1715887B0080BB82 /* CartEFSCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartEFSCWidget.cxx; sourceTree = ""; }; DCAAE5BE1715887B0080BB82 /* CartEFSCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartEFSCWidget.hxx; sourceTree = ""; }; DCAAE5BF1715887B0080BB82 /* CartEFWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartEFWidget.cxx; sourceTree = ""; }; DCAAE5C01715887B0080BB82 /* CartEFWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartEFWidget.hxx; sourceTree = ""; }; DCAAE5C11715887B0080BB82 /* CartF0Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartF0Widget.cxx; sourceTree = ""; }; DCAAE5C21715887B0080BB82 /* CartF0Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartF0Widget.hxx; sourceTree = ""; }; DCAAE5C31715887B0080BB82 /* CartF4SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartF4SCWidget.cxx; sourceTree = ""; }; DCAAE5C41715887B0080BB82 /* CartF4SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartF4SCWidget.hxx; sourceTree = ""; }; DCAAE5C51715887B0080BB82 /* CartF4Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartF4Widget.cxx; sourceTree = ""; }; DCAAE5C61715887B0080BB82 /* CartF4Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartF4Widget.hxx; sourceTree = ""; }; DCAAE5C71715887B0080BB82 /* CartF6SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartF6SCWidget.cxx; sourceTree = ""; }; DCAAE5C81715887B0080BB82 /* CartF6SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartF6SCWidget.hxx; sourceTree = ""; }; DCAAE5C91715887B0080BB82 /* CartF6Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartF6Widget.cxx; sourceTree = ""; }; DCAAE5CA1715887B0080BB82 /* CartF6Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartF6Widget.hxx; sourceTree = ""; }; DCAAE5CB1715887B0080BB82 /* CartF8SCWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartF8SCWidget.cxx; sourceTree = ""; }; DCAAE5CC1715887B0080BB82 /* CartF8SCWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartF8SCWidget.hxx; sourceTree = ""; }; DCAAE5CD1715887B0080BB82 /* CartF8Widget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartF8Widget.cxx; sourceTree = ""; }; DCAAE5CE1715887B0080BB82 /* CartF8Widget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartF8Widget.hxx; sourceTree = ""; }; DCAAE5CF1715887B0080BB82 /* CartFAWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFAWidget.cxx; sourceTree = ""; }; DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFAWidget.hxx; sourceTree = ""; }; DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartUAWidget.cxx; sourceTree = ""; }; DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartUAWidget.hxx; sourceTree = ""; }; DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCVPlusWidget.cxx; sourceTree = ""; }; DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCVPlusWidget.hxx; sourceTree = ""; }; DCACBAD21C54298300703A9B /* CartCVPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartCVPlus.cxx; sourceTree = ""; }; DCACBAD31C54298300703A9B /* CartCVPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartCVPlus.hxx; sourceTree = ""; }; DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDPCPlus.cxx; sourceTree = ""; }; DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDPCPlus.hxx; sourceTree = ""; }; DCB20EC61A0C506C0048F595 /* main.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cxx; sourceTree = ""; }; DCB2ECAB1F0AECA3009738A6 /* BSType.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BSType.hxx; sourceTree = ""; }; DCB2ECAC1F0AECA3009738A6 /* CartDetector.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartDetector.cxx; sourceTree = ""; }; DCB2ECAD1F0AECA3009738A6 /* CartDetector.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartDetector.hxx; sourceTree = ""; }; DCB87E571A104C1E00BF2A3B /* MediaFactory.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MediaFactory.hxx; sourceTree = ""; }; DCBA710010DED62E0077193B /* Stella.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Stella.app; sourceTree = BUILT_PRODUCTS_DIR; }; DCBDDE981D6A5F0E009DF1E9 /* Cart3EPlusWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart3EPlusWidget.cxx; sourceTree = ""; }; DCBDDE991D6A5F0E009DF1E9 /* Cart3EPlusWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart3EPlusWidget.hxx; sourceTree = ""; }; DCBDDE9C1D6A5F2F009DF1E9 /* Cart3EPlus.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Cart3EPlus.cxx; sourceTree = ""; }; DCBDDE9D1D6A5F2F009DF1E9 /* Cart3EPlus.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Cart3EPlus.hxx; sourceTree = ""; }; DCC527C910B9DA19005E1287 /* Device.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Device.hxx; sourceTree = ""; }; DCC527CA10B9DA19005E1287 /* M6502.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = M6502.cxx; sourceTree = ""; }; DCC527CB10B9DA19005E1287 /* M6502.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = M6502.hxx; sourceTree = ""; }; DCC527CD10B9DA19005E1287 /* NullDev.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = NullDev.hxx; sourceTree = ""; }; DCC527CE10B9DA19005E1287 /* System.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = System.cxx; sourceTree = ""; }; DCC527CF10B9DA19005E1287 /* System.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = System.hxx; sourceTree = ""; }; DCC527D810B9DA6A005E1287 /* bspf.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = bspf.hxx; sourceTree = ""; }; DCCA26B11FA64D5E000EE4D8 /* AbstractFrameManager.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AbstractFrameManager.hxx; sourceTree = ""; }; DCCA26B21FA64D5E000EE4D8 /* FrameManager.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FrameManager.hxx; sourceTree = ""; }; DCCF47DB14B60DEE00814FAB /* ControllerWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ControllerWidget.hxx; sourceTree = ""; }; DCCF47DC14B60DEE00814FAB /* JoystickWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JoystickWidget.cxx; sourceTree = ""; }; DCCF47DD14B60DEE00814FAB /* JoystickWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = JoystickWidget.hxx; sourceTree = ""; }; DCCF49B514B7544A00814FAB /* PaddleWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PaddleWidget.cxx; sourceTree = ""; }; DCCF49B614B7544A00814FAB /* PaddleWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PaddleWidget.hxx; sourceTree = ""; }; DCCF4ACE14B7E6C300814FAB /* BoosterWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BoosterWidget.cxx; sourceTree = ""; }; DCCF4ACF14B7E6C300814FAB /* BoosterWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = BoosterWidget.hxx; sourceTree = ""; }; DCCF4AD014B7E6C300814FAB /* NullControlWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = NullControlWidget.hxx; sourceTree = ""; }; DCCF4ADA14B9433100814FAB /* GenesisWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GenesisWidget.cxx; sourceTree = ""; }; DCCF4ADB14B9433100814FAB /* GenesisWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GenesisWidget.hxx; sourceTree = ""; }; DCCF4AFE14BA27EB00814FAB /* DrivingWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrivingWidget.cxx; sourceTree = ""; }; DCCF4AFF14BA27EB00814FAB /* DrivingWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DrivingWidget.hxx; sourceTree = ""; }; DCCF4B0014BA27EB00814FAB /* KeyboardWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyboardWidget.cxx; sourceTree = ""; }; DCCF4B0114BA27EB00814FAB /* KeyboardWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = KeyboardWidget.hxx; sourceTree = ""; }; DCD2839612E39F1200A808DC /* Thumbulator.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Thumbulator.cxx; sourceTree = ""; }; DCD2839712E39F1200A808DC /* Thumbulator.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Thumbulator.hxx; sourceTree = ""; }; DCD3F7C311340AAF00DBA3AE /* Genesis.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Genesis.cxx; sourceTree = ""; }; DCD3F7C411340AAF00DBA3AE /* Genesis.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Genesis.hxx; sourceTree = ""; }; DCD56D360B247D920092F9F8 /* Cart4A50.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Cart4A50.cxx; sourceTree = ""; }; DCD56D370B247D920092F9F8 /* Cart4A50.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Cart4A50.hxx; sourceTree = ""; }; DCD6FC5D11C281ED005DA767 /* png.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = png.c; sourceTree = ""; }; DCD6FC5E11C281ED005DA767 /* png.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = png.h; sourceTree = ""; }; DCD6FC5F11C281ED005DA767 /* pngconf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngconf.h; sourceTree = ""; }; DCD6FC6011C281ED005DA767 /* pngerror.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngerror.c; sourceTree = ""; }; DCD6FC6111C281ED005DA767 /* pngget.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngget.c; sourceTree = ""; }; DCD6FC6211C281ED005DA767 /* pngmem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngmem.c; sourceTree = ""; }; DCD6FC6311C281ED005DA767 /* pngpread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngpread.c; sourceTree = ""; }; DCD6FC6411C281ED005DA767 /* pngpriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pngpriv.h; sourceTree = ""; }; DCD6FC6511C281ED005DA767 /* pngread.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngread.c; sourceTree = ""; }; DCD6FC6611C281ED005DA767 /* pngrio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngrio.c; sourceTree = ""; }; DCD6FC6711C281ED005DA767 /* pngrtran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngrtran.c; sourceTree = ""; }; DCD6FC6811C281ED005DA767 /* pngrutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngrutil.c; sourceTree = ""; }; DCD6FC6911C281ED005DA767 /* pngset.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngset.c; sourceTree = ""; }; DCD6FC6B11C281ED005DA767 /* pngtrans.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngtrans.c; sourceTree = ""; }; DCD6FC6C11C281ED005DA767 /* pngwio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngwio.c; sourceTree = ""; }; DCD6FC6D11C281ED005DA767 /* pngwrite.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngwrite.c; sourceTree = ""; }; DCD6FC6E11C281ED005DA767 /* pngwtran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngwtran.c; sourceTree = ""; }; DCD6FC6F11C281ED005DA767 /* pngwutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pngwutil.c; sourceTree = ""; }; DCD6FC9111C28C6F005DA767 /* PNGLibrary.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PNGLibrary.cxx; sourceTree = ""; }; DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PNGLibrary.hxx; sourceTree = ""; }; DCDA03AE1A2009BA00711920 /* CartWD.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartWD.cxx; sourceTree = ""; }; DCDA03AF1A2009BB00711920 /* CartWD.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartWD.hxx; sourceTree = ""; }; DCDAF4D818CA9AAB00D3865D /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = ""; }; DCDDEAC01F5DBF0400C67366 /* RewindManager.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RewindManager.cxx; sourceTree = ""; }; DCDDEAC11F5DBF0400C67366 /* RewindManager.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RewindManager.hxx; sourceTree = ""; }; DCDDEAC21F5DBF0400C67366 /* StateManager.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StateManager.cxx; sourceTree = ""; }; DCDDEAC31F5DBF0400C67366 /* StateManager.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StateManager.hxx; sourceTree = ""; }; DCDE17F617724E5D00EB1AC6 /* ConfigPathDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConfigPathDialog.cxx; sourceTree = ""; }; DCDE17F717724E5D00EB1AC6 /* ConfigPathDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConfigPathDialog.hxx; sourceTree = ""; }; DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SnapshotDialog.cxx; sourceTree = ""; }; DCDE17F917724E5D00EB1AC6 /* SnapshotDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SnapshotDialog.hxx; sourceTree = ""; }; DCE395DA16CB0B2B008DB1E5 /* FSNodePOSIX.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FSNodePOSIX.hxx; sourceTree = ""; }; DCE395EA16CB0B5F008DB1E5 /* FSNodeFactory.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FSNodeFactory.hxx; sourceTree = ""; }; DCE395EB16CB0B5F008DB1E5 /* FSNodeZIP.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FSNodeZIP.cxx; sourceTree = ""; }; DCE395EC16CB0B5F008DB1E5 /* FSNodeZIP.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FSNodeZIP.hxx; sourceTree = ""; }; DCE395ED16CB0B5F008DB1E5 /* ZipHandler.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ZipHandler.cxx; sourceTree = ""; }; DCE395EE16CB0B5F008DB1E5 /* ZipHandler.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ZipHandler.hxx; sourceTree = ""; }; DCE3BBF50C95CEDC00A671DF /* RomInfoWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = RomInfoWidget.cxx; sourceTree = ""; }; DCE3BBF60C95CEDC00A671DF /* RomInfoWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = RomInfoWidget.hxx; sourceTree = ""; }; DCE5CDE11BA10024005CD08A /* RiotRamWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RiotRamWidget.cxx; sourceTree = ""; }; DCE5CDE21BA10024005CD08A /* RiotRamWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RiotRamWidget.hxx; sourceTree = ""; }; DCE8B1861E7E03B300189864 /* FrameLayout.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FrameLayout.hxx; sourceTree = ""; }; DCE91589201543B900960CC0 /* TimeLineWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeLineWidget.cxx; sourceTree = ""; }; DCE9158A201543B900960CC0 /* TimeLineWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimeLineWidget.hxx; sourceTree = ""; }; DCEC58561E945125002F0246 /* DelayQueueWidget.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DelayQueueWidget.cxx; sourceTree = ""; }; DCEC58571E945125002F0246 /* DelayQueueWidget.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DelayQueueWidget.hxx; sourceTree = ""; }; DCEC585B1E945175002F0246 /* DelayQueueIterator.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DelayQueueIterator.hxx; sourceTree = ""; }; DCEECE540B5E5E540021D754 /* Cart0840.cxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Cart0840.cxx; sourceTree = ""; }; DCEECE550B5E5E540021D754 /* Cart0840.hxx */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = Cart0840.hxx; sourceTree = ""; }; DCF3A6CD1DFC75E3008A8AF3 /* Background.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Background.cxx; sourceTree = ""; }; DCF3A6CE1DFC75E3008A8AF3 /* Background.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Background.hxx; sourceTree = ""; }; DCF3A6CF1DFC75E3008A8AF3 /* Ball.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Ball.cxx; sourceTree = ""; }; DCF3A6D01DFC75E3008A8AF3 /* Ball.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Ball.hxx; sourceTree = ""; }; DCF3A6D21DFC75E3008A8AF3 /* DelayQueue.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DelayQueue.hxx; sourceTree = ""; }; DCF3A6D41DFC75E3008A8AF3 /* DelayQueueMember.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DelayQueueMember.hxx; sourceTree = ""; }; DCF3A6D51DFC75E3008A8AF3 /* DrawCounterDecodes.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawCounterDecodes.cxx; sourceTree = ""; }; DCF3A6D61DFC75E3008A8AF3 /* DrawCounterDecodes.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DrawCounterDecodes.hxx; sourceTree = ""; }; DCF3A6D91DFC75E3008A8AF3 /* LatchedInput.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LatchedInput.cxx; sourceTree = ""; }; DCF3A6DA1DFC75E3008A8AF3 /* LatchedInput.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LatchedInput.hxx; sourceTree = ""; }; DCF3A6DB1DFC75E3008A8AF3 /* Missile.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Missile.cxx; sourceTree = ""; }; DCF3A6DC1DFC75E3008A8AF3 /* Missile.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Missile.hxx; sourceTree = ""; }; DCF3A6DE1DFC75E3008A8AF3 /* PaddleReader.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PaddleReader.cxx; sourceTree = ""; }; DCF3A6DF1DFC75E3008A8AF3 /* PaddleReader.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PaddleReader.hxx; sourceTree = ""; }; DCF3A6E01DFC75E3008A8AF3 /* Player.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Player.cxx; sourceTree = ""; }; DCF3A6E11DFC75E3008A8AF3 /* Player.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Player.hxx; sourceTree = ""; }; DCF3A6E21DFC75E3008A8AF3 /* Playfield.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Playfield.cxx; sourceTree = ""; }; DCF3A6E31DFC75E3008A8AF3 /* Playfield.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Playfield.hxx; sourceTree = ""; }; DCF3A6E41DFC75E3008A8AF3 /* TIA.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIA.cxx; sourceTree = ""; }; DCF3A6E51DFC75E3008A8AF3 /* TIA.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIA.hxx; sourceTree = ""; }; DCF3A7011DFC76BC008A8AF3 /* TIATypes.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIATypes.hxx; sourceTree = ""; }; DCF467B40F93993B00B25D7A /* SoundNull.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SoundNull.hxx; sourceTree = ""; }; DCF467BC0F9399F500B25D7A /* Version.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Version.hxx; sourceTree = ""; }; DCF467BE0F939A1400B25D7A /* CartEF.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartEF.cxx; sourceTree = ""; }; DCF467BF0F939A1400B25D7A /* CartEF.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartEF.hxx; sourceTree = ""; }; DCF467C00F939A1400B25D7A /* CartEFSC.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartEFSC.cxx; sourceTree = ""; }; DCF467C10F939A1400B25D7A /* CartEFSC.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartEFSC.hxx; sourceTree = ""; }; DCF490791A0ECE5B00A67AA9 /* Vec.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Vec.hxx; sourceTree = ""; }; DCF7B0D910A762FC007A2870 /* CartF0.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartF0.cxx; sourceTree = ""; }; DCF7B0DA10A762FC007A2870 /* CartF0.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartF0.hxx; sourceTree = ""; }; DCF7B0DB10A762FC007A2870 /* CartFA.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CartFA.cxx; sourceTree = ""; }; DCF7B0DC10A762FC007A2870 /* CartFA.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CartFA.hxx; sourceTree = ""; }; DCFB9FAB1ECA2609004FD69B /* DelayQueueIteratorImpl.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DelayQueueIteratorImpl.hxx; sourceTree = ""; }; DCFF14CB18B0260300A20364 /* EventHandlerSDL2.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventHandlerSDL2.cxx; sourceTree = ""; }; DCFF14CC18B0260300A20364 /* EventHandlerSDL2.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = EventHandlerSDL2.hxx; sourceTree = ""; }; DCFFE59B12100E1400DFA000 /* ComboDialog.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ComboDialog.cxx; sourceTree = ""; }; DCFFE59C12100E1400DFA000 /* ComboDialog.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ComboDialog.hxx; sourceTree = ""; }; E0306E061F93E915003DDD52 /* YStartDetector.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = YStartDetector.cxx; sourceTree = ""; }; E0306E071F93E915003DDD52 /* FrameLayoutDetector.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FrameLayoutDetector.hxx; sourceTree = ""; }; E0306E081F93E915003DDD52 /* YStartDetector.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = YStartDetector.hxx; sourceTree = ""; }; E0306E091F93E915003DDD52 /* JitterEmulation.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JitterEmulation.cxx; sourceTree = ""; }; E0306E0A1F93E916003DDD52 /* FrameLayoutDetector.cxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameLayoutDetector.cxx; sourceTree = ""; }; E0306E0B1F93E916003DDD52 /* JitterEmulation.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = JitterEmulation.hxx; sourceTree = ""; }; E0DFDD781F81A358000F3505 /* AbstractFrameManager.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractFrameManager.cxx; sourceTree = ""; }; E0DFDD7B1F81A358000F3505 /* FrameManager.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FrameManager.cxx; sourceTree = ""; }; F5A47A9D01A0482F01D3D55B /* SDLMain.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SDLMain.h; sourceTree = SOURCE_ROOT; }; F5A47A9E01A0483001D3D55B /* SDLMain.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = SDLMain.m; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 2D91750E09BA90380026E9FF /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( DCDAF4D918CA9AAB00D3865D /* SDL2.framework in Frameworks */, 2D91750F09BA90380026E9FF /* Cocoa.framework in Frameworks */, 2D91751009BA90380026E9FF /* OpenGL.framework in Frameworks */, 2D91751209BA90380026E9FF /* ApplicationServices.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( 2D1A6CD4085135F9007CDBA8 /* AboutBox.h */, 2D1A6CD5085135F9007CDBA8 /* AboutBox.m */, 2DDBEBE3084582C400812C11 /* Preferences.h */, 2DDBEBE4084582C400812C11 /* Preferences.m */, F5A47A9D01A0482F01D3D55B /* SDLMain.h */, F5A47A9E01A0483001D3D55B /* SDLMain.m */, ); name = Classes; sourceTree = ""; }; 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 2D17D98E08BC398400E47F69 /* ApplicationServices.framework */, 2DEB3D4C0629BD24007EBBD3 /* OpenGL.framework */, 29B97325FDCFA39411CA2CEA /* Foundation.framework */, 29B97324FDCFA39411CA2CEA /* AppKit.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FACFE9D520D11CA2CBB /* Products */ = { isa = PBXGroup; children = ( DCBA710010DED62E0077193B /* Stella.app */, ); name = Products; sourceTree = ""; }; 29B97314FDCFA39411CA2CEA /* Stella */ = { isa = PBXGroup; children = ( 080E96DDFE201D6D7F000001 /* Classes */, 29B97315FDCFA39411CA2CEA /* Other Sources */, 29B97317FDCFA39411CA2CEA /* Resources */, 29B97323FDCFA39411CA2CEA /* Frameworks */, 19C28FACFE9D520D11CA2CBB /* Products */, ); indentWidth = 2; name = Stella; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; 29B97315FDCFA39411CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( DCCC0C9109C3541E0088BFF1 /* cheat */, 2D6050C5089876F300C6DE89 /* common */, 2D605130089879BA00C6DE89 /* debugger */, 2D6050CC0898776500C6DE89 /* emucore */, 2D6050FA0898786C00C6DE89 /* gui */, DCD6FC5A11C281A1005DA767 /* libpng */, 2D6050C60898771C00C6DE89 /* macosx */, 2D6050C90898774B00C6DE89 /* unix */, 2D60513708987A5400C6DE89 /* yacc */, DC3EE83B1E2C0E4400905161 /* zlib */, ); name = "Other Sources"; path = ..; sourceTree = ""; }; 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( DCA43BFF10DED5890070CEFD /* Info-Stella.plist */, 55FE2A3C1EE487CA00078ADE /* InfoPlist.strings */, 2D113E090672BF2100317017 /* docs */, 2D16A8E106324136005DF364 /* Stella.icns */, 2DEFB40B09C3386F00754289 /* Cart.icns */, 2D7B4F6C063B513200579B93 /* Credits.html */, B2F367C504C7ADC700A80002 /* SDLMain.nib */, 2D1A6CD808513610007CDBA8 /* AboutBox.nib */, ); name = Resources; sourceTree = ""; }; 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( DCDAF4D818CA9AAB00D3865D /* SDL2.framework */, 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; 2D20F9E308C603C500A73076 /* gui */ = { isa = PBXGroup; children = ( DC9616221F817830008A2206 /* AmigaMouseWidget.cxx */, DC9616231F817830008A2206 /* AmigaMouseWidget.hxx */, DC9616241F817830008A2206 /* AtariMouseWidget.cxx */, DC9616251F817830008A2206 /* AtariMouseWidget.hxx */, DC62E6431960E87B007AEF05 /* AtariVoxWidget.cxx */, DC62E6441960E87B007AEF05 /* AtariVoxWidget.hxx */, 2D23318F0900B5EF00613B1F /* AudioWidget.cxx */, 2D2331900900B5EF00613B1F /* AudioWidget.hxx */, DCCF4ACE14B7E6C300814FAB /* BoosterWidget.cxx */, DCCF4ACF14B7E6C300814FAB /* BoosterWidget.hxx */, DCAAE5B21715887B0080BB82 /* Cart2KWidget.cxx */, DCAAE5B31715887B0080BB82 /* Cart2KWidget.hxx */, DCBDDE981D6A5F0E009DF1E9 /* Cart3EPlusWidget.cxx */, DCBDDE991D6A5F0E009DF1E9 /* Cart3EPlusWidget.hxx */, DC676A251729A0B000E4E73D /* Cart3EWidget.cxx */, DC676A261729A0B000E4E73D /* Cart3EWidget.hxx */, DCAAE5B41715887B0080BB82 /* Cart3FWidget.cxx */, DCAAE5B51715887B0080BB82 /* Cart3FWidget.hxx */, DC676A271729A0B000E4E73D /* Cart4A50Widget.cxx */, DC676A281729A0B000E4E73D /* Cart4A50Widget.hxx */, DCAACB04188D636F00A4D282 /* Cart4KSCWidget.cxx */, DCAACB05188D636F00A4D282 /* Cart4KSCWidget.hxx */, DCAAE5B61715887B0080BB82 /* Cart4KWidget.cxx */, DCAAE5B71715887B0080BB82 /* Cart4KWidget.hxx */, DCAAE5B81715887B0080BB82 /* Cart0840Widget.cxx */, DCAAE5B91715887B0080BB82 /* Cart0840Widget.hxx */, DC676A291729A0B000E4E73D /* CartARWidget.cxx */, DC676A2A1729A0B000E4E73D /* CartARWidget.hxx */, DCAACB06188D636F00A4D282 /* CartBFSCWidget.cxx */, DCAACB07188D636F00A4D282 /* CartBFSCWidget.hxx */, DCAACB08188D636F00A4D282 /* CartBFWidget.cxx */, DCAACB09188D636F00A4D282 /* CartBFWidget.hxx */, CFE3F6071E84A9A200A8204E /* CartBUSWidget.cxx */, CFE3F6081E84A9A200A8204E /* CartBUSWidget.hxx */, CFE3F6091E84A9A200A8204E /* CartCDFWidget.cxx */, CFE3F60A1E84A9A200A8204E /* CartCDFWidget.hxx */, DC676A2B1729A0B000E4E73D /* CartCMWidget.cxx */, DC676A2C1729A0B000E4E73D /* CartCMWidget.hxx */, DC676A2D1729A0B000E4E73D /* CartCTYWidget.cxx */, DC676A2E1729A0B000E4E73D /* CartCTYWidget.hxx */, DCACBACE1C54296300703A9B /* CartCVPlusWidget.cxx */, DCACBACF1C54296300703A9B /* CartCVPlusWidget.hxx */, DCAAE5BA1715887B0080BB82 /* CartCVWidget.cxx */, DCAAE5BB1715887B0080BB82 /* CartCVWidget.hxx */, DC74E5C4198AF12700F37E36 /* CartDASHWidget.cxx */, DC74E5C5198AF12700F37E36 /* CartDASHWidget.hxx */, DC5ACB5D1FBFCEB800A213FD /* CartDebugWidget.cxx */, DCAAE5BC1715887B0080BB82 /* CartDebugWidget.hxx */, DCAACB0A188D636F00A4D282 /* CartDFSCWidget.cxx */, DCAACB0B188D636F00A4D282 /* CartDFSCWidget.hxx */, DCAACB0C188D636F00A4D282 /* CartDFWidget.cxx */, DCAACB0D188D636F00A4D282 /* CartDFWidget.hxx */, DC676A2F1729A0B000E4E73D /* CartDPCPlusWidget.cxx */, DC676A301729A0B000E4E73D /* CartDPCPlusWidget.hxx */, DC676A311729A0B000E4E73D /* CartDPCWidget.cxx */, DC676A321729A0B000E4E73D /* CartDPCWidget.hxx */, DC676A331729A0B000E4E73D /* CartE0Widget.cxx */, DC676A341729A0B000E4E73D /* CartE0Widget.hxx */, DC676A351729A0B000E4E73D /* CartE7Widget.cxx */, DC676A361729A0B000E4E73D /* CartE7Widget.hxx */, DC71EAA11FDA070D008827CB /* CartE78KWidget.cxx */, DC71EAA21FDA070D008827CB /* CartE78KWidget.hxx */, DCAAE5BD1715887B0080BB82 /* CartEFSCWidget.cxx */, DCAAE5BE1715887B0080BB82 /* CartEFSCWidget.hxx */, DCAAE5BF1715887B0080BB82 /* CartEFWidget.cxx */, DCAAE5C01715887B0080BB82 /* CartEFWidget.hxx */, DCAAE5C11715887B0080BB82 /* CartF0Widget.cxx */, DCAAE5C21715887B0080BB82 /* CartF0Widget.hxx */, DCAAE5C31715887B0080BB82 /* CartF4SCWidget.cxx */, DCAAE5C41715887B0080BB82 /* CartF4SCWidget.hxx */, DCAAE5C51715887B0080BB82 /* CartF4Widget.cxx */, DCAAE5C61715887B0080BB82 /* CartF4Widget.hxx */, DCAAE5C71715887B0080BB82 /* CartF6SCWidget.cxx */, DCAAE5C81715887B0080BB82 /* CartF6SCWidget.hxx */, DCAAE5C91715887B0080BB82 /* CartF6Widget.cxx */, DCAAE5CA1715887B0080BB82 /* CartF6Widget.hxx */, DCAAE5CB1715887B0080BB82 /* CartF8SCWidget.cxx */, DCAAE5CC1715887B0080BB82 /* CartF8SCWidget.hxx */, DCAAE5CD1715887B0080BB82 /* CartF8Widget.cxx */, DCAAE5CE1715887B0080BB82 /* CartF8Widget.hxx */, DC676A371729A0B000E4E73D /* CartFA2Widget.cxx */, DC676A381729A0B000E4E73D /* CartFA2Widget.hxx */, DCAAE5CF1715887B0080BB82 /* CartFAWidget.cxx */, DCAAE5D01715887B0080BB82 /* CartFAWidget.hxx */, DC676A391729A0B000E4E73D /* CartFEWidget.cxx */, DC676A3A1729A0B000E4E73D /* CartFEWidget.hxx */, DC6A18F619B3E65500DEB242 /* CartMDMWidget.cxx */, DC6A18F719B3E65500DEB242 /* CartMDMWidget.hxx */, DC71EAA31FDA070D008827CB /* CartMNetworkWidget.cxx */, DC71EAA41FDA070D008827CB /* CartMNetworkWidget.hxx */, DC2AADB2194F390F0026C7A4 /* CartRamWidget.cxx */, DC2AADB3194F390F0026C7A4 /* CartRamWidget.hxx */, DC676A3D1729A0B000E4E73D /* CartSBWidget.cxx */, DC676A3E1729A0B000E4E73D /* CartSBWidget.hxx */, DCAAE5D11715887B0080BB82 /* CartUAWidget.cxx */, DCAAE5D21715887B0080BB82 /* CartUAWidget.hxx */, DC6D39851A3CE65000171E71 /* CartWDWidget.cxx */, DC6D39861A3CE65000171E71 /* CartWDWidget.hxx */, DC676A3F1729A0B000E4E73D /* CartX07Widget.cxx */, DC676A401729A0B000E4E73D /* CartX07Widget.hxx */, DCCF47DB14B60DEE00814FAB /* ControllerWidget.hxx */, 2D20F9E608C603EC00A73076 /* CpuWidget.cxx */, 2D20F9E708C603EC00A73076 /* CpuWidget.hxx */, 2D20F9E808C603EC00A73076 /* DataGridOpsWidget.cxx */, 2D20F9E908C603EC00A73076 /* DataGridOpsWidget.hxx */, 2D20F9EA08C603EC00A73076 /* DataGridWidget.cxx */, 2D20F9EB08C603EC00A73076 /* DataGridWidget.hxx */, 2D20F9EC08C603EC00A73076 /* DebuggerDialog.cxx */, 2D20F9ED08C603EC00A73076 /* DebuggerDialog.hxx */, DCEC58561E945125002F0246 /* DelayQueueWidget.cxx */, DCEC58571E945125002F0246 /* DelayQueueWidget.hxx */, DCCF4AFE14BA27EB00814FAB /* DrivingWidget.cxx */, DCCF4AFF14BA27EB00814FAB /* DrivingWidget.hxx */, DC9616261F817830008A2206 /* FlashWidget.cxx */, DC9616271F817830008A2206 /* FlashWidget.hxx */, DCCF4ADA14B9433100814FAB /* GenesisWidget.cxx */, DCCF4ADB14B9433100814FAB /* GenesisWidget.hxx */, DCCF47DC14B60DEE00814FAB /* JoystickWidget.cxx */, DCCF47DD14B60DEE00814FAB /* JoystickWidget.hxx */, DCCF4B0014BA27EB00814FAB /* KeyboardWidget.cxx */, DCCF4B0114BA27EB00814FAB /* KeyboardWidget.hxx */, DCCF4AD014B7E6C300814FAB /* NullControlWidget.hxx */, DCCF49B514B7544A00814FAB /* PaddleWidget.cxx */, DCCF49B614B7544A00814FAB /* PaddleWidget.hxx */, DC9616281F817830008A2206 /* PointingDeviceWidget.cxx */, DC9616291F817830008A2206 /* PointingDeviceWidget.hxx */, 2D20F9EE08C603EC00A73076 /* PromptWidget.cxx */, 2D20F9EF08C603EC00A73076 /* PromptWidget.hxx */, 2D20F9F008C603EC00A73076 /* RamWidget.cxx */, 2D20F9F108C603EC00A73076 /* RamWidget.hxx */, DCE5CDE11BA10024005CD08A /* RiotRamWidget.cxx */, DCE5CDE21BA10024005CD08A /* RiotRamWidget.hxx */, DC4AC6ED0DC8DACB00CD3AD2 /* RiotWidget.cxx */, DC4AC6EE0DC8DACB00CD3AD2 /* RiotWidget.hxx */, DC13B53D176FF2F500B8B4BB /* RomListSettings.cxx */, DC13B53E176FF2F500B8B4BB /* RomListSettings.hxx */, 2D20F9F208C603EC00A73076 /* RomListWidget.cxx */, 2D20F9F308C603EC00A73076 /* RomListWidget.hxx */, 2D20F9F408C603EC00A73076 /* RomWidget.cxx */, 2D20F9F508C603EC00A73076 /* RomWidget.hxx */, DC62E6451960E87B007AEF05 /* SaveKeyWidget.cxx */, DC62E6461960E87B007AEF05 /* SaveKeyWidget.hxx */, 2D20F9F608C603EC00A73076 /* TiaInfoWidget.cxx */, 2D20F9F708C603EC00A73076 /* TiaInfoWidget.hxx */, 2D20F9F808C603EC00A73076 /* TiaOutputWidget.cxx */, 2D20F9F908C603EC00A73076 /* TiaOutputWidget.hxx */, 2D20F9FA08C603EC00A73076 /* TiaWidget.cxx */, 2D20F9FB08C603EC00A73076 /* TiaWidget.hxx */, 2D20F9FC08C603EC00A73076 /* ToggleBitWidget.cxx */, 2D20F9FD08C603EC00A73076 /* ToggleBitWidget.hxx */, 2D20F9FE08C603EC00A73076 /* TogglePixelWidget.cxx */, 2D20F9FF08C603EC00A73076 /* TogglePixelWidget.hxx */, 2D20FA0008C603EC00A73076 /* ToggleWidget.cxx */, 2D20FA0108C603EC00A73076 /* ToggleWidget.hxx */, DC96162A1F817830008A2206 /* TrakBallWidget.cxx */, DC96162B1F817830008A2206 /* TrakBallWidget.hxx */, ); path = gui; sourceTree = ""; }; 2D6050C5089876F300C6DE89 /* common */ = { isa = PBXGroup; children = ( DC79F81017A88D9E00288B91 /* Base.cxx */, DC79F81117A88D9E00288B91 /* Base.hxx */, DCC527D810B9DA6A005E1287 /* bspf.hxx */, DCFF14CB18B0260300A20364 /* EventHandlerSDL2.cxx */, DCFF14CC18B0260300A20364 /* EventHandlerSDL2.hxx */, DC73BD831915E5B1003FAFAD /* FBSurfaceSDL2.cxx */, DC73BD841915E5B1003FAFAD /* FBSurfaceSDL2.hxx */, DC368F5018A2FB710084199C /* FrameBufferSDL2.cxx */, DC368F5118A2FB710084199C /* FrameBufferSDL2.hxx */, DCE395EA16CB0B5F008DB1E5 /* FSNodeFactory.hxx */, DCE395EB16CB0B5F008DB1E5 /* FSNodeZIP.cxx */, DCE395EC16CB0B5F008DB1E5 /* FSNodeZIP.hxx */, DCA078321F8C1B04008EFEE5 /* LinkedObjectPool.hxx */, DCB20EC61A0C506C0048F595 /* main.cxx */, DCB87E571A104C1E00BF2A3B /* MediaFactory.hxx */, DC56FCDC14CCCC4900A31CC3 /* MouseControl.cxx */, DC56FCDD14CCCC4900A31CC3 /* MouseControl.hxx */, DCD6FC9111C28C6F005DA767 /* PNGLibrary.cxx */, DCD6FC9211C28C6F005DA767 /* PNGLibrary.hxx */, DCDDEAC01F5DBF0400C67366 /* RewindManager.cxx */, DCDDEAC11F5DBF0400C67366 /* RewindManager.hxx */, DCA078331F8C1B04008EFEE5 /* SDL_lib.hxx */, DC2C5EDA1F8F2403007D2A09 /* smartmod.hxx */, DCF467B40F93993B00B25D7A /* SoundNull.hxx */, DC368F5218A2FB710084199C /* SoundSDL2.cxx */, DC368F5318A2FB710084199C /* SoundSDL2.hxx */, DC5D1AA6102C6FC900E59AC1 /* Stack.hxx */, DCDDEAC21F5DBF0400C67366 /* StateManager.cxx */, DCDDEAC31F5DBF0400C67366 /* StateManager.hxx */, DC5C768E14C26F7C0031EBC7 /* StellaKeys.hxx */, DC74D6A0138D4D7E00F05C5C /* StringParser.hxx */, DCC467EA14FBEC9600E15508 /* tv_filters */, DC7A24D4173B1CF600B20FE9 /* Variant.hxx */, DCF490791A0ECE5B00A67AA9 /* Vec.hxx */, DCF467BC0F9399F500B25D7A /* Version.hxx */, DCE395ED16CB0B5F008DB1E5 /* ZipHandler.cxx */, DCE395EE16CB0B5F008DB1E5 /* ZipHandler.hxx */, ); path = common; sourceTree = ""; }; 2D6050C60898771C00C6DE89 /* macosx */ = { isa = PBXGroup; children = ( 2DDBEA0E0845709700812C11 /* OSystemMACOSX.cxx */, 2DDBEA0F0845709700812C11 /* OSystemMACOSX.hxx */, DC1FC1880DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx */, DC1FC1890DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx */, 2D944866062911CD00DD9879 /* SettingsMACOSX.cxx */, 2D94486C0629124700DD9879 /* SettingsMACOSX.hxx */, ); path = macosx; sourceTree = ""; }; 2D6050C90898774B00C6DE89 /* unix */ = { isa = PBXGroup; children = ( 2DDBEA0C0845708800812C11 /* FSNodePOSIX.cxx */, DCE395DA16CB0B2B008DB1E5 /* FSNodePOSIX.hxx */, ); path = unix; sourceTree = ""; }; 2D6050CC0898776500C6DE89 /* emucore */ = { isa = PBXGroup; children = ( DC1B2EBE1E50036100F62837 /* AmigaMouse.hxx */, DC1B2EC01E50036100F62837 /* AtariMouse.hxx */, DC487FB40DA5350900E12499 /* AtariVox.cxx */, DC487FB50DA5350900E12499 /* AtariVox.hxx */, 2DE2DF100627AE07006BEC99 /* Booster.cxx */, 2DE2DF110627AE07006BEC99 /* Booster.hxx */, DCB2ECAB1F0AECA3009738A6 /* BSType.hxx */, 2DE2DF120627AE07006BEC99 /* Cart.cxx */, 2DE2DF130627AE07006BEC99 /* Cart.hxx */, 2DE2DF140627AE07006BEC99 /* Cart2K.cxx */, 2DE2DF150627AE07006BEC99 /* Cart2K.hxx */, 2D9555D90880E78000466554 /* Cart3E.cxx */, 2D9555DA0880E78000466554 /* Cart3E.hxx */, DCBDDE9C1D6A5F2F009DF1E9 /* Cart3EPlus.cxx */, DCBDDE9D1D6A5F2F009DF1E9 /* Cart3EPlus.hxx */, 2DE2DF160627AE07006BEC99 /* Cart3F.cxx */, 2DE2DF170627AE07006BEC99 /* Cart3F.hxx */, DCD56D360B247D920092F9F8 /* Cart4A50.cxx */, DCD56D370B247D920092F9F8 /* Cart4A50.hxx */, 2DE2DF180627AE07006BEC99 /* Cart4K.cxx */, 2DE2DF190627AE07006BEC99 /* Cart4K.hxx */, DCAACAEC188D631500A4D282 /* Cart4KSC.cxx */, DCAACAED188D631500A4D282 /* Cart4KSC.hxx */, DCEECE540B5E5E540021D754 /* Cart0840.cxx */, DCEECE550B5E5E540021D754 /* Cart0840.hxx */, 2DE2DF1A0627AE07006BEC99 /* CartAR.cxx */, 2DE2DF1B0627AE07006BEC99 /* CartAR.hxx */, DCAACAEE188D631500A4D282 /* CartBF.cxx */, DCAACAEF188D631500A4D282 /* CartBF.hxx */, DCAACAF0188D631500A4D282 /* CartBFSC.cxx */, DCAACAF1188D631500A4D282 /* CartBFSC.hxx */, CFE3F60F1E84A9CE00A8204E /* CartBUS.cxx */, CFE3F6101E84A9CE00A8204E /* CartBUS.hxx */, CFE3F6111E84A9CE00A8204E /* CartCDF.cxx */, CFE3F6121E84A9CE00A8204E /* CartCDF.hxx */, DC8C1BA714B25DE7006440EE /* CartCM.cxx */, DC8C1BA814B25DE7006440EE /* CartCM.hxx */, DC6727081556F4860023653B /* CartCTY.cxx */, DC6727091556F4860023653B /* CartCTY.hxx */, DC67270A1556F4860023653B /* CartCTYTunes.hxx */, 2DE2DF1C0627AE07006BEC99 /* CartCV.cxx */, 2DE2DF1D0627AE07006BEC99 /* CartCV.hxx */, DCACBAD21C54298300703A9B /* CartCVPlus.cxx */, DCACBAD31C54298300703A9B /* CartCVPlus.hxx */, DC2AADAA194F389C0026C7A4 /* CartDASH.cxx */, DC2AADAB194F389C0026C7A4 /* CartDASH.hxx */, DCB2ECAC1F0AECA3009738A6 /* CartDetector.cxx */, DCB2ECAD1F0AECA3009738A6 /* CartDetector.hxx */, DCAACAF2188D631500A4D282 /* CartDF.cxx */, DCAACAF3188D631500A4D282 /* CartDF.hxx */, DCAACAF4188D631500A4D282 /* CartDFSC.cxx */, DCAACAF5188D631500A4D282 /* CartDFSC.hxx */, 2DE2DF1E0627AE07006BEC99 /* CartDPC.cxx */, 2DE2DF1F0627AE07006BEC99 /* CartDPC.hxx */, DCAD60A61152F8BD00BC4184 /* CartDPCPlus.cxx */, DCAD60A71152F8BD00BC4184 /* CartDPCPlus.hxx */, 2DE2DF200627AE07006BEC99 /* CartE0.cxx */, 2DE2DF210627AE07006BEC99 /* CartE0.hxx */, 2DE2DF220627AE07006BEC99 /* CartE7.cxx */, 2DE2DF230627AE07006BEC99 /* CartE7.hxx */, DC71EA991FDA06D2008827CB /* CartE78K.cxx */, DC71EA9A1FDA06D2008827CB /* CartE78K.hxx */, DCF467BE0F939A1400B25D7A /* CartEF.cxx */, DCF467BF0F939A1400B25D7A /* CartEF.hxx */, DCF467C00F939A1400B25D7A /* CartEFSC.cxx */, DCF467C10F939A1400B25D7A /* CartEFSC.hxx */, DCF7B0D910A762FC007A2870 /* CartF0.cxx */, DCF7B0DA10A762FC007A2870 /* CartF0.hxx */, 2DE2DF240627AE07006BEC99 /* CartF4.cxx */, 2DE2DF250627AE07006BEC99 /* CartF4.hxx */, 2DE2DF260627AE07006BEC99 /* CartF4SC.cxx */, 2DE2DF270627AE07006BEC99 /* CartF4SC.hxx */, 2DE2DF280627AE07006BEC99 /* CartF6.cxx */, 2DE2DF290627AE07006BEC99 /* CartF6.hxx */, 2DE2DF2A0627AE07006BEC99 /* CartF6SC.cxx */, 2DE2DF2B0627AE07006BEC99 /* CartF6SC.hxx */, 2DE2DF2C0627AE07006BEC99 /* CartF8.cxx */, 2DE2DF2D0627AE07006BEC99 /* CartF8.hxx */, 2DE2DF2E0627AE07006BEC99 /* CartF8SC.cxx */, 2DE2DF2F0627AE07006BEC99 /* CartF8SC.hxx */, DCF7B0DB10A762FC007A2870 /* CartFA.cxx */, DCF7B0DC10A762FC007A2870 /* CartFA.hxx */, DC36D2C614CAFAB0007DC821 /* CartFA2.cxx */, DC36D2C714CAFAB0007DC821 /* CartFA2.hxx */, 2DE2DF320627AE07006BEC99 /* CartFE.cxx */, 2DE2DF330627AE07006BEC99 /* CartFE.hxx */, DC6A18FA19B3E67A00DEB242 /* CartMDM.cxx */, DC6A18FB19B3E67A00DEB242 /* CartMDM.hxx */, DC71EA9B1FDA06D2008827CB /* CartMNetwork.cxx */, DC71EA9C1FDA06D2008827CB /* CartMNetwork.hxx */, DC0984830D3985160073C852 /* CartSB.cxx */, DC0984840D3985160073C852 /* CartSB.hxx */, 2DDBEB7008457B7D00812C11 /* CartUA.cxx */, 2DDBEB7108457B7D00812C11 /* CartUA.hxx */, DCDA03AE1A2009BA00711920 /* CartWD.cxx */, DCDA03AF1A2009BB00711920 /* CartWD.hxx */, DCA23AE70D75B22500F77B33 /* CartX07.cxx */, DCA23AE80D75B22500F77B33 /* CartX07.hxx */, DC8C1BA914B25DE7006440EE /* CompuMate.cxx */, DC8C1BAA14B25DE7006440EE /* CompuMate.hxx */, 2DE2DF380627AE07006BEC99 /* Console.cxx */, 2DE2DF390627AE07006BEC99 /* Console.hxx */, 2DE2DF3A0627AE07006BEC99 /* Control.cxx */, 2DE2DF3B0627AE07006BEC99 /* Control.hxx */, DC932D3F0F278A5200FEFEFC /* DefProps.hxx */, DCC527C910B9DA19005E1287 /* Device.hxx */, 2DE2DF3E0627AE07006BEC99 /* Driving.cxx */, 2DE2DF3F0627AE07006BEC99 /* Driving.hxx */, 2DE2DF410627AE07006BEC99 /* Event.hxx */, 2D733D6E062895B2006265D9 /* EventHandler.cxx */, 2D733D6F062895B2006265D9 /* EventHandler.hxx */, DC5AAC261FCB24AB00C420A6 /* EventHandlerConstants.hxx */, DC5E473A19EC9A14000E45DF /* EventJoyHandler.cxx */, DC73BD871915E5E3003FAFAD /* FBSurface.cxx */, DC73BD881915E5E3003FAFAD /* FBSurface.hxx */, 2D733D70062895B2006265D9 /* FrameBuffer.cxx */, 2D733D71062895B2006265D9 /* FrameBuffer.hxx */, DC5AAC271FCB24AB00C420A6 /* FrameBufferConstants.hxx */, 2DDBEB7208457B7D00812C11 /* FSNode.cxx */, 2DDBEB7308457B7D00812C11 /* FSNode.hxx */, DCD3F7C311340AAF00DBA3AE /* Genesis.cxx */, DCD3F7C411340AAF00DBA3AE /* Genesis.hxx */, 2DE2DF420627AE07006BEC99 /* Joystick.cxx */, 2DE2DF430627AE07006BEC99 /* Joystick.hxx */, 2DE2DF440627AE07006BEC99 /* Keyboard.cxx */, 2DE2DF450627AE07006BEC99 /* Keyboard.hxx */, DC9EA8850F729A36000452B5 /* KidVid.cxx */, DC9EA8860F729A36000452B5 /* KidVid.hxx */, DCC527CA10B9DA19005E1287 /* M6502.cxx */, DCC527CB10B9DA19005E1287 /* M6502.hxx */, 2DE2DF7C0627AE33006BEC99 /* M6532.cxx */, 2DE2DF7D0627AE33006BEC99 /* M6532.hxx */, 2DE2DF7E0627AE33006BEC99 /* MD5.cxx */, 2DE2DF7F0627AE34006BEC99 /* MD5.hxx */, DC8C1BAB14B25DE7006440EE /* MindLink.cxx */, DC8C1BAC14B25DE7006440EE /* MindLink.hxx */, DC11F78B0DB36933003B505E /* MT24LC256.cxx */, DC11F78C0DB36933003B505E /* MT24LC256.hxx */, DCC527CD10B9DA19005E1287 /* NullDev.hxx */, 2DDBEB7408457B7D00812C11 /* OSystem.cxx */, 2DDBEB7508457B7D00812C11 /* OSystem.hxx */, 2DE2DF820627AE34006BEC99 /* Paddles.cxx */, 2DE2DF830627AE34006BEC99 /* Paddles.hxx */, DC53B6AD1F3622DA00AA6BFB /* PointingDevice.cxx */, DC3DAFAB1F2E233B00A64410 /* PointingDevice.hxx */, 2DE2DF840627AE34006BEC99 /* Props.cxx */, 2DE2DF850627AE34006BEC99 /* Props.hxx */, 2DE2DF860627AE34006BEC99 /* PropsSet.cxx */, 2DE2DF870627AE34006BEC99 /* PropsSet.hxx */, 2DE2DF890627AE34006BEC99 /* Random.hxx */, DC4AC6F10DC8DAEF00CD3AD2 /* SaveKey.cxx */, DC4AC6F20DC8DAEF00CD3AD2 /* SaveKey.hxx */, DC932D400F278A5200FEFEFC /* Serializable.hxx */, 2DE2DF8A0627AE34006BEC99 /* Serializer.cxx */, 2DE2DF8B0627AE34006BEC99 /* Serializer.hxx */, DC932D410F278A5200FEFEFC /* SerialPort.hxx */, 2D944848062904E800DD9879 /* Settings.cxx */, 2D733D77062895F1006265D9 /* Settings.hxx */, 2DE2DF8D0627AE34006BEC99 /* Sound.hxx */, 2DE2DF8E0627AE34006BEC99 /* Switches.cxx */, 2DE2DF8F0627AE34006BEC99 /* Switches.hxx */, DCC527CE10B9DA19005E1287 /* System.cxx */, DCC527CF10B9DA19005E1287 /* System.hxx */, DCD2839612E39F1200A808DC /* Thumbulator.cxx */, DCD2839712E39F1200A808DC /* Thumbulator.hxx */, DCE903E31DF5DCD10080A7F3 /* tia */, 2DE7242D08CE910900C889A8 /* TIASnd.cxx */, 2DE7242E08CE910900C889A8 /* TIASnd.hxx */, DC2AADAC194F389C0026C7A4 /* TIASurface.cxx */, DC2AADAD194F389C0026C7A4 /* TIASurface.hxx */, DCF3A7011DFC76BC008A8AF3 /* TIATypes.hxx */, DC1B2EC21E50036100F62837 /* TrakBall.hxx */, ); path = emucore; sourceTree = ""; }; 2D6050FA0898786C00C6DE89 /* gui */ = { isa = PBXGroup; children = ( 2DDBEAA3084578BF00812C11 /* AboutDialog.cxx */, 2DDBEAA4084578BF00812C11 /* AboutDialog.hxx */, 2DDBEAA6084578BF00812C11 /* AudioDialog.cxx */, 2DDBEAA7084578BF00812C11 /* AudioDialog.hxx */, 2DDBEAA8084578BF00812C11 /* BrowserDialog.cxx */, 2DDBEAA9084578BF00812C11 /* BrowserDialog.hxx */, 2DEF21F808BC033500B246B4 /* CheckListWidget.cxx */, 2DEF21F908BC033500B246B4 /* CheckListWidget.hxx */, DC44019C1F1A5D01008C08F6 /* ColorWidget.cxx */, DC44019D1F1A5D01008C08F6 /* ColorWidget.hxx */, DCFFE59B12100E1400DFA000 /* ComboDialog.cxx */, DCFFE59C12100E1400DFA000 /* ComboDialog.hxx */, 2DDBEAAA084578BF00812C11 /* Command.hxx */, 2D73959308C3EB4E0060BB99 /* CommandDialog.cxx */, 2D73959408C3EB4E0060BB99 /* CommandDialog.hxx */, 2D73959508C3EB4E0060BB99 /* CommandMenu.cxx */, 2D73959608C3EB4E0060BB99 /* CommandMenu.hxx */, DCDE17F617724E5D00EB1AC6 /* ConfigPathDialog.cxx */, DCDE17F717724E5D00EB1AC6 /* ConfigPathDialog.hxx */, DC5BE4B117C913AC0091FD64 /* ConsoleBFont.hxx */, 2D9217FA0857CC88001D664B /* ConsoleFont.hxx */, DC5BE4B217C913AC0091FD64 /* ConsoleMediumBFont.hxx */, DC8CF9BC17C15A27004B533D /* ConsoleMediumFont.hxx */, DC173F740E2CAC1E00320F94 /* ContextMenu.cxx */, DC173F750E2CAC1E00320F94 /* ContextMenu.hxx */, DC5ACB591FBFCE8E00A213FD /* DeveloperDialog.cxx */, DC5ACB5A1FBFCE8E00A213FD /* DeveloperDialog.hxx */, 2DDBEAAB084578BF00812C11 /* Dialog.cxx */, 2DDBEAAC084578BF00812C11 /* Dialog.hxx */, 2DDBEAAD084578BF00812C11 /* DialogContainer.cxx */, 2DDBEAAE084578BF00812C11 /* DialogContainer.hxx */, 2D403BA0086116D1001E31A1 /* EditableWidget.cxx */, 2D403BA1086116D1001E31A1 /* EditableWidget.hxx */, 2D403BA4086116D1001E31A1 /* EditTextWidget.cxx */, 2D403BA5086116D1001E31A1 /* EditTextWidget.hxx */, 2D05FF5E096E269100A518FE /* EventMappingWidget.cxx */, 2D05FF5F096E269100A518FE /* EventMappingWidget.hxx */, DC7A24DD173B1DBC00B20FE9 /* FileListWidget.cxx */, DC7A24DE173B1DBC00B20FE9 /* FileListWidget.hxx */, 2D9217FB0857CC88001D664B /* Font.cxx */, 2D9217FC0857CC88001D664B /* Font.hxx */, 2DDBEAB2084578BF00812C11 /* GameInfoDialog.cxx */, 2DDBEAB3084578BF00812C11 /* GameInfoDialog.hxx */, 2DDBEAB4084578BF00812C11 /* GameList.cxx */, 2DDBEAB5084578BF00812C11 /* GameList.hxx */, DC0DF8670F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx */, DC0DF8680F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx */, 2DDBEAB6084578BF00812C11 /* GuiObject.hxx */, 2DDBEAB8084578BF00812C11 /* HelpDialog.cxx */, 2DDBEAB9084578BF00812C11 /* HelpDialog.hxx */, 2D05FF60096E269100A518FE /* InputDialog.cxx */, 2D05FF61096E269100A518FE /* InputDialog.hxx */, 2D02207F08A301F200B9C76B /* InputTextDialog.cxx */, 2D02208008A301F200B9C76B /* InputTextDialog.hxx */, DC047FEC1A4A6F3600348F0F /* JoystickDialog.cxx */, DC047FED1A4A6F3600348F0F /* JoystickDialog.hxx */, 2DDBEABA084578BF00812C11 /* Launcher.cxx */, 2DDBEABB084578BF00812C11 /* Launcher.hxx */, 2DDBEABC084578BF00812C11 /* LauncherDialog.cxx */, 2DDBEABD084578BF00812C11 /* LauncherDialog.hxx */, DC5D2C5E0F129B1E004D1660 /* LauncherFilterDialog.cxx */, DC5D2C5F0F129B1E004D1660 /* LauncherFilterDialog.hxx */, 2DDBEAC0084578BF00812C11 /* ListWidget.cxx */, 2DDBEAC1084578BF00812C11 /* ListWidget.hxx */, DC6C726013CDEA0A008A5975 /* LoggerDialog.cxx */, DC6C726113CDEA0A008A5975 /* LoggerDialog.hxx */, 2DDBEAC2084578BF00812C11 /* Menu.cxx */, 2DDBEAC3084578BF00812C11 /* Menu.hxx */, DC98F35411F5B56200AA520F /* MessageBox.cxx */, DC98F35511F5B56200AA520F /* MessageBox.hxx */, 2DDBEAC4084578BF00812C11 /* OptionsDialog.cxx */, 2DDBEAC5084578BF00812C11 /* OptionsDialog.hxx */, 2DDBEAC6084578BF00812C11 /* PopUpWidget.cxx */, 2DDBEAC7084578BF00812C11 /* PopUpWidget.hxx */, 2DDBEAC8084578BF00812C11 /* ProgressDialog.cxx */, 2DDBEAC9084578BF00812C11 /* ProgressDialog.hxx */, DC5AAC2A1FCB24DF00C420A6 /* RadioButtonWidget.cxx */, DC5AAC2B1FCB24DF00C420A6 /* RadioButtonWidget.hxx */, DC5D2C4E0F117CFD004D1660 /* Rect.hxx */, DC4613650D92C03600D8DAB9 /* RomAuditDialog.cxx */, DC4613660D92C03600D8DAB9 /* RomAuditDialog.hxx */, DCE3BBF50C95CEDC00A671DF /* RomInfoWidget.cxx */, DCE3BBF60C95CEDC00A671DF /* RomInfoWidget.hxx */, 2DDBEACA084578BF00812C11 /* ScrollBarWidget.cxx */, 2DDBEACB084578BF00812C11 /* ScrollBarWidget.hxx */, DCDE17F817724E5D00EB1AC6 /* SnapshotDialog.cxx */, DCDE17F917724E5D00EB1AC6 /* SnapshotDialog.hxx */, DC5D2C4F0F117CFD004D1660 /* StellaFont.hxx */, DC5D2C500F117CFD004D1660 /* StellaLargeFont.hxx */, DC5D2C510F117CFD004D1660 /* StellaMediumFont.hxx */, 2DEF21FA08BC033500B246B4 /* StringListWidget.cxx */, 2DEF21FB08BC033500B246B4 /* StringListWidget.hxx */, 2DDBEAD0084578BF00812C11 /* TabWidget.cxx */, 2DDBEAD1084578BF00812C11 /* TabWidget.hxx */, DCE91589201543B900960CC0 /* TimeLineWidget.cxx */, DCE9158A201543B900960CC0 /* TimeLineWidget.hxx */, DCA82C6D1FEB4E780059340F /* TimeMachine.cxx */, DCA82C6E1FEB4E780059340F /* TimeMachine.hxx */, DCA82C6F1FEB4E780059340F /* TimeMachineDialog.cxx */, DCA82C701FEB4E780059340F /* TimeMachineDialog.hxx */, DC8078E60B4BD697005E9305 /* UIDialog.cxx */, DC8078E70B4BD697005E9305 /* UIDialog.hxx */, 2DDBEAD2084578BF00812C11 /* VideoDialog.cxx */, 2DDBEAD3084578BF00812C11 /* VideoDialog.hxx */, 2DDBEAD4084578BF00812C11 /* Widget.cxx */, 2DDBEAD5084578BF00812C11 /* Widget.hxx */, ); path = gui; sourceTree = ""; }; 2D605130089879BA00C6DE89 /* debugger */ = { isa = PBXGroup; children = ( DC6B2BA011037FF200F199A7 /* CartDebug.cxx */, DC6B2BA111037FF200F199A7 /* CartDebug.hxx */, 2D9555DD0880E79600466554 /* CpuDebug.cxx */, 2D9555DE0880E79600466554 /* CpuDebug.hxx */, 2D659E2D085D3DD6005D96C8 /* Debugger.cxx */, 2D659E2E085D3DD6005D96C8 /* Debugger.hxx */, DC8078DA0B4BD5F3005E9305 /* DebuggerExpressions.hxx */, 2D659E31085D3DD6005D96C8 /* DebuggerParser.cxx */, 2D659E32085D3DD6005D96C8 /* DebuggerParser.hxx */, 2DF971D70892CEA400F64D23 /* DebuggerSystem.hxx */, DC6B2BA211037FF200F199A7 /* DiStella.cxx */, DC6B2BA311037FF200F199A7 /* DiStella.hxx */, 2DF971DF0892CEA400F64D23 /* Expression.hxx */, 2D20F9E308C603C500A73076 /* gui */, 2D403BCF08611A69001E31A1 /* PackedBitArray.hxx */, DCA00FF50DBABCAD00C3823D /* RiotDebug.cxx */, DCA00FF60DBABCAD00C3823D /* RiotDebug.hxx */, 2D30F8750868A4DB00938B9D /* TIADebug.cxx */, 2D30F8760868A4DB00938B9D /* TIADebug.hxx */, 2D6CC10308C811A600B8F642 /* TiaZoomWidget.cxx */, 2D6CC10408C811A600B8F642 /* TiaZoomWidget.hxx */, DC2874061F8F2278004BF21A /* TrapArray.hxx */, ); path = debugger; sourceTree = ""; }; 2D60513708987A5400C6DE89 /* yacc */ = { isa = PBXGroup; children = ( 2D313F0A0879C4C0005BD3E5 /* YaccParser.cxx */, 2D313F0B0879C4C0005BD3E5 /* YaccParser.hxx */, ); path = yacc; sourceTree = ""; }; DC3EE83B1E2C0E4400905161 /* zlib */ = { isa = PBXGroup; children = ( DC3EE83C1E2C0E6D00905161 /* adler32.c */, DC3EE83D1E2C0E6D00905161 /* compress.c */, DC3EE83E1E2C0E6D00905161 /* crc32.c */, DC3EE83F1E2C0E6D00905161 /* crc32.h */, DC3EE8401E2C0E6D00905161 /* deflate.c */, DC3EE8411E2C0E6D00905161 /* deflate.h */, DC3EE8421E2C0E6D00905161 /* gzclose.c */, DC3EE8431E2C0E6D00905161 /* gzguts.h */, DC3EE8441E2C0E6D00905161 /* gzlib.c */, DC3EE8451E2C0E6D00905161 /* gzread.c */, DC3EE8461E2C0E6D00905161 /* gzwrite.c */, DC3EE8471E2C0E6D00905161 /* infback.c */, DC3EE8481E2C0E6D00905161 /* inffast.c */, DC3EE8491E2C0E6D00905161 /* inffast.h */, DC3EE84A1E2C0E6D00905161 /* inffixed.h */, DC3EE84B1E2C0E6D00905161 /* inflate.c */, DC3EE84C1E2C0E6D00905161 /* inflate.h */, DC3EE84D1E2C0E6D00905161 /* inftrees.c */, DC3EE84E1E2C0E6D00905161 /* inftrees.h */, DC3EE84F1E2C0E6D00905161 /* trees.c */, DC3EE8501E2C0E6D00905161 /* trees.h */, DC3EE8511E2C0E6D00905161 /* uncompr.c */, DC3EE8521E2C0E6D00905161 /* zconf.h */, DC3EE8531E2C0E6D00905161 /* zlib.h */, DC3EE8541E2C0E6D00905161 /* zutil.c */, DC3EE8551E2C0E6D00905161 /* zutil.h */, ); path = zlib; sourceTree = ""; }; DCC467EA14FBEC9600E15508 /* tv_filters */ = { isa = PBXGroup; children = ( DC2B85E51EF5EF2300379EB9 /* AtariNTSC.cxx */, DC2B85E61EF5EF2300379EB9 /* AtariNTSC.hxx */, DC5EE7C014F7C165001C628C /* NTSCFilter.cxx */, DC5EE7C114F7C165001C628C /* NTSCFilter.hxx */, ); path = tv_filters; sourceTree = ""; }; DCCC0C9109C3541E0088BFF1 /* cheat */ = { isa = PBXGroup; children = ( DC47454A09C34BFA00EDDA3A /* BankRomCheat.cxx */, DC47454B09C34BFA00EDDA3A /* BankRomCheat.hxx */, DC47454C09C34BFA00EDDA3A /* Cheat.hxx */, DC47454D09C34BFA00EDDA3A /* CheatCodeDialog.cxx */, DC47454E09C34BFA00EDDA3A /* CheatCodeDialog.hxx */, DC47454F09C34BFA00EDDA3A /* CheatManager.cxx */, DC47455009C34BFA00EDDA3A /* CheatManager.hxx */, DC47455109C34BFA00EDDA3A /* CheetahCheat.cxx */, DC47455209C34BFA00EDDA3A /* CheetahCheat.hxx */, DC47455309C34BFA00EDDA3A /* RamCheat.cxx */, DC47455409C34BFA00EDDA3A /* RamCheat.hxx */, ); path = cheat; sourceTree = ""; }; DCD6FC5A11C281A1005DA767 /* libpng */ = { isa = PBXGroup; children = ( DCD6FC5D11C281ED005DA767 /* png.c */, DCD6FC5E11C281ED005DA767 /* png.h */, DCD6FC5F11C281ED005DA767 /* pngconf.h */, DC6967071361FD0A0036499D /* pngdebug.h */, DCD6FC6011C281ED005DA767 /* pngerror.c */, DCD6FC6111C281ED005DA767 /* pngget.c */, DC6967081361FD0A0036499D /* pnginfo.h */, DC6967091361FD0A0036499D /* pnglibconf.h */, DCD6FC6211C281ED005DA767 /* pngmem.c */, DCD6FC6311C281ED005DA767 /* pngpread.c */, DCD6FC6411C281ED005DA767 /* pngpriv.h */, DCD6FC6511C281ED005DA767 /* pngread.c */, DCD6FC6611C281ED005DA767 /* pngrio.c */, DCD6FC6711C281ED005DA767 /* pngrtran.c */, DCD6FC6811C281ED005DA767 /* pngrutil.c */, DCD6FC6911C281ED005DA767 /* pngset.c */, DC69670A1361FD0A0036499D /* pngstruct.h */, DCD6FC6B11C281ED005DA767 /* pngtrans.c */, DCD6FC6C11C281ED005DA767 /* pngwio.c */, DCD6FC6D11C281ED005DA767 /* pngwrite.c */, DCD6FC6E11C281ED005DA767 /* pngwtran.c */, DCD6FC6F11C281ED005DA767 /* pngwutil.c */, ); path = libpng; sourceTree = ""; }; DCE903E31DF5DCD10080A7F3 /* tia */ = { isa = PBXGroup; children = ( DCF3A6CD1DFC75E3008A8AF3 /* Background.cxx */, DCF3A6CE1DFC75E3008A8AF3 /* Background.hxx */, DCF3A6CF1DFC75E3008A8AF3 /* Ball.cxx */, DCF3A6D01DFC75E3008A8AF3 /* Ball.hxx */, DCF3A6D21DFC75E3008A8AF3 /* DelayQueue.hxx */, DCEC585B1E945175002F0246 /* DelayQueueIterator.hxx */, DCFB9FAB1ECA2609004FD69B /* DelayQueueIteratorImpl.hxx */, DCF3A6D41DFC75E3008A8AF3 /* DelayQueueMember.hxx */, DCF3A6D51DFC75E3008A8AF3 /* DrawCounterDecodes.cxx */, DCF3A6D61DFC75E3008A8AF3 /* DrawCounterDecodes.hxx */, E0DFDD731F81A358000F3505 /* frame-manager */, DCE8B1861E7E03B300189864 /* FrameLayout.hxx */, DCF3A6D91DFC75E3008A8AF3 /* LatchedInput.cxx */, DCF3A6DA1DFC75E3008A8AF3 /* LatchedInput.hxx */, DCF3A6DB1DFC75E3008A8AF3 /* Missile.cxx */, DCF3A6DC1DFC75E3008A8AF3 /* Missile.hxx */, DCF3A6DE1DFC75E3008A8AF3 /* PaddleReader.cxx */, DCF3A6DF1DFC75E3008A8AF3 /* PaddleReader.hxx */, DCF3A6E01DFC75E3008A8AF3 /* Player.cxx */, DCF3A6E11DFC75E3008A8AF3 /* Player.hxx */, DCF3A6E21DFC75E3008A8AF3 /* Playfield.cxx */, DCF3A6E31DFC75E3008A8AF3 /* Playfield.hxx */, DCF3A6E41DFC75E3008A8AF3 /* TIA.cxx */, DCF3A6E51DFC75E3008A8AF3 /* TIA.hxx */, DC68F88F1FA64C5300F4A2CC /* TIAConstants.hxx */, ); path = tia; sourceTree = ""; }; E0DFDD731F81A358000F3505 /* frame-manager */ = { isa = PBXGroup; children = ( E0DFDD781F81A358000F3505 /* AbstractFrameManager.cxx */, DCCA26B11FA64D5E000EE4D8 /* AbstractFrameManager.hxx */, E0306E0A1F93E916003DDD52 /* FrameLayoutDetector.cxx */, E0306E071F93E915003DDD52 /* FrameLayoutDetector.hxx */, E0DFDD7B1F81A358000F3505 /* FrameManager.cxx */, DCCA26B21FA64D5E000EE4D8 /* FrameManager.hxx */, E0306E091F93E915003DDD52 /* JitterEmulation.cxx */, E0306E0B1F93E916003DDD52 /* JitterEmulation.hxx */, E0306E061F93E915003DDD52 /* YStartDetector.cxx */, E0306E081F93E915003DDD52 /* YStartDetector.hxx */, ); path = "frame-manager"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 2D9173CA09BA90380026E9FF /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 2D9173CB09BA90380026E9FF /* SDLMain.h in Headers */, 2D9173CC09BA90380026E9FF /* Booster.hxx in Headers */, 2D9173CD09BA90380026E9FF /* Cart.hxx in Headers */, 2D9173CE09BA90380026E9FF /* Cart2K.hxx in Headers */, 2D9173CF09BA90380026E9FF /* Cart3F.hxx in Headers */, DC3EE86D1E2C0E6D00905161 /* zlib.h in Headers */, DC3EE86A1E2C0E6D00905161 /* trees.h in Headers */, 2D9173D009BA90380026E9FF /* Cart4K.hxx in Headers */, 2D9173D109BA90380026E9FF /* CartAR.hxx in Headers */, 2D9173D209BA90380026E9FF /* CartCV.hxx in Headers */, 2D9173D309BA90380026E9FF /* CartDPC.hxx in Headers */, DC71EAA01FDA06D2008827CB /* CartMNetwork.hxx in Headers */, 2D9173D409BA90380026E9FF /* CartE0.hxx in Headers */, DC5AAC281FCB24AB00C420A6 /* EventHandlerConstants.hxx in Headers */, DC73BD8A1915E5E3003FAFAD /* FBSurface.hxx in Headers */, 2D9173D509BA90380026E9FF /* CartE7.hxx in Headers */, 2D9173D609BA90380026E9FF /* CartF4.hxx in Headers */, 2D9173D709BA90380026E9FF /* CartF4SC.hxx in Headers */, DCF3A6FD1DFC75E3008A8AF3 /* Playfield.hxx in Headers */, 2D9173D809BA90380026E9FF /* CartF6.hxx in Headers */, 2D9173D909BA90380026E9FF /* CartF6SC.hxx in Headers */, DC71EAA61FDA070D008827CB /* CartE78KWidget.hxx in Headers */, DC9616311F817830008A2206 /* FlashWidget.hxx in Headers */, 2D9173DA09BA90380026E9FF /* CartF8.hxx in Headers */, DC3EE8591E2C0E6D00905161 /* crc32.h in Headers */, 2D9173DB09BA90380026E9FF /* CartF8SC.hxx in Headers */, 2D9173DD09BA90380026E9FF /* CartFE.hxx in Headers */, DC62E6481960E87B007AEF05 /* AtariVoxWidget.hxx in Headers */, 2D9173E009BA90380026E9FF /* Console.hxx in Headers */, 2D9173E109BA90380026E9FF /* Control.hxx in Headers */, DC5AAC2D1FCB24DF00C420A6 /* RadioButtonWidget.hxx in Headers */, 2D9173E309BA90380026E9FF /* Driving.hxx in Headers */, 2D9173E409BA90380026E9FF /* Event.hxx in Headers */, 2D9173E509BA90380026E9FF /* Joystick.hxx in Headers */, 2D9173E609BA90380026E9FF /* Keyboard.hxx in Headers */, DCACBAD51C54298300703A9B /* CartCVPlus.hxx in Headers */, DCACBAD11C54296300703A9B /* CartCVPlusWidget.hxx in Headers */, DC1B2EC81E50036100F62837 /* TrakBall.hxx in Headers */, 2D9173E709BA90380026E9FF /* M6532.hxx in Headers */, 2D9173E809BA90380026E9FF /* MD5.hxx in Headers */, 2D9173EA09BA90380026E9FF /* Paddles.hxx in Headers */, 2D9173EB09BA90380026E9FF /* Props.hxx in Headers */, DC5ACB5C1FBFCE8E00A213FD /* DeveloperDialog.hxx in Headers */, 2D9173EC09BA90380026E9FF /* PropsSet.hxx in Headers */, 2D9173ED09BA90380026E9FF /* Random.hxx in Headers */, 2D9173EE09BA90380026E9FF /* Serializer.hxx in Headers */, 2D9173EF09BA90380026E9FF /* Sound.hxx in Headers */, 2D9173F009BA90380026E9FF /* Switches.hxx in Headers */, 2D9173F909BA90380026E9FF /* EventHandler.hxx in Headers */, 2D9173FA09BA90380026E9FF /* FrameBuffer.hxx in Headers */, 2D9173FB09BA90380026E9FF /* Settings.hxx in Headers */, 2D9173FC09BA90380026E9FF /* SettingsMACOSX.hxx in Headers */, 2D9173FF09BA90380026E9FF /* OSystemMACOSX.hxx in Headers */, 2D91740009BA90380026E9FF /* AboutDialog.hxx in Headers */, DCF3A6EE1DFC75E3008A8AF3 /* DelayQueueMember.hxx in Headers */, DC96162F1F817830008A2206 /* AtariMouseWidget.hxx in Headers */, DCF4907A1A0ECE5B00A67AA9 /* Vec.hxx in Headers */, 2D91740109BA90380026E9FF /* AudioDialog.hxx in Headers */, DC71EA9E1FDA06D2008827CB /* CartE78K.hxx in Headers */, 2D91740209BA90380026E9FF /* BrowserDialog.hxx in Headers */, 2D91740309BA90380026E9FF /* Command.hxx in Headers */, DC3EE85B1E2C0E6D00905161 /* deflate.h in Headers */, 2D91740409BA90380026E9FF /* Dialog.hxx in Headers */, 2D91740509BA90380026E9FF /* DialogContainer.hxx in Headers */, DC6D39881A3CE65000171E71 /* CartWDWidget.hxx in Headers */, 2D91740609BA90380026E9FF /* GameInfoDialog.hxx in Headers */, DCE9158C201543B900960CC0 /* TimeLineWidget.hxx in Headers */, 2D91740709BA90380026E9FF /* GameList.hxx in Headers */, 2D91740809BA90380026E9FF /* GuiObject.hxx in Headers */, DC73BD861915E5B1003FAFAD /* FBSurfaceSDL2.hxx in Headers */, 2D91740A09BA90380026E9FF /* HelpDialog.hxx in Headers */, 2D91740B09BA90380026E9FF /* Launcher.hxx in Headers */, 2D91740C09BA90380026E9FF /* LauncherDialog.hxx in Headers */, DC2AADB5194F390F0026C7A4 /* CartRamWidget.hxx in Headers */, 2D91740E09BA90380026E9FF /* ListWidget.hxx in Headers */, 2D91740F09BA90380026E9FF /* Menu.hxx in Headers */, 2D91741009BA90380026E9FF /* OptionsDialog.hxx in Headers */, DCEC58591E945125002F0246 /* DelayQueueWidget.hxx in Headers */, 2D91741109BA90380026E9FF /* PopUpWidget.hxx in Headers */, 2D91741209BA90380026E9FF /* ProgressDialog.hxx in Headers */, 2D91741309BA90380026E9FF /* ScrollBarWidget.hxx in Headers */, 2D91741609BA90380026E9FF /* TabWidget.hxx in Headers */, DCB2ECB01F0AECA3009738A6 /* CartDetector.hxx in Headers */, 2D91741709BA90380026E9FF /* VideoDialog.hxx in Headers */, 2D91741809BA90380026E9FF /* Widget.hxx in Headers */, 2D91741909BA90380026E9FF /* CartUA.hxx in Headers */, DCE8B1871E7E03B300189864 /* FrameLayout.hxx in Headers */, 2D91741A09BA90380026E9FF /* FSNode.hxx in Headers */, 2D91741B09BA90380026E9FF /* OSystem.hxx in Headers */, 2D91741D09BA90380026E9FF /* Preferences.h in Headers */, DC6A18F919B3E65500DEB242 /* CartMDMWidget.hxx in Headers */, 2D91741F09BA90380026E9FF /* AboutBox.h in Headers */, 2D91742009BA90380026E9FF /* ConsoleFont.hxx in Headers */, 2D91742109BA90380026E9FF /* Font.hxx in Headers */, 2D91742209BA90380026E9FF /* Debugger.hxx in Headers */, 2D91742309BA90380026E9FF /* DebuggerParser.hxx in Headers */, 2D91742409BA90380026E9FF /* EditableWidget.hxx in Headers */, DC3EE86F1E2C0E6D00905161 /* zutil.h in Headers */, 2D91742509BA90380026E9FF /* EditTextWidget.hxx in Headers */, DCB87E581A104C1E00BF2A3B /* MediaFactory.hxx in Headers */, 2D91742809BA90380026E9FF /* PackedBitArray.hxx in Headers */, 2D91742909BA90380026E9FF /* TIADebug.hxx in Headers */, 2D91742A09BA90380026E9FF /* YaccParser.hxx in Headers */, 2D91742B09BA90380026E9FF /* Cart3E.hxx in Headers */, DCF3A6F61DFC75E3008A8AF3 /* Missile.hxx in Headers */, DC9616351F817830008A2206 /* TrakBallWidget.hxx in Headers */, 2D91742C09BA90380026E9FF /* CpuDebug.hxx in Headers */, DC3EE86C1E2C0E6D00905161 /* zconf.h in Headers */, 2D91743609BA90380026E9FF /* DebuggerSystem.hxx in Headers */, 2D91743A09BA90380026E9FF /* Expression.hxx in Headers */, 2D91744F09BA90380026E9FF /* InputTextDialog.hxx in Headers */, DC1B2EC61E50036100F62837 /* AtariMouse.hxx in Headers */, DC9616331F817830008A2206 /* PointingDeviceWidget.hxx in Headers */, 2D91745009BA90380026E9FF /* CheckListWidget.hxx in Headers */, 2D91745109BA90380026E9FF /* StringListWidget.hxx in Headers */, DC62E64A1960E87B007AEF05 /* SaveKeyWidget.hxx in Headers */, 2D91745209BA90380026E9FF /* CommandDialog.hxx in Headers */, 2D91745309BA90380026E9FF /* CommandMenu.hxx in Headers */, DCB2ECAE1F0AECA3009738A6 /* BSType.hxx in Headers */, E0306E111F93E916003DDD52 /* JitterEmulation.hxx in Headers */, 2D91745509BA90380026E9FF /* CpuWidget.hxx in Headers */, 2D91745609BA90380026E9FF /* DataGridOpsWidget.hxx in Headers */, 2D91745709BA90380026E9FF /* DataGridWidget.hxx in Headers */, DCF3A6EC1DFC75E3008A8AF3 /* DelayQueue.hxx in Headers */, DCA078341F8C1B04008EFEE5 /* LinkedObjectPool.hxx in Headers */, 2D91745809BA90380026E9FF /* DebuggerDialog.hxx in Headers */, DC2C5EDB1F8F2403007D2A09 /* smartmod.hxx in Headers */, DCE5CDE41BA10024005CD08A /* RiotRamWidget.hxx in Headers */, DCF3A6E81DFC75E3008A8AF3 /* Background.hxx in Headers */, DCFB9FAC1ECA2609004FD69B /* DelayQueueIteratorImpl.hxx in Headers */, DCA078351F8C1B04008EFEE5 /* SDL_lib.hxx in Headers */, DCDA03B11A2009BB00711920 /* CartWD.hxx in Headers */, 2D91745909BA90380026E9FF /* PromptWidget.hxx in Headers */, DC2AADAF194F389C0026C7A4 /* CartDASH.hxx in Headers */, 2D91745A09BA90380026E9FF /* RamWidget.hxx in Headers */, 2D91745B09BA90380026E9FF /* RomListWidget.hxx in Headers */, 2D91745C09BA90380026E9FF /* RomWidget.hxx in Headers */, 2D91745D09BA90380026E9FF /* TiaInfoWidget.hxx in Headers */, 2D91745E09BA90380026E9FF /* TiaOutputWidget.hxx in Headers */, 2D91745F09BA90380026E9FF /* TiaWidget.hxx in Headers */, 2D91746009BA90380026E9FF /* ToggleBitWidget.hxx in Headers */, 2D91746109BA90380026E9FF /* TogglePixelWidget.hxx in Headers */, 2D91746209BA90380026E9FF /* ToggleWidget.hxx in Headers */, 2D91746409BA90380026E9FF /* TiaZoomWidget.hxx in Headers */, 2D91746509BA90380026E9FF /* TIASnd.hxx in Headers */, 2D91746609BA90380026E9FF /* AudioWidget.hxx in Headers */, 2D91746909BA90380026E9FF /* EventMappingWidget.hxx in Headers */, 2D91746A09BA90380026E9FF /* InputDialog.hxx in Headers */, DC47455609C34BFA00EDDA3A /* BankRomCheat.hxx in Headers */, DC47455709C34BFA00EDDA3A /* Cheat.hxx in Headers */, DC47455909C34BFA00EDDA3A /* CheatCodeDialog.hxx in Headers */, DC47455B09C34BFA00EDDA3A /* CheatManager.hxx in Headers */, DC47455D09C34BFA00EDDA3A /* CheetahCheat.hxx in Headers */, DC47455F09C34BFA00EDDA3A /* RamCheat.hxx in Headers */, DCD56D390B247D920092F9F8 /* Cart4A50.hxx in Headers */, DC5AAC291FCB24AB00C420A6 /* FrameBufferConstants.hxx in Headers */, E0306E0D1F93E916003DDD52 /* FrameLayoutDetector.hxx in Headers */, DC8078DB0B4BD5F3005E9305 /* DebuggerExpressions.hxx in Headers */, DC8078EB0B4BD697005E9305 /* UIDialog.hxx in Headers */, DCEECE570B5E5E540021D754 /* Cart0840.hxx in Headers */, DCE3BBFA0C95CEDC00A671DF /* RomInfoWidget.hxx in Headers */, DC0984860D3985160073C852 /* CartSB.hxx in Headers */, DCEC585E1E945175002F0246 /* DelayQueueIterator.hxx in Headers */, DCA23AEA0D75B22500F77B33 /* CartX07.hxx in Headers */, DC4613680D92C03600D8DAB9 /* RomAuditDialog.hxx in Headers */, DC487FB70DA5350900E12499 /* AtariVox.hxx in Headers */, DC11F78E0DB36933003B505E /* MT24LC256.hxx in Headers */, DC1FC18B0DB3B2C7009B3DF7 /* SerialPortMACOSX.hxx in Headers */, DCA00FF80DBABCAD00C3823D /* RiotDebug.hxx in Headers */, DC4AC6F00DC8DACB00CD3AD2 /* RiotWidget.hxx in Headers */, DC4AC6F40DC8DAEF00CD3AD2 /* SaveKey.hxx in Headers */, DC173F770E2CAC1E00320F94 /* ContextMenu.hxx in Headers */, DC0DF86A0F0DAAF500B0F1F3 /* GlobalPropsDialog.hxx in Headers */, DC5D2C520F117CFD004D1660 /* Rect.hxx in Headers */, DC71EAA81FDA070D008827CB /* CartMNetworkWidget.hxx in Headers */, DC5D2C530F117CFD004D1660 /* StellaFont.hxx in Headers */, DC5D2C540F117CFD004D1660 /* StellaLargeFont.hxx in Headers */, DC5D2C550F117CFD004D1660 /* StellaMediumFont.hxx in Headers */, DC5D2C610F129B1E004D1660 /* LauncherFilterDialog.hxx in Headers */, DC3EE8681E2C0E6D00905161 /* inftrees.h in Headers */, DC932D440F278A5200FEFEFC /* DefProps.hxx in Headers */, DC932D450F278A5200FEFEFC /* Serializable.hxx in Headers */, DC932D460F278A5200FEFEFC /* SerialPort.hxx in Headers */, DC9EA8880F729A36000452B5 /* KidVid.hxx in Headers */, DCF3A7021DFC76BC008A8AF3 /* TIATypes.hxx in Headers */, DCF467B80F93993B00B25D7A /* SoundNull.hxx in Headers */, DCBDDE9F1D6A5F2F009DF1E9 /* Cart3EPlus.hxx in Headers */, DCF467BD0F9399F500B25D7A /* Version.hxx in Headers */, DC2B85E81EF5EF2300379EB9 /* AtariNTSC.hxx in Headers */, DCF467C30F939A1400B25D7A /* CartEF.hxx in Headers */, DC68F8901FA64C5300F4A2CC /* TIAConstants.hxx in Headers */, DCA82C721FEB4E780059340F /* TimeMachine.hxx in Headers */, DCF467C50F939A1400B25D7A /* CartEFSC.hxx in Headers */, DC3EE8641E2C0E6D00905161 /* inffixed.h in Headers */, DC5D1AA7102C6FC900E59AC1 /* Stack.hxx in Headers */, DCF7B0DE10A762FC007A2870 /* CartF0.hxx in Headers */, DCF7B0E010A762FC007A2870 /* CartFA.hxx in Headers */, DCC527D110B9DA19005E1287 /* Device.hxx in Headers */, DCC527D310B9DA19005E1287 /* M6502.hxx in Headers */, DC3EE8661E2C0E6D00905161 /* inflate.h in Headers */, DCC527D510B9DA19005E1287 /* NullDev.hxx in Headers */, DCC527D710B9DA19005E1287 /* System.hxx in Headers */, CFE3F6161E84A9CE00A8204E /* CartCDF.hxx in Headers */, DCC527DB10B9DA6A005E1287 /* bspf.hxx in Headers */, DC6B2BA511037FF200F199A7 /* CartDebug.hxx in Headers */, DC6B2BA711037FF200F199A7 /* DiStella.hxx in Headers */, DCD3F7C611340AAF00DBA3AE /* Genesis.hxx in Headers */, DCAD60A91152F8BD00BC4184 /* CartDPCPlus.hxx in Headers */, DCD6FC7111C281ED005DA767 /* png.h in Headers */, DCD6FC7211C281ED005DA767 /* pngconf.h in Headers */, DCF3A6F41DFC75E3008A8AF3 /* LatchedInput.hxx in Headers */, DC74E5C7198AF12700F37E36 /* CartDASHWidget.hxx in Headers */, DCD6FC7711C281ED005DA767 /* pngpriv.h in Headers */, CFE3F60C1E84A9A200A8204E /* CartBUSWidget.hxx in Headers */, DCD6FC9411C28C6F005DA767 /* PNGLibrary.hxx in Headers */, DC98F35711F5B56200AA520F /* MessageBox.hxx in Headers */, DCFFE59E12100E1400DFA000 /* ComboDialog.hxx in Headers */, DCD2839912E39F1200A808DC /* Thumbulator.hxx in Headers */, DC69670B1361FD0A0036499D /* pngdebug.h in Headers */, DC69670C1361FD0A0036499D /* pnginfo.h in Headers */, DC69670D1361FD0A0036499D /* pnglibconf.h in Headers */, DC69670E1361FD0A0036499D /* pngstruct.h in Headers */, DC74D6A2138D4D7E00F05C5C /* StringParser.hxx in Headers */, DC2874071F8F2278004BF21A /* TrapArray.hxx in Headers */, DCCA26B41FA64D5E000EE4D8 /* FrameManager.hxx in Headers */, DC6C726313CDEA0A008A5975 /* LoggerDialog.hxx in Headers */, DC8C1BAE14B25DE7006440EE /* CartCM.hxx in Headers */, DCF3A6FB1DFC75E3008A8AF3 /* Player.hxx in Headers */, DCDDEAC71F5DBF0400C67366 /* StateManager.hxx in Headers */, DC8C1BB014B25DE7006440EE /* CompuMate.hxx in Headers */, DC8C1BB214B25DE7006440EE /* MindLink.hxx in Headers */, DCCF47DE14B60DEE00814FAB /* ControllerWidget.hxx in Headers */, DCCF47E014B60DEE00814FAB /* JoystickWidget.hxx in Headers */, DCCF49B814B7544A00814FAB /* PaddleWidget.hxx in Headers */, DCCF4AD214B7E6C300814FAB /* BoosterWidget.hxx in Headers */, DCCF4AD314B7E6C300814FAB /* NullControlWidget.hxx in Headers */, DCCF4ADD14B9433100814FAB /* GenesisWidget.hxx in Headers */, DCF3A6EA1DFC75E3008A8AF3 /* Ball.hxx in Headers */, DCBDDE9B1D6A5F0E009DF1E9 /* Cart3EPlusWidget.hxx in Headers */, DCCF4B0314BA27EB00814FAB /* DrivingWidget.hxx in Headers */, DCCF4B0514BA27EB00814FAB /* KeyboardWidget.hxx in Headers */, DC5C768F14C26F7C0031EBC7 /* StellaKeys.hxx in Headers */, DC36D2C914CAFAB0007DC821 /* CartFA2.hxx in Headers */, DC56FCDF14CCCC4900A31CC3 /* MouseControl.hxx in Headers */, DC5EE7C314F7C165001C628C /* NTSCFilter.hxx in Headers */, DC67270C1556F4860023653B /* CartCTY.hxx in Headers */, DC1B2EC41E50036100F62837 /* AmigaMouse.hxx in Headers */, DC67270D1556F4860023653B /* CartCTYTunes.hxx in Headers */, DCE395DB16CB0B2B008DB1E5 /* FSNodePOSIX.hxx in Headers */, DCE395EF16CB0B5F008DB1E5 /* FSNodeFactory.hxx in Headers */, DCE395F116CB0B5F008DB1E5 /* FSNodeZIP.hxx in Headers */, DCE395F316CB0B5F008DB1E5 /* ZipHandler.hxx in Headers */, DCAAE5D41715887B0080BB82 /* Cart2KWidget.hxx in Headers */, DCAAE5D61715887B0080BB82 /* Cart3FWidget.hxx in Headers */, DCAAE5D81715887B0080BB82 /* Cart4KWidget.hxx in Headers */, DCAAE5DA1715887B0080BB82 /* Cart0840Widget.hxx in Headers */, DCAAE5DC1715887B0080BB82 /* CartCVWidget.hxx in Headers */, DCAAE5DD1715887B0080BB82 /* CartDebugWidget.hxx in Headers */, DCAAE5DF1715887B0080BB82 /* CartEFSCWidget.hxx in Headers */, DCAAE5E11715887B0080BB82 /* CartEFWidget.hxx in Headers */, DCAAE5E31715887B0080BB82 /* CartF0Widget.hxx in Headers */, DCAAE5E51715887B0080BB82 /* CartF4SCWidget.hxx in Headers */, DCAAE5E71715887B0080BB82 /* CartF4Widget.hxx in Headers */, DCAAE5E91715887B0080BB82 /* CartF6SCWidget.hxx in Headers */, DCAAE5EB1715887B0080BB82 /* CartF6Widget.hxx in Headers */, DCAAE5ED1715887B0080BB82 /* CartF8SCWidget.hxx in Headers */, DCAAE5EF1715887B0080BB82 /* CartF8Widget.hxx in Headers */, DCAAE5F11715887B0080BB82 /* CartFAWidget.hxx in Headers */, DCAAE5F31715887B0080BB82 /* CartUAWidget.hxx in Headers */, DC676A421729A0B000E4E73D /* Cart3EWidget.hxx in Headers */, DC676A441729A0B000E4E73D /* Cart4A50Widget.hxx in Headers */, CFE3F6141E84A9CE00A8204E /* CartBUS.hxx in Headers */, DC676A461729A0B000E4E73D /* CartARWidget.hxx in Headers */, DC676A481729A0B000E4E73D /* CartCMWidget.hxx in Headers */, DC676A4A1729A0B000E4E73D /* CartCTYWidget.hxx in Headers */, DC676A4C1729A0B000E4E73D /* CartDPCPlusWidget.hxx in Headers */, DC676A4E1729A0B000E4E73D /* CartDPCWidget.hxx in Headers */, DCCA26B31FA64D5E000EE4D8 /* AbstractFrameManager.hxx in Headers */, DC3EE8631E2C0E6D00905161 /* inffast.h in Headers */, DC676A501729A0B000E4E73D /* CartE0Widget.hxx in Headers */, DC676A521729A0B000E4E73D /* CartE7Widget.hxx in Headers */, DC676A541729A0B000E4E73D /* CartFA2Widget.hxx in Headers */, DC676A561729A0B000E4E73D /* CartFEWidget.hxx in Headers */, DC676A5A1729A0B000E4E73D /* CartSBWidget.hxx in Headers */, DC676A5C1729A0B000E4E73D /* CartX07Widget.hxx in Headers */, DC3DAFAC1F2E233B00A64410 /* PointingDevice.hxx in Headers */, DC7A24D5173B1CF600B20FE9 /* Variant.hxx in Headers */, DC7A24E0173B1DBC00B20FE9 /* FileListWidget.hxx in Headers */, DC13B540176FF2F500B8B4BB /* RomListSettings.hxx in Headers */, DC3EE85D1E2C0E6D00905161 /* gzguts.h in Headers */, DCDE17FB17724E5D00EB1AC6 /* ConfigPathDialog.hxx in Headers */, DCDE17FD17724E5D00EB1AC6 /* SnapshotDialog.hxx in Headers */, DC79F81317A88D9E00288B91 /* Base.hxx in Headers */, DC2AADB1194F389C0026C7A4 /* TIASurface.hxx in Headers */, DC8CF9BD17C15A27004B533D /* ConsoleMediumFont.hxx in Headers */, DC5BE4B317C913AC0091FD64 /* ConsoleBFont.hxx in Headers */, DC5BE4B417C913AC0091FD64 /* ConsoleMediumBFont.hxx in Headers */, DCAACAF7188D631500A4D282 /* Cart4KSC.hxx in Headers */, DCAACAF9188D631500A4D282 /* CartBF.hxx in Headers */, DCAACAFB188D631500A4D282 /* CartBFSC.hxx in Headers */, DCAACAFD188D631500A4D282 /* CartDF.hxx in Headers */, DCAACAFF188D631500A4D282 /* CartDFSC.hxx in Headers */, DCAACB0F188D636F00A4D282 /* Cart4KSCWidget.hxx in Headers */, DCAACB11188D636F00A4D282 /* CartBFSCWidget.hxx in Headers */, DCA82C741FEB4E780059340F /* TimeMachineDialog.hxx in Headers */, DC6A18FD19B3E67A00DEB242 /* CartMDM.hxx in Headers */, DCDDEAC51F5DBF0400C67366 /* RewindManager.hxx in Headers */, DCAACB13188D636F00A4D282 /* CartBFWidget.hxx in Headers */, DCAACB15188D636F00A4D282 /* CartDFSCWidget.hxx in Headers */, DC44019F1F1A5D01008C08F6 /* ColorWidget.hxx in Headers */, E0306E0E1F93E916003DDD52 /* YStartDetector.hxx in Headers */, DC96162D1F817830008A2206 /* AmigaMouseWidget.hxx in Headers */, DCAACB17188D636F00A4D282 /* CartDFWidget.hxx in Headers */, DCF3A6FF1DFC75E3008A8AF3 /* TIA.hxx in Headers */, DC368F5718A2FB710084199C /* FrameBufferSDL2.hxx in Headers */, DC368F5918A2FB710084199C /* SoundSDL2.hxx in Headers */, DCF3A6F91DFC75E3008A8AF3 /* PaddleReader.hxx in Headers */, DCFF14CE18B0260300A20364 /* EventHandlerSDL2.hxx in Headers */, DC047FEF1A4A6F3600348F0F /* JoystickDialog.hxx in Headers */, CFE3F60E1E84A9A200A8204E /* CartCDFWidget.hxx in Headers */, DCF3A6F01DFC75E3008A8AF3 /* DrawCounterDecodes.hxx in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 2D9173C809BA90380026E9FF /* Stella */ = { isa = PBXNativeTarget; buildConfigurationList = 2D91751609BA90380026E9FF /* Build configuration list for PBXNativeTarget "Stella" */; buildPhases = ( 2D9173C909BA90380026E9FF /* ShellScript */, 2D9173CA09BA90380026E9FF /* Headers */, 2D91746C09BA90380026E9FF /* Resources */, 2D91747309BA90380026E9FF /* Sources */, 2D91750E09BA90380026E9FF /* Frameworks */, 2D91751309BA90380026E9FF /* CopyFiles */, DCCC0C9609C354660088BFF1 /* CopyFiles */, ); buildRules = ( DC5EE7DF14F7C32D001C628C /* PBXBuildRule */, DC5EE7E014F7C32D001C628C /* PBXBuildRule */, 2D91751B09BA90380026E9FF /* PBXBuildRule */, ); dependencies = ( ); name = Stella; productInstallPath = "$(HOME)/Applications"; productName = "«PROJECTNAME»"; productReference = DCBA710010DED62E0077193B /* Stella.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 29B97313FDCFA39411CA2CEA /* Project object */ = { isa = PBXProject; attributes = { LastUpgradeCheck = 0830; ORGANIZATIONNAME = "Stella-emu"; }; buildConfigurationList = 2D91752109BA903B0026E9FF /* Build configuration list for PBXProject "stella" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( English, Japanese, French, German, ); mainGroup = 29B97314FDCFA39411CA2CEA /* Stella */; projectDirPath = ""; projectRoot = ""; targets = ( 2D9173C809BA90380026E9FF /* Stella */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 2D91746C09BA90380026E9FF /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 2D91746E09BA90380026E9FF /* SDLMain.nib in Resources */, 55FE2A501EE4880500078ADE /* InfoPlist.strings in Resources */, 2D91746F09BA90380026E9FF /* Stella.icns in Resources */, 2D91747009BA90380026E9FF /* Credits.html in Resources */, 2D91747109BA90380026E9FF /* docs in Resources */, 2D91747209BA90380026E9FF /* AboutBox.nib in Resources */, 2DEFB40C09C3386F00754289 /* Cart.icns in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ 2D9173C909BA90380026E9FF /* ShellScript */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "m4 ../emucore/M6502.m4 > M6502.ins\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 2D91747309BA90380026E9FF /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( E0406FB61F81A85400A82AE0 /* AbstractFrameManager.cxx in Sources */, E0406FB81F81A85400A82AE0 /* FrameManager.cxx in Sources */, 2D91747409BA90380026E9FF /* SDLMain.m in Sources */, 2D91747509BA90380026E9FF /* Booster.cxx in Sources */, DC3EE8671E2C0E6D00905161 /* inftrees.c in Sources */, 2D91747609BA90380026E9FF /* Cart.cxx in Sources */, 2D91747709BA90380026E9FF /* Cart2K.cxx in Sources */, 2D91747809BA90380026E9FF /* Cart3F.cxx in Sources */, 2D91747909BA90380026E9FF /* Cart4K.cxx in Sources */, 2D91747A09BA90380026E9FF /* CartAR.cxx in Sources */, 2D91747B09BA90380026E9FF /* CartCV.cxx in Sources */, DC5ACB5E1FBFCEB800A213FD /* CartDebugWidget.cxx in Sources */, DCF3A6FC1DFC75E3008A8AF3 /* Playfield.cxx in Sources */, 2D91747C09BA90380026E9FF /* CartDPC.cxx in Sources */, 2D91747D09BA90380026E9FF /* CartE0.cxx in Sources */, 2D91747E09BA90380026E9FF /* CartE7.cxx in Sources */, DC9616321F817830008A2206 /* PointingDeviceWidget.cxx in Sources */, 2D91747F09BA90380026E9FF /* CartF4.cxx in Sources */, 2D91748009BA90380026E9FF /* CartF4SC.cxx in Sources */, 2D91748109BA90380026E9FF /* CartF6.cxx in Sources */, 2D91748209BA90380026E9FF /* CartF6SC.cxx in Sources */, 2D91748309BA90380026E9FF /* CartF8.cxx in Sources */, 2D91748409BA90380026E9FF /* CartF8SC.cxx in Sources */, DCF3A6FA1DFC75E3008A8AF3 /* Player.cxx in Sources */, 2D91748609BA90380026E9FF /* CartFE.cxx in Sources */, 2D91748909BA90380026E9FF /* Console.cxx in Sources */, 2D91748A09BA90380026E9FF /* Control.cxx in Sources */, 2D91748C09BA90380026E9FF /* Driving.cxx in Sources */, E0306E101F93E916003DDD52 /* FrameLayoutDetector.cxx in Sources */, 2D91748E09BA90380026E9FF /* Joystick.cxx in Sources */, 2D91748F09BA90380026E9FF /* Keyboard.cxx in Sources */, 2D91749009BA90380026E9FF /* M6532.cxx in Sources */, 2D91749109BA90380026E9FF /* MD5.cxx in Sources */, DC44019E1F1A5D01008C08F6 /* ColorWidget.cxx in Sources */, 2D91749309BA90380026E9FF /* Paddles.cxx in Sources */, 2D91749409BA90380026E9FF /* Props.cxx in Sources */, 2D91749509BA90380026E9FF /* PropsSet.cxx in Sources */, 2D91749709BA90380026E9FF /* Serializer.cxx in Sources */, 2D91749809BA90380026E9FF /* Switches.cxx in Sources */, 2D9174A109BA90380026E9FF /* EventHandler.cxx in Sources */, 2D9174A209BA90380026E9FF /* FrameBuffer.cxx in Sources */, 2D9174A309BA90380026E9FF /* Settings.cxx in Sources */, 2D9174A409BA90380026E9FF /* SettingsMACOSX.cxx in Sources */, 2D9174A809BA90380026E9FF /* FSNodePOSIX.cxx in Sources */, 2D9174A909BA90380026E9FF /* OSystemMACOSX.cxx in Sources */, 2D9174AA09BA90380026E9FF /* AboutDialog.cxx in Sources */, 2D9174AB09BA90380026E9FF /* AudioDialog.cxx in Sources */, 2D9174AC09BA90380026E9FF /* BrowserDialog.cxx in Sources */, 2D9174AD09BA90380026E9FF /* Dialog.cxx in Sources */, 2D9174AE09BA90380026E9FF /* DialogContainer.cxx in Sources */, 2D9174AF09BA90380026E9FF /* GameInfoDialog.cxx in Sources */, 2D9174B009BA90380026E9FF /* GameList.cxx in Sources */, 2D9174B109BA90380026E9FF /* HelpDialog.cxx in Sources */, 2D9174B209BA90380026E9FF /* Launcher.cxx in Sources */, 2D9174B309BA90380026E9FF /* LauncherDialog.cxx in Sources */, 2D9174B509BA90380026E9FF /* ListWidget.cxx in Sources */, 2D9174B609BA90380026E9FF /* Menu.cxx in Sources */, DC5E473B19EC9A14000E45DF /* EventJoyHandler.cxx in Sources */, CFE3F60D1E84A9A200A8204E /* CartCDFWidget.cxx in Sources */, 2D9174B709BA90380026E9FF /* OptionsDialog.cxx in Sources */, 2D9174B809BA90380026E9FF /* PopUpWidget.cxx in Sources */, DCBDDE9A1D6A5F0E009DF1E9 /* Cart3EPlusWidget.cxx in Sources */, DCE9158B201543B900960CC0 /* TimeLineWidget.cxx in Sources */, DCE5CDE31BA10024005CD08A /* RiotRamWidget.cxx in Sources */, 2D9174B909BA90380026E9FF /* ProgressDialog.cxx in Sources */, 2D9174BA09BA90380026E9FF /* ScrollBarWidget.cxx in Sources */, 2D9174BB09BA90380026E9FF /* TabWidget.cxx in Sources */, 2D9174BC09BA90380026E9FF /* VideoDialog.cxx in Sources */, DC6A18FC19B3E67A00DEB242 /* CartMDM.cxx in Sources */, 2D9174BD09BA90380026E9FF /* Widget.cxx in Sources */, 2D9174BE09BA90380026E9FF /* CartUA.cxx in Sources */, DC3EE86E1E2C0E6D00905161 /* zutil.c in Sources */, CFE3F60B1E84A9A200A8204E /* CartBUSWidget.cxx in Sources */, DCEC58581E945125002F0246 /* DelayQueueWidget.cxx in Sources */, 2D9174BF09BA90380026E9FF /* FSNode.cxx in Sources */, DCF3A6FE1DFC75E3008A8AF3 /* TIA.cxx in Sources */, 2D9174C009BA90380026E9FF /* OSystem.cxx in Sources */, 2D9174C209BA90380026E9FF /* Preferences.m in Sources */, DC53B6AE1F3622DA00AA6BFB /* PointingDevice.cxx in Sources */, 2D9174C409BA90380026E9FF /* AboutBox.m in Sources */, DC96162C1F817830008A2206 /* AmigaMouseWidget.cxx in Sources */, 2D9174C509BA90380026E9FF /* Font.cxx in Sources */, 2D9174C609BA90380026E9FF /* Debugger.cxx in Sources */, 2D9174C709BA90380026E9FF /* DebuggerParser.cxx in Sources */, 2D9174C809BA90380026E9FF /* EditableWidget.cxx in Sources */, 2D9174C909BA90380026E9FF /* EditTextWidget.cxx in Sources */, 2D9174CC09BA90380026E9FF /* TIADebug.cxx in Sources */, 2D9174CD09BA90380026E9FF /* YaccParser.cxx in Sources */, DC6A18F819B3E65500DEB242 /* CartMDMWidget.cxx in Sources */, DC62E6491960E87B007AEF05 /* SaveKeyWidget.cxx in Sources */, 2D9174CE09BA90380026E9FF /* Cart3E.cxx in Sources */, 2D9174CF09BA90380026E9FF /* CpuDebug.cxx in Sources */, 2D9174F109BA90380026E9FF /* InputTextDialog.cxx in Sources */, DC74E5C6198AF12700F37E36 /* CartDASHWidget.cxx in Sources */, 2D9174F209BA90380026E9FF /* CheckListWidget.cxx in Sources */, 2D9174F309BA90380026E9FF /* StringListWidget.cxx in Sources */, 2D9174F409BA90380026E9FF /* CommandDialog.cxx in Sources */, DC2B85E71EF5EF2300379EB9 /* AtariNTSC.cxx in Sources */, 2D9174F509BA90380026E9FF /* CommandMenu.cxx in Sources */, 2D9174F709BA90380026E9FF /* CpuWidget.cxx in Sources */, 2D9174F809BA90380026E9FF /* DataGridOpsWidget.cxx in Sources */, 2D9174F909BA90380026E9FF /* DataGridWidget.cxx in Sources */, 2D9174FA09BA90380026E9FF /* DebuggerDialog.cxx in Sources */, DCF3A6E91DFC75E3008A8AF3 /* Ball.cxx in Sources */, 2D9174FB09BA90380026E9FF /* PromptWidget.cxx in Sources */, 2D9174FC09BA90380026E9FF /* RamWidget.cxx in Sources */, DC2AADAE194F389C0026C7A4 /* CartDASH.cxx in Sources */, 2D9174FD09BA90380026E9FF /* RomListWidget.cxx in Sources */, DCF3A6F81DFC75E3008A8AF3 /* PaddleReader.cxx in Sources */, 2D9174FE09BA90380026E9FF /* RomWidget.cxx in Sources */, DCA82C731FEB4E780059340F /* TimeMachineDialog.cxx in Sources */, 2D9174FF09BA90380026E9FF /* TiaInfoWidget.cxx in Sources */, 2D91750009BA90380026E9FF /* TiaOutputWidget.cxx in Sources */, 2D91750109BA90380026E9FF /* TiaWidget.cxx in Sources */, DC73BD891915E5E3003FAFAD /* FBSurface.cxx in Sources */, 2D91750209BA90380026E9FF /* ToggleBitWidget.cxx in Sources */, 2D91750309BA90380026E9FF /* TogglePixelWidget.cxx in Sources */, 2D91750409BA90380026E9FF /* ToggleWidget.cxx in Sources */, 2D91750609BA90380026E9FF /* TiaZoomWidget.cxx in Sources */, CFE3F6131E84A9CE00A8204E /* CartBUS.cxx in Sources */, DC71EA9D1FDA06D2008827CB /* CartE78K.cxx in Sources */, DC73BD851915E5B1003FAFAD /* FBSurfaceSDL2.cxx in Sources */, DCDDEAC41F5DBF0400C67366 /* RewindManager.cxx in Sources */, 2D91750709BA90380026E9FF /* TIASnd.cxx in Sources */, DC71EA9F1FDA06D2008827CB /* CartMNetwork.cxx in Sources */, 2D91750809BA90380026E9FF /* AudioWidget.cxx in Sources */, 2D91750B09BA90380026E9FF /* EventMappingWidget.cxx in Sources */, 2D91750C09BA90380026E9FF /* InputDialog.cxx in Sources */, DC47455509C34BFA00EDDA3A /* BankRomCheat.cxx in Sources */, DC47455809C34BFA00EDDA3A /* CheatCodeDialog.cxx in Sources */, DC47455A09C34BFA00EDDA3A /* CheatManager.cxx in Sources */, DC47455C09C34BFA00EDDA3A /* CheetahCheat.cxx in Sources */, DC62E6471960E87B007AEF05 /* AtariVoxWidget.cxx in Sources */, DCACBAD41C54298300703A9B /* CartCVPlus.cxx in Sources */, DC47455E09C34BFA00EDDA3A /* RamCheat.cxx in Sources */, DCD56D380B247D920092F9F8 /* Cart4A50.cxx in Sources */, DC96162E1F817830008A2206 /* AtariMouseWidget.cxx in Sources */, DC3EE85E1E2C0E6D00905161 /* gzlib.c in Sources */, DC8078EA0B4BD697005E9305 /* UIDialog.cxx in Sources */, DCEECE560B5E5E540021D754 /* Cart0840.cxx in Sources */, DC3EE8571E2C0E6D00905161 /* compress.c in Sources */, DCE3BBF90C95CEDC00A671DF /* RomInfoWidget.cxx in Sources */, DC0984850D3985160073C852 /* CartSB.cxx in Sources */, DC3EE8651E2C0E6D00905161 /* inflate.c in Sources */, DC6D39871A3CE65000171E71 /* CartWDWidget.cxx in Sources */, DCA23AE90D75B22500F77B33 /* CartX07.cxx in Sources */, DC3EE8691E2C0E6D00905161 /* trees.c in Sources */, DC4613670D92C03600D8DAB9 /* RomAuditDialog.cxx in Sources */, DC487FB60DA5350900E12499 /* AtariVox.cxx in Sources */, DC11F78D0DB36933003B505E /* MT24LC256.cxx in Sources */, DC1FC18A0DB3B2C7009B3DF7 /* SerialPortMACOSX.cxx in Sources */, DCA00FF70DBABCAD00C3823D /* RiotDebug.cxx in Sources */, DC047FEE1A4A6F3600348F0F /* JoystickDialog.cxx in Sources */, DC4AC6EF0DC8DACB00CD3AD2 /* RiotWidget.cxx in Sources */, DC71EAA51FDA070D008827CB /* CartE78KWidget.cxx in Sources */, DC4AC6F30DC8DAEF00CD3AD2 /* SaveKey.cxx in Sources */, DC173F760E2CAC1E00320F94 /* ContextMenu.cxx in Sources */, DC2AADB4194F390F0026C7A4 /* CartRamWidget.cxx in Sources */, DC0DF8690F0DAAF500B0F1F3 /* GlobalPropsDialog.cxx in Sources */, DC5D2C600F129B1E004D1660 /* LauncherFilterDialog.cxx in Sources */, DCF3A6EF1DFC75E3008A8AF3 /* DrawCounterDecodes.cxx in Sources */, DC5AAC2C1FCB24DF00C420A6 /* RadioButtonWidget.cxx in Sources */, DC9EA8870F729A36000452B5 /* KidVid.cxx in Sources */, DCF467C20F939A1400B25D7A /* CartEF.cxx in Sources */, DCF467C40F939A1400B25D7A /* CartEFSC.cxx in Sources */, DCF7B0DD10A762FC007A2870 /* CartF0.cxx in Sources */, DCF7B0DF10A762FC007A2870 /* CartFA.cxx in Sources */, DCC527D210B9DA19005E1287 /* M6502.cxx in Sources */, DC3EE86B1E2C0E6D00905161 /* uncompr.c in Sources */, DCC527D610B9DA19005E1287 /* System.cxx in Sources */, DC6B2BA411037FF200F199A7 /* CartDebug.cxx in Sources */, DCB20EC71A0C506C0048F595 /* main.cxx in Sources */, DC6B2BA611037FF200F199A7 /* DiStella.cxx in Sources */, CFE3F6151E84A9CE00A8204E /* CartCDF.cxx in Sources */, DCA82C711FEB4E780059340F /* TimeMachine.cxx in Sources */, DCD3F7C511340AAF00DBA3AE /* Genesis.cxx in Sources */, DCAD60A81152F8BD00BC4184 /* CartDPCPlus.cxx in Sources */, DC5ACB5B1FBFCE8E00A213FD /* DeveloperDialog.cxx in Sources */, DCD6FC7011C281ED005DA767 /* png.c in Sources */, DCD6FC7311C281ED005DA767 /* pngerror.c in Sources */, DCF3A6E71DFC75E3008A8AF3 /* Background.cxx in Sources */, DCD6FC7411C281ED005DA767 /* pngget.c in Sources */, DCD6FC7511C281ED005DA767 /* pngmem.c in Sources */, DCF3A6F51DFC75E3008A8AF3 /* Missile.cxx in Sources */, DCD6FC7611C281ED005DA767 /* pngpread.c in Sources */, DCD6FC7811C281ED005DA767 /* pngread.c in Sources */, DCD6FC7911C281ED005DA767 /* pngrio.c in Sources */, DCD6FC7A11C281ED005DA767 /* pngrtran.c in Sources */, DC3EE85C1E2C0E6D00905161 /* gzclose.c in Sources */, DCD6FC7B11C281ED005DA767 /* pngrutil.c in Sources */, E0306E0F1F93E916003DDD52 /* JitterEmulation.cxx in Sources */, DCD6FC7C11C281ED005DA767 /* pngset.c in Sources */, DCD6FC7E11C281ED005DA767 /* pngtrans.c in Sources */, DCD6FC7F11C281ED005DA767 /* pngwio.c in Sources */, DCD6FC8011C281ED005DA767 /* pngwrite.c in Sources */, DC3EE8621E2C0E6D00905161 /* inffast.c in Sources */, DCD6FC8111C281ED005DA767 /* pngwtran.c in Sources */, DCD6FC8211C281ED005DA767 /* pngwutil.c in Sources */, DCD6FC9311C28C6F005DA767 /* PNGLibrary.cxx in Sources */, DC98F35611F5B56200AA520F /* MessageBox.cxx in Sources */, DC9616301F817830008A2206 /* FlashWidget.cxx in Sources */, DCFFE59D12100E1400DFA000 /* ComboDialog.cxx in Sources */, DCD2839812E39F1200A808DC /* Thumbulator.cxx in Sources */, DC6C726213CDEA0A008A5975 /* LoggerDialog.cxx in Sources */, DC8C1BAD14B25DE7006440EE /* CartCM.cxx in Sources */, DCDDEAC61F5DBF0400C67366 /* StateManager.cxx in Sources */, DC8C1BAF14B25DE7006440EE /* CompuMate.cxx in Sources */, DC8C1BB114B25DE7006440EE /* MindLink.cxx in Sources */, DCCF47DF14B60DEE00814FAB /* JoystickWidget.cxx in Sources */, DCCF49B714B7544A00814FAB /* PaddleWidget.cxx in Sources */, DCCF4AD114B7E6C300814FAB /* BoosterWidget.cxx in Sources */, DCCF4ADC14B9433100814FAB /* GenesisWidget.cxx in Sources */, DCCF4B0214BA27EB00814FAB /* DrivingWidget.cxx in Sources */, DCCF4B0414BA27EB00814FAB /* KeyboardWidget.cxx in Sources */, DC36D2C814CAFAB0007DC821 /* CartFA2.cxx in Sources */, DC56FCDE14CCCC4900A31CC3 /* MouseControl.cxx in Sources */, DC3EE8611E2C0E6D00905161 /* infback.c in Sources */, DC5EE7C214F7C165001C628C /* NTSCFilter.cxx in Sources */, DCF3A6F31DFC75E3008A8AF3 /* LatchedInput.cxx in Sources */, DC67270B1556F4860023653B /* CartCTY.cxx in Sources */, DCE395F016CB0B5F008DB1E5 /* FSNodeZIP.cxx in Sources */, E0306E0C1F93E916003DDD52 /* YStartDetector.cxx in Sources */, DCE395F216CB0B5F008DB1E5 /* ZipHandler.cxx in Sources */, DCAAE5D31715887B0080BB82 /* Cart2KWidget.cxx in Sources */, DCAAE5D51715887B0080BB82 /* Cart3FWidget.cxx in Sources */, DC3EE8601E2C0E6D00905161 /* gzwrite.c in Sources */, DCAAE5D71715887B0080BB82 /* Cart4KWidget.cxx in Sources */, DCDA03B01A2009BB00711920 /* CartWD.cxx in Sources */, DCAAE5D91715887B0080BB82 /* Cart0840Widget.cxx in Sources */, DCAAE5DB1715887B0080BB82 /* CartCVWidget.cxx in Sources */, DCAAE5DE1715887B0080BB82 /* CartEFSCWidget.cxx in Sources */, DCAAE5E01715887B0080BB82 /* CartEFWidget.cxx in Sources */, DCAAE5E21715887B0080BB82 /* CartF0Widget.cxx in Sources */, DCB2ECAF1F0AECA3009738A6 /* CartDetector.cxx in Sources */, DCAAE5E41715887B0080BB82 /* CartF4SCWidget.cxx in Sources */, DC71EAA71FDA070D008827CB /* CartMNetworkWidget.cxx in Sources */, DC2AADB0194F389C0026C7A4 /* TIASurface.cxx in Sources */, DCBDDE9E1D6A5F2F009DF1E9 /* Cart3EPlus.cxx in Sources */, DCAAE5E61715887B0080BB82 /* CartF4Widget.cxx in Sources */, DCAAE5E81715887B0080BB82 /* CartF6SCWidget.cxx in Sources */, DCAAE5EA1715887B0080BB82 /* CartF6Widget.cxx in Sources */, DCAAE5EC1715887B0080BB82 /* CartF8SCWidget.cxx in Sources */, DCAAE5EE1715887B0080BB82 /* CartF8Widget.cxx in Sources */, DCAAE5F01715887B0080BB82 /* CartFAWidget.cxx in Sources */, DCAAE5F21715887B0080BB82 /* CartUAWidget.cxx in Sources */, DC676A411729A0B000E4E73D /* Cart3EWidget.cxx in Sources */, DC676A431729A0B000E4E73D /* Cart4A50Widget.cxx in Sources */, DC3EE85A1E2C0E6D00905161 /* deflate.c in Sources */, DC676A451729A0B000E4E73D /* CartARWidget.cxx in Sources */, DC3EE85F1E2C0E6D00905161 /* gzread.c in Sources */, DC676A471729A0B000E4E73D /* CartCMWidget.cxx in Sources */, DC676A491729A0B000E4E73D /* CartCTYWidget.cxx in Sources */, DC676A4B1729A0B000E4E73D /* CartDPCPlusWidget.cxx in Sources */, DC676A4D1729A0B000E4E73D /* CartDPCWidget.cxx in Sources */, DC676A4F1729A0B000E4E73D /* CartE0Widget.cxx in Sources */, DC676A511729A0B000E4E73D /* CartE7Widget.cxx in Sources */, DC676A531729A0B000E4E73D /* CartFA2Widget.cxx in Sources */, DC676A551729A0B000E4E73D /* CartFEWidget.cxx in Sources */, DC676A591729A0B000E4E73D /* CartSBWidget.cxx in Sources */, DC676A5B1729A0B000E4E73D /* CartX07Widget.cxx in Sources */, DC7A24DF173B1DBC00B20FE9 /* FileListWidget.cxx in Sources */, DC13B53F176FF2F500B8B4BB /* RomListSettings.cxx in Sources */, DCDE17FA17724E5D00EB1AC6 /* ConfigPathDialog.cxx in Sources */, DC3EE8581E2C0E6D00905161 /* crc32.c in Sources */, DCDE17FC17724E5D00EB1AC6 /* SnapshotDialog.cxx in Sources */, DC79F81217A88D9E00288B91 /* Base.cxx in Sources */, DCAACAF6188D631500A4D282 /* Cart4KSC.cxx in Sources */, DC9616341F817830008A2206 /* TrakBallWidget.cxx in Sources */, DCAACAF8188D631500A4D282 /* CartBF.cxx in Sources */, DCAACAFA188D631500A4D282 /* CartBFSC.cxx in Sources */, DCAACAFC188D631500A4D282 /* CartDF.cxx in Sources */, DCAACAFE188D631500A4D282 /* CartDFSC.cxx in Sources */, DCAACB0E188D636F00A4D282 /* Cart4KSCWidget.cxx in Sources */, DCACBAD01C54296300703A9B /* CartCVPlusWidget.cxx in Sources */, DCAACB10188D636F00A4D282 /* CartBFSCWidget.cxx in Sources */, DCAACB12188D636F00A4D282 /* CartBFWidget.cxx in Sources */, DCAACB14188D636F00A4D282 /* CartDFSCWidget.cxx in Sources */, DCAACB16188D636F00A4D282 /* CartDFWidget.cxx in Sources */, DC368F5618A2FB710084199C /* FrameBufferSDL2.cxx in Sources */, DC368F5818A2FB710084199C /* SoundSDL2.cxx in Sources */, DCFF14CD18B0260300A20364 /* EventHandlerSDL2.cxx in Sources */, DC3EE8561E2C0E6D00905161 /* adler32.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 55FE2A3C1EE487CA00078ADE /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 55FE2A3D1EE487CA00078ADE /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 2D91751709BA90380026E9FF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", "$(LOCAL_LIBRARY_DIR)/Frameworks", ); GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_GETTIMEOFDAY, CHEATCODE_SUPPORT, DEBUGGER_SUPPORT, JOYSTICK_SUPPORT, SOUND_SUPPORT, WINDOWED_SUPPORT, BSPF_MAC_OSX, MAC_OSX, ); HEADER_SEARCH_PATHS = ( /Library/Frameworks/SDL2.framework/Headers, ../cheat, ../common, ../common/tv_filters, ../debugger, ../debugger/gui, ../emucore, ../gui, ../yacc, ../emucore/tia, ., ); INFOPLIST_FILE = "Info-Stella.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = "$(LIBRARY_SEARCH_PATHS)"; OTHER_CFLAGS = ""; OTHER_LDFLAGS = "-lz"; PRODUCT_BUNDLE_IDENTIFIER = "Stella-emu"; PRODUCT_NAME = Stella; SECTORDER_FLAGS = ""; WARNING_CFLAGS = ( "-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", ); WRAPPER_EXTENSION = app; }; name = Debug; }; 2D91751809BA90380026E9FF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", "$(LOCAL_LIBRARY_DIR)/Frameworks", ); GCC_ENABLE_FIX_AND_CONTINUE = NO; GCC_GENERATE_DEBUGGING_SYMBOLS = NO; GCC_OPTIMIZATION_LEVEL = 3; GCC_PREPROCESSOR_DEFINITIONS = ( HAVE_GETTIMEOFDAY, CHEATCODE_SUPPORT, DEBUGGER_SUPPORT, JOYSTICK_SUPPORT, SOUND_SUPPORT, WINDOWED_SUPPORT, BSPF_MAC_OSX, MAC_OSX, ); HEADER_SEARCH_PATHS = ( /Library/Frameworks/SDL2.framework/Headers, ../cheat, ../common, ../common/tv_filters, ../debugger, ../debugger/gui, ../emucore, ../gui, ../yacc, ../emucore/tia, ., ); INFOPLIST_FILE = "Info-Stella.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = "$(LIBRARY_SEARCH_PATHS)"; OTHER_CFLAGS = ""; OTHER_LDFLAGS = "-lz"; PRODUCT_BUNDLE_IDENTIFIER = "Stella-emu"; PRODUCT_NAME = Stella; SECTORDER_FLAGS = ""; WARNING_CFLAGS = ( "-Wmost", "-Wno-four-char-constants", "-Wno-unknown-pragmas", ); WRAPPER_EXTENSION = app; }; name = Release; }; 2D91752209BA903B0026E9FF /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_VERSION = ""; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; VALID_ARCHS = x86_64; WARNING_CFLAGS = "-Wall"; }; name = Debug; }; 2D91752309BA903B0026E9FF /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "c++14"; CLANG_CXX_LIBRARY = "libc++"; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = NO; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = ( ., "$(HOME)/Library/Frameworks", ); GCC_ENABLE_CPP_RTTI = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 3; GCC_VERSION = ""; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INSTALL_PATH = "@rpath"; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.7; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; VALID_ARCHS = x86_64; WARNING_CFLAGS = "-Wall"; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 2D91751609BA90380026E9FF /* Build configuration list for PBXNativeTarget "Stella" */ = { isa = XCConfigurationList; buildConfigurations = ( 2D91751709BA90380026E9FF /* Debug */, 2D91751809BA90380026E9FF /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 2D91752109BA903B0026E9FF /* Build configuration list for PBXProject "stella" */ = { isa = XCConfigurationList; buildConfigurations = ( 2D91752209BA903B0026E9FF /* Debug */, 2D91752309BA903B0026E9FF /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; } stella-5.1.1/src/macosx/template.dmg.gz000066400000000000000000003473361324334165500200340ustar00rootroot00000000000000 ^Ktemplate.dmgMl𷻶@>LpC m>R>'H)䋈&Ѐ B8UVB=TBUBq( SPj7o׻q:[=zμ͆,Wc{BP7oټ%zzx\ʘB}ªqRbX\at?ߴi\JaAl=@LtWzcqv/xy)}rhX_lC#\ BɥN׫W.k'lr0HTP荓bS 0P ϶B8)tWL4S~==o Op<v}RW67fWGB%&±9 {p4%gev|~|Lȷou[:烞absMGa_cS/n):^Z[Q5q:Z90[ bkcjթƖYJɘ^^²:@%{UXw)w:T g5ΞMyW]9\RyotnI}iYWU&b]Jګ&SO;/RoCnkouO5[¦yqOG3]Pޛy6,uX%Wngq >Lݚ츌jA3cl>-B|~ez{1&/"\|v.lLd|jwǜ96#t-dGr.sGQ'jagu8ON5,\ΕxfS>P.__=w`X[ޫۖC?Q\ԋ:\6]sMg##7,bz)mm\Xr嘭}Cv*5)Godu,:?L>lSg֔Թw},#ھWtەG*VPE`\k#V+c ?/<\X߼Qm̬?3fW)śޑ8ߡxF9Wc 3px$ R?k?)s[WLӌ9x]1Y RLa"M Z=OYӝE)_ִ"mЊPŽ>1hZSZU0}d$Yپ-YesKųGrvWE mY:mwR+`dw.,X&ee[Z9Y^[>^+c=[J /6_|Ɨcylr|wbK7 (^wjk.u}U>ʙKmk.| w{Pm]Mޖh>0Wbt~ta3ժ=_Ҷ2o \F{"b۷ԮZsoB/.X3F?7Kjqsm핃^aqǭYVQe݊в_:)oEe#Z\,cWlZg_ݢZ ,@oHy矩WOomW3؃ FPUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUaN*?di$m J@QJR(ݡRB (bHDҤ&)X<)iDR*d,"Z X ")ggsf=ޛ4-E/~/]=9zKM;kfgw7ng͞>~ ׋f,oBU,䟋mղăV4:NN_z֮nE 1'ٵwܸFqQqI鐲eeKmmo8sFN8swh-Y}Ʌ׋::K k}IU;s]?a+?gI{OoҊٶ,ۘ[~1)WQ!Õ"L#,Om -aLgmMF%.Ybw-3i195~T4;ųfrB>q@3 w PX7wt@@7:萳՟~nnjۭԃw;zќ}퐩uւ[8>wG~3͝Y>cN_eYf/7aQ}رVi;3Ә5cib؅Z:Ϟ&O0yt3ԷNiskSaC:3X2化eK[ڻj95]t4Sg&vAc ﷍hZ/:{YK@lcggcbh6n=,aCɭ6>h󷿠c/|/8~/h0y o࠱[}e0}Nk[ˠ(l:mc7.N Ǎϒlm>>؂*p5<};c{uLk˙-S9hlHmfҴ-ָa5C[綟ѐ[njki[69mYNE%n&uv?09탭?@;>&?fl.T No<5Vp kh={yv6:v/s~[Onu̚-zoZ5lkNh6ط65v粴uYxԂO͞h#fOoX|ļN 3;:ӄ$ߓ 5;T9Ssgnt\'s^e\4wts<~Ŕ֙9ozC;w8k?NXpggntы^@eݹ9-mͅM5u4vw 5m>?Wҭ4uZg[^ӿޜήZu7tNy? *$?wF]K-n_?̝yHۦT?'N\?aqcƍPWΘٸ̎?[N߶;cA[sKW[ۻ[Nm:ᠱ/=`{@中B gwu,l?c$_`|oPJÐ0;NkM^8 _{wDzŻw^O1[V Qφ0Ĺ3WknnL[n "pP88LZg9. åwpMv%?  #Cn_¿FQ44DGF ihNtx4/Z DQStj-Z}.:#Z>]}-vtFOE?~{fG{{3 _#ɯ}|ܕ7d_Ƚ>q`b ,'п Ǵk}17e e 泑R G8mgc \IctwxjKqiz-gu+3ᨎduUɥɕɭ%dM䖤$ US'a ;e))N5湰_?\߉/5ׇÔO˻;w`q1wFsajC´ dH~3k0+LIo$hh>z~Co>rNw]84OÓGɱɅɤ ]ca82¸pftu.;a^-mi:w6$Ò'1ذ8OOKǧI31k*Y|&-Z:hm9BU?=lssOJk`fK[[R>*VG!PR|hN78L+O %vrTWrbK'U՞s8a LXth Ks16, +t gTU=aFcvf`fG[GEis|YGgf]hݝmٯ8!,zBR%#iTS9BHK砃ZhoYS_+VcM=-Sr 6jɼM͍v6śoBo/Wi_ kfa9K~IuòƦl!\*MF&/I.iv.`sX_. ks){ZkwL; T% O3epW3m#mJ61c\Op]_>mySr-}Q,+% 5M>ppSN9|7L9aPȒ=9nKfQv_\'p5p{Qi}`yw[K܇ot;]YKvId=\A7z`x(<> pQx20<Ҳ6#Z7<+qVW؝uESSs`eolmoLIɼ$TI'&c^cæLI:.e9}~^ /WOdwYMϚ}q6vvut&˒Kr@KUqҙ|zhH #/´fx+2* IvK>|,3xWɐv8l5t.;s߲xQe]k_ٺc&?ZNʳ~NG޿򎅭Ϛemmk拮rפU?Ï䶺h9g컽-z|tfGgO83K~YgM3y~Y<[6ϙx@6;i ¿?Hk?ӆH,d#C`7sm^Te^43?|$vIVE~/DqTvڨ8*IhHTvb>7i#r#pW2.&'nΥ1,*`lb2hD*NS0h5Ѩ40?ϮkFi&uvXgzw&_;Wo~kNa޷ɘdR>ɏD\n%{ί[\S^>}<+D'QvwE4.>47L5AS uer벱m l\vZCm-ҙZƔh^k[N<9|iZ;&3 z4)7OajA!ifƜ$'&S[kь2:B>Uص!l3o5D >ՃCs=">;0ZrMtdtTԐIM>uMtttLtl23Nі6 ђ4Iis;aYG/uaUc}_H;esԜ+^Zzwԡ3zOiQ0w-3’|_qH;~74ߣ0I%c/ \uF]8:F_54=kr6~apD+a[dQŝ)n揓G---]W /ytI:4Z].֥UEWGߊ֧;rmt]t}1G4v" <+mxi>.7-gKGrKlO˸&0U>WGYg+IyͲݿ Y[ru_oMq+V,O9?U/ʒƽlHnzݒast{鴘sɤڍ]~V{IP?;m%S&KSS]======|&iLNN%=r!N&l  sOh;fWx)Q)k:яg'I艞6χJ1=̦ OooM@8ʒ׎o~E/F/E/:wH;%69=iM.M\{ߛ^^&z-z=U' a{lY>k_fǺ'6;cЛoG\37<-m߄F.1z74vt kxPt*>BrvUM<}"_]& }lƻ3'TZiu燣2.J NJpt<, Tڸ,iY[,#/fqEts\>W5tg5vҝ-i gs$8#9kCv[MrfM<`B!s'80x\-9y~%Wӟ]4gƻr4lvHvYn:kg&>ǥdoKQtҤ\GV c{泶?kYqmg?uxxLJ84Y$0!r:݄+^t<17,/|.?o=tƇYxFeٟ[zFۻsaz[wKg{r-6`3wwv<:wLWkGskܴu'nN.US~dܓ^}tғ[o^[d&sG-8|xpv]|X<7Y;qϻ.ҷ1 UfZɹξʹwL+zYVNL OhĴ)$(>z}|ta)<-Ke0 gftsI3'¹l3ǟ[oHg$pqZGF]ȴ'cX:{\O~}v`\F&ø8$lεiNs,2[VuynVŽ/R|~dmd]#9|,N_pfzp#'X^ݟe^_ޒSKi7=4.es兹}?2ǁݘ'9n|K|kxCrud}rMrmr]r};%UT}j}Rupǫ>Vgը?]]d|SuV?]?;;#1;4 eaѰw ҉t8%z:z69*^w=7??hTnE{M,T_ES.:hz̢E-:舢EG5]tlgڊڋ]肢EWTtGE\JѫEoOšxhw*޹#)>xaQŋ)^\Kŗ_Q|]-wo(7?THůQV) %L*^rx1%%JV|伒U%_*rE%\Wrw%l*yX?SɟJG֕~t\i3Jg)=tAϕ(biOWJ/.Jo*tcJ)}ҷJyH<|Cv2~Ȕ!3r!Y9!\;!7 i+CClHYMe/;젲ef*SvXeG-(;ܲ-즲;*PvOٽem,{쑲ʞ,{lso~W({eRoe*ϲ? C㡻 =h財zg=lȰ]:iX]0l>lð{;a=?a^yT^T^R>|Tw)ߵ{O.߯sO(o._Zʿ]~S巔o(|S (wXQSW+>]񹊾+.K*.V|Ɗ+xⱊ'*~T㊟Tw'olxg teÿ>|o rU7 q>__<"1|.#v{sm#q#qۈF<=o刷GzoGnFÈwGqĿUCծiW[5UVͭ:ꈪUGVQSu^ժ/U_V]TuqUU}ƪT}֪۪ꁪޭޥz VT=zZՇU]\}Ji՟zmW?^L+տ)T3S54לRsZgkjkttלQsVMO5_jE5_YWseU5Wly'k~RR͛59|d]G~b#nj7r}G0rȆ:{G0w0|p#Ñ_JGFMuCFM5cԬQKF]2Qwzlˣ~=OF׌5vw=F9zџ=n:G>ig}F?5P;v}j֎X;vjkO=sjW~U_rگ^]{[wnk7>THj_}7jߪU;?Օ ZW^WY7nd躺}nuP7nVC-\]W3ή;nEzΫ[U/]P;PwOݽum{Ꞩauꞩ{ns u?{W^{_սSw\v(ߡr>Rzwl<;Wnli\ShZoozooYǰju~w'ZOB/FkzO[M(t7eޡ7T-_+mfuW Rs1hR֬+YINWj쯆]jժtaipIhHs>tul\_ߗe{ۋoz.ſpo~*I__EO4yܸƍ[}U٣iZ N_vkl-%]}-Z6B*}_ͥݕȚu0qrӉi;?~/=\HshL;s9N썚­ѭ⾴RZ[[Ӡ[V~cp}!d].\r{78I{S'ަ{[},ǭ,#zM˲2p3&(+//a͊b]־n-O9C>qw}w4ꆐӗrt\S|޼rz^W1l%\X([Z"p)dOxol̕\BA-w{ O܄5s7o.-y;s}}YG |m׾쓬DQr#im/v{(F?(w\Mܮ Ml_*VQsE.6gKΞW?OoɴiMMM=5#M7!ؖ+x=a.?DG#rO;7Ƅ?[t) _VI]y5![M"Eev)C. Pز|{5[MR+{qu~Vt8>!+_:0, ZXޡ]]ٴ0'yM^_O=nׯ[l4c'}ᢷz oCz^Peeyl{7~u|a_Ig|~Ukr1.+ >ߴsY{˾rß# k?0\m[k/{w$WfǗ^Jz/Xޖۏ|ş]xa^@mUO7GW\tQϠu[bz~Sϴe>=vߝ7|k}+vk~{կoWK~wt%vKH};{~ICWťŗӓwPwy$o|mFa~?|7_˫EV^N|ypdw* X/Ƙ3ϒD)l"FF]Vewh8[X]&/R* 5j4QXboޤffA+{]s{;AwڥN޿ccۃ6f)[EtOߵy(HRˏ.%}zG` R=Sib(IEػwy=n\.f͛wEnaegKaDOPo\>߶YJ}Fۦo6o޶%V箣@dL6I@ޝ[._yÇk.9~p`{??"2om0pA`OOKNJ;x`?E<2*wu4ϓ']3N8yBzDF4@:p(-V9\# ?fqofr_Ϝ:q4-59!>9_+b߻O{Y~Ο=u .II(8C'_5_nQ R p!=uhX*(U9ُ9v[t ߄bQB8q #-)Xqӛ'~I޷Dz nӋ۪`W~p̉X()((,,8ٽM?u淃'nYPRܤWVbw2E*W}JS-4CvOuEEe8E(iާY7n?q!g~_`L2kuPqtѪˆcs>'o-iBgaŻrD¬*&XEױ GOŋ=8O3ASjC=dzG.&p!\k'Tս~ W9w,)dRܩ3I΀Ŝc7'TK0gJKKaA_Sħ9'·_.@{MewDZHVUQ,tu559S)ny+|vo3]?:%%ဗ<=a3 )'O>OX-8uQm*҈vqIXZ40镔-.5잔Cu'M//S~PRqi;&g>rL80& 򯨈K]Nx }ԤۓR2wS=͜&cU'Lgѐ%E9w|0S{~!cOH@ @>c"*"eKjF7ɩ ;|r `S󋋊 s܋G|aHYT/_6JKH⅍QgN++ײsjaB1!e%]>}xC|,뇴G"+ByX$-!YE0MU`ՕҊ!e_:w2m{⧔K=S&RJWz'\+Anг:]]qEys ;b>p8>i{>/V3kE~RY8tU:UUaC+J{ON0{g&ŧ$-+OON<~n5˾;DZ*eb6ҡbPZ9,=[P,ƍ]JEӓRصaÚݗstTDꪂ!T2JV9nv:ztۑ+RW%'%\Jڶ~Skydc& +"+ݒ qwۉS\͘nq DDJbrb7mYw VI (;=[]5~Ƣ/8^¹sܜ]OܟI8_%'IW*OUHOz#Ʈz^51)?]) - ,bɫQQ$̗_KÕ1gS֟zX+ ^#_LV5,΅x-E=9%ObR¯;2sJ˕U`C9].^Te?3?qZh1}e#q>9Y~3< P X4^^Yu*®(#K>#s.ڡ+bS!Fϟ{_FB )(gb]|4lR\|aIHPWXҨH(e972~ŵ :(FZP;S'zL8IKt( JbO ~̚xNaiȤ)O\waQp`lz]RU*y6>fnyeY8"i9:88lU’Q/=5oUUeY*++J.\kH:9ڞxZVJ%ktkjVeedAEI)Rݩ.dS锖PV9];Oӭ_+ ~V&:1LG}';:y\ N2HOLMVu:f; @ZVQpt2i%BZF]GWV޻3w + y9 jT&}j=/ rDײkjjWCʣ_8 ѕV趨hSm$ݶZ1FCp k6_8OY)uuTkSBZTbPG(vEUph ٔL"USátUt[(SA:v}]=Y ԳNiff Yˮ UFqkjpjT#>CԒ ή&yzVYgɳ#L.JP)S#w&mfe٣5fFоIZ^.%J舺Mvf=Ss qaN/Cu^,r(jD-(EʄU&GЅd̍h<O %ҢzA,a<.ǓJq|S3KjkK &tzy!SV_h^i B+j0Ț~.$qoT@6 i8Ж$ʥ\vbm-fXW]%q Și;/K\`nVYZKOdx_e:;quHW<zIe1xV׊Z1RGYΊҬ՝eY짔;$ȯb=&!;3zlVV_,ӤQY-t{u(Z+,O> ݁^-!!9=Fa~岵1dv TK6b8pv Iūƌ?y劭AZfZ m6|]tK`f+0H0xɪPI@LPfը)qM¼)%̇Ł_o-v9i+4 y~eu2R+1I(0%덎2/[*QV@l5YsKMA+M>82=wJB?4r(UD+I:IgZ 2\n76N" @i1*Kz?A,X'W*C ~RZR#J) (b0hfJwbVb|Z'A%akےVc?Z1^"9>pIB@qHi$++/!?dxUD4KE ]eNPNNƘoC$+"DyT B$$A, q؂!+v8$O%E{ Y¥cKf:9M^I>eRK(Mo !:˂b 'vJ;1 >A\ٟO|Q/T/+sy~#{5T" 1#-?wH =9pn!$ k_8t9G,ZO 쉃p'C}C|LHabjE6}4F:O6ޑY8S$oPrلqƌ273c%" !YəI[yލ TgIcV_"O/ ILLzX,7J/ q؅#ttoS P,ķ!ȓkU͂|I,z>RxBӖ /&Z ]ƍc5L'! %K>|+1y__P$"%ȯ31#'#(A>/ %\ W'}IDAP= LR \ 54&Oi&.nh`T.;?^y_=J5}~H)k׮D?zwGC)EɇrUjWOࡣr<++k˿rc|Կ`S|xegwvNvΖlYgw*\:Y𖼃{dѹw5QޚN*kr׶Pq>:/UhR_M?t(>':!I~*]^H^ ;d^oZ~O׫BLEh g}dq[YuCSZƣ-^Mf&4ꅐIK8N݄R=Qb3w-{-ȢByqރ߶>1B=z*Nߟ4D̠'B&[u9Nu6GPԋX,H*6KK}٭>B= APd^ݤ{M#oлz [NꕕJ%J!Pqq KLdD,o=$>;;G4O Fz,գw{CP4oף44[@`d Ez+Qb{49ӅTMTvjӻ﶐#E" ,0z!! +YQ7jRCMڱGc=G07b dT^Fyf7}u+J]@ݔuH'\S7adA]6M@lbӀ=jElvѭ١HZt iҪuJRyj&[w㘭*f(D: 4h=Zf!Cmzң]7!}X3,G,,0-ݝ֑8T? !_Ў[ly&LvH+ SW0-|> ΩqS"]2%'T8eld~X,]C }F,}XC'u`v=pxCF0$oUj b ^#[d}k%Ntz-w6QCM{~8ʹۨ3 t`]^?J;@w..o_3 t)'Z'N;@w0:;Ho ~rܮ$o )${c J* oN C^'&J75}{ ѯx>M7l7x-4y{c?zH?zon{o}}whx76ꃷ{U]Z~-_˯kZ~-_˯kZ~-_˯kZ~-_˯k%oߟ jۨG35y߀5Oi>XJlK |'T:iWWWljڀK;3gg2gϜmc}Ag?83Q]kf Ps66ck܂߉sqn;7Zz;E덎5iMkZӚִv\.ΘNvؠsFٙOsmfa9 A6F>z9\# &x8ڜiԃ Ǔ' l6 #dBk)CtV G9q\`,G`G(yeVvb1Tx@< 1L8_(F@<$/>bS.T 6l mZ% kʅ%omlsUT àP$#pPЈ sq^x4#ۻ1Q<%0vODZi<1I\sbs!XAAAfp\iP-5$H,s0KDEqD,DyBĐ< -: Z\Ha8qljÐxy3N> 38*T)* !@9zXmn>SA8 1&Q! Ƥk\ &v44P} yX g'3gc3aslgͲ>o"l0`?5< JPse7vT'g'yXcgػa3ga,w'ζ`ў:LU# 5 GMP.,<䥊``H k> q`jix+"\މ X3Rquh1'c`Sŕı[h(T0.HKK,fٚXU.!t3sA1g.kZӚִ5iOy"#Zpą@x# 1xG' ~6C"_hd9(14 !7p3᷹687lbEF^ ? QE\M4+ft` " $^Ƀ!xl"`*t-<tqK& ފTjMkZӚִ5iMkZӚ;m4ՎϑHp 6 FP'lܝfpea+Gw"b"֍rS;pmh3=ص::s;fpp窨<$ ɋM^ljlWYYpVܓxg柗59b. 7'vQ[k-)Q Ap/pbKa>_}o1E r]xzW~~w Emz+"䶙P 8b"|8om#̠ĸu.NH8|#|ܕ$6?\muq 1hu!ݨ 9H m*.89q$tfCl'k TyT;CNL=]+&ϦB#OБ5zn[sݾ5d=kE|-;;46ܨUXjt .ReMnM FGzOuctM-uu]zĵ|1xm3Q2tj$Vh_FkMkZYO74b!'4hÈq&5& $ċ ؊}vB?Q[\1F%SCy (G9uD3D3.634-{6Fݬ}ӄԮjg'Eڜj]%6r46jxlf_#H\Ϟ#bW!s)q9gHl4=z,|34V4q-h[ AB/Vf/"^gQs: Ba2i*#N}P6(tb !~L)tKnPTAx%Pś FTi(}IzmPL[t@L*>[ㆭF}02GNk w7;sW[gA(J8Rd +Q(Pl,= x882e=}8b_2T㦟HO /CPARm2HEBw6uR}|1v)wwȽ)Eoߚ5}֯da[aҰMd/^ v(Lw; $Jl*#t88K#0xN tL*^Хb6k$ gRLiiI#-_B4"Gȑ/!h䨗: l.<0: nf9@ݩS S -j W76c4ޓGQe{vVM88DA0#:zY (,BD(hH0da!@,)GB؄ e"<'}GTsoUNfPܪ:=ܪ:׵(9xRr+_'։ZX˓YPq%ֿU 9{L׿wNnVCy fP0sdt F ;[W(Gҿ +2lbhw^mBY^:ˈ7Ӳw\t/#1#۫1of1J[I7\.&Iw^?]ٹ CϬ"0W`ket}Bx׺3;ÚWxIZ7ASgI`ĨPnQn+Xpr$y̞[KV~;*O|r7Un #S-#@"5~h}yw|$۫eDelR[.J\[-cTB|$'__/妋ZZWI&9Bj{IM>ZTS''MMr*튕#_f [wysA|ZRhV?B&o'%f1$!le43ߦ2zX0οh@"]QdR@ k IĿ@ ^g!3DֲCp[ۊL ~+O58@r;'_ف|7!nKkyj pUC]\_~ܑcG6`=R_܋+6?p[ 襡Rϡux{ ZgDA6͢qnnJa9 "xAq_Ff0 5AP ZF }Aߊ'H+5{}A˿A)γCM"$ @u4@&)4eOv-_%6D>4ȗ{ 5YdUЛ6 Oaz(yK*L !v`ۂȧ$ZFפ DĴRz (йd1CyL؃aa*"nL#dFE`ZG^t!YgD+N"'Ed@{V1-"Ӟ-8ކELfDc1?aL. 4[R(yd T2ndt5D,c0t-9RdO&2G%5"=_1'D Ӧ ө*!1}|.d;+. &D"2"Yi-y Sd~D$ S GO pM"A'A%87Dv/"9U@ǐVLN&m"!/O"az1֓M>~ ~ ݧ$ӟM)Ej☱ Z~*+o,@nl7ۍvc[L;/BBT{m4ZM W|VWnvik5Fy]{TӾ;iszvu>ѴK2.iZ#}02Tܢmzz CGu?Uݹ6;Nsr41xmGUK~ӏ]u:f%}:{{ @IBPǻ֡ D'kTP3s;$t(י.ܼ"~ݴqP9{ŇEѦ]珝{yI;QYgO646.^!ae-Nۊ^;SsYYo@?}{//YeGPrxi-(7ێI='W-lA {b[CCXS4n3J0ێ9]=.<Ξ6FԳm#Ѱ7M>؝5췮,Ǐܹ<|)My_ZVMs՝~[ -35'k~J {(59ٳPTUȝbD;уo[GnC)E{1FD(rȫs<$[O01 #Stabbw#,w_ @MOUXk(^RUi;WUH6Oa!У=]}ΐ_KVB }UJ;4-B ŕIKKbpڲJ˰a#.,<)xeۧ=xt[>cٓEO>1B [>zUsJL4it@WI/Y=sNM2y0 Nwtj9朲Ξ95gA񊢙oJ|s1`TdAmDQee ű>ԔSEG.)+YWh Ox4= KXiIy 61({}oxG ~s اxMif] 8}hB# J*2`oH!d0"Kr8À!/0>> i]R1A))qQYDF &a{=ALN@ "),<@k/riiZڵ[W؆Oe? QkyVVoMm(HNr8'v-Pkmގ;ᑼ5V-dr"ʴlcldzxL@ky;C6wBkbaئy A<ykb\^ogf'!ab♘+9d>obex5Pq1h OS@1x/Gf#K%2@GuY6 rZ4fN{216$G{q^g;@ @Nt:NTӷf4>m!ާwde>?F2sŹ ^lU̅#$N<f6bWY@wG' nv:Q w6Ng鱥5|n>W ΣNaNO7#K7;y%E!%%zq M k\lYg3]H-f2LtvJnc)Y/L&`0w7ͭ&AN-΂.>! R,z"^oِ#d6XocEHC#~!-ևLn=igdMhxGt6Fba Btr lVND_p@%Qt1ٚWWP 3ct$dfl6kpm)v7_lLocbu"_]/,IN] X].VؠZ-|PK:b+!$wHFx[sJ` ג *:Z"P 2%cMnhb5&9wiaգPؚ+KNU_uO)evB]fW=WE0 ܺ PN{|U2GbȋmU۔ת,LB^;]Ζd˨Sq*JxlQҡػA?.2$ϑ &gܵ!Xabk-7-v炬́3{FzԹ.ԜUź35 ._?XslYPMo?p/G={"g~B1%y{l_zWRDna;KUw)*+V..-&XbL%ys~1F=!wfΜ9޳, J%|4u6u N0sҶ&@;.FFkl@Ӿ 2**yQ&kk= 둪Bf@g}Qт(B)P3ilm;6sJJXftwKϭJJqp9mHչIsY:h"ۅ2UD:5KZvol=Ye%&W!zZڻ4K{ y|.3B '+/h>^Z!>SX8e Z9EzjȖ--XPuJ[j}DpӪKEA+Ԉ%{[[[zVɼvP[eE#V czQYҸbXvQ‚CkVdKrNܼ[8z2qǢI۩kTĖ JNg]ͶI'{umMN[.4l\) T3ϞTԜdE[⃇vVl]*KNHL_0֔YZ'y-b|iӶPL+)>&lAYmˮGcsPabnr|LĬtT13&%3bk V|& '%Hkee1I 6CE͒}Keh9^9=)g kaݖC#bk!&Ytb)a`DDEF1$!rAH YzDI.@m"mq=E&E{H!H&|1YcVlʸ#lh&H%kLu Bk}|}Gv",??_?z" ,v#'}"C$@0.L nj V ,ޖ) ?sK!v1wM22 Wm![2>fOkd?2Q^iR.(eg0n7N`OtWVelgT掳!ʕ ASk<&Jآ쌜c .ʪi[syLB@hK]s*WKen>R%L2&u QjJ2Y;C'; pyB.?Y$%d%85\v Qo J9-i~pOgd0cs}}F@kr O𴧮EC crx -f s2ao b:" i. ^.V "JBx߆SxjD&iTB9Q*ʡ(xwȄF!SdPi0!6`~%x[f VDQ~wH$p,ܯD\-V[ | S RyD<*C4B@u2"R HY!БdwD2T4Fd2_ʗM&ɥ*"I1H2څ4W"m;\Y"LF zS7"4""8oE@܏US}MHGWNS\kZ7n)B:o| ȇ~Z ܢQ{zZ*ug\'~҃?ߏ\'kbuNOtx-{[f*\u䣏%YgܑZL ԋ5 m.~Ww2 5NkS[{JcuS&?7\S{޷q?/=9}f 2ߓ;y o"r]}7ї!%a%50Ҏ=mFlXG2ƦlߜIl3,uWor;o)[:r+L'&n?sϸ'IJK5ڗ.o̼)D3;~/ i{HvI&xHci.`-ONpL@)vGw%aArEیS~ d^si?DRR}:-ٺqtCY)acA E`+>rYƁuR+jT"%}8sҥݢgN^zx2p/m<{Bnc^p 隷o:zȾ{|z`u d!:x\W݇ŋsjtݵ}N^h.]yp遃'/4t>T}ȥ8hjbˁ×;z{NupzoVdxt\ +hm1p~Po-#bcF_FZ `sKwWWggc}}]ِ#%&P zϝ4ua[KkN ƒ-Ύ׎j>~seBHTLll\lTlydo=+iw:\>+#2DSb#+E֊a ]=Ǻ׵mK;v ,-Nq$Au/mTooId⺵o pZG~OQqhPG Ӕq̌vw?6NO?9&minܱܿ;dMWN,ڙ<;=59%aƧ67Ivb&U:pȎm筑K!Gn H(Xx4<9{#R,5\>sf^-žլ=],/ @{> pV l{i%RQUIj{ziqN/Q۝k,)p9 B&3>D~sqJCP$jn=']& mlzSZlEqaQ>`a6a;;d;Vic}#}x?[=2H,:;S 4_.*_bi%L.?+bH;rWM*554;K>lַͪz{s#PƎ뗪JJ.[ee['i$fIDT o$tX.O&Ώ[ #gyˊ " S ȇl5#74Igۏf.m[OoEO1HyܞV//.ZZ$]$MoB~ -OI,]7yPӹ!EaܪN)u,,[ ͔'\@S^'iDIEΣ M4u4b ':`E"ꀹۻzM[RX*bۇtmKI>jhj 546ɚwOqkii2lLQAr?1M-ƶ+֔WT^@X0XyFi X-_Új7vH#3SV665G8*, ٺ+V.+ZR4w^Dꛄ"}՘g}cLZ!gɨVf&F.YѼX&B6@ Tzfk+QK.YKjjj_S"D5xD VFcbE M. 'nZbժ5 W%AҚ5vOAݨqs2;wg;Kv1VyaYBhdLTXVD^t-k*U(.YHލ\RE{vWSwwMumcCL]lqfm]mGOW4g5J$k8Q1U}lӮkT([,n4q}joh4To]>r({/wW'1q[dfQ}SwϮIIќkFn|zʵז,XB ٿ{_QsnJ~XGw /W;W% `䮁xH8Ē{klYvMʕk&iYk}7 D5K2#̭m}<\' eFp]SA2C8!޳a͚VW.4B Ԙ ښ}[ˋ2G[Zs1{>nN.qdM2%t#--5%*nmY"W**֖Wl ھeCYQ.+jXQ6fΛ={ƌ>8kأ\ #L~LY:gifM/&ok!HKLfrL/#}bZMD,'knݸ~v^j\`$DŽϙ9I6nُF %舐 CB `6w.f& SG0l]3KN^޻uȊ66 ehxRgok=J'°-59 U)75TcMRX/DS|IiM h h\0 KMNJHHM_$}qmcxKArTbbr2Eb\d\lC˧{w iD~r38L~/Ǯo_bMa0l!LQFR ELb22xV=d<>hE>:ۚFXa3775u<θ\ӂV! 6gH|:4&qpr:*FG{##*ab1P6Xe=P;&L)7zL|$J!WS5?zq>~>Sn#}ER4Aݚ^>~>^ߠtKuZ.nZ4/ϊ wvʔ@8o wH;y=`xPsR32yyap=ߗqmfNycY>gItH:c|}"[ E@Ly|S}_b܂|!aG)ߗ@ fЗ=)RR RzM 5,ÍhgQ#<i߂ F݋)P_"]¨ w>.VFzQT444)wv‚EyCr3eVV-8SnaS3m]ggdM/\Y\73Tr s+H`-寬bzڎSIvYk3y9{V',/^[0u2l]dgqoۜ8;{m]E8'^U9^81}B~ў*턉c2wTٙ~K^pþ&L .#C)\ >Tlߞ8_g]8VofLbdߚKyjJwdxړH!:>k'; 9Y8^^fve]܉&Nk*;oLFNVv6O00dB{8Yd\NK][y,'EX) 2Zq n-g7jD.4*\`dgg9y 󸅻wgN0ߓQUc.Xv=A&d/ڰCˆSjQ'/as 6v8) P]^bKÎ!Wfҝr|NލX̌}!lWؓG"Ch~,.ڰ976-3+ؼm; 2Q5Xٕ5븩\ +kva\?aWt2G'3hݛrܒ1 Ί .h;#Ȉhh&DB;gÖ8F^;o vrd`7_w +53'#^8!!;Q4vtʞ̌ªR9\{ VORmA6y8(b 7ծb2$_Eݸs 'K hZ]9+-#33;W4-!3]gU$[Wo+ڳ'?eܔb/ڱy:U?oSmcdV*0KjքWhadLweeeڿ13r9V3X|F~SadBlݺ8Ƀ{-9qYYlCe3Vl(JOe N$U2r4w|v6&gyݦi0F~/~dFLq`v+0%g .BZ9-@/PtwÐ~dI5BٌOp~^yXQƘ1);{æ̹02 |=';A;S]4es8p/Yl.,‰dmڌ@@]&jѪNɐԃ i~ə\yw%Wyef xVgNadfԍ4 ꎱLM=:(=C.pLY,[ xTe=MxQ,0csY sdgr52*ysgӧ Eߑv4lc18􈩮VLi|o((`ϛT163xqN000Y0gY `E!/E/Łyrekb #`1.v=1/S| Ο U1t!RCR2l60C4֤h{22,&[& 3be-O?/8dYfϘ4͞ք`Y A|&-1TUTҙbt \bn\2fĂ* R~vJ|n`.*MoicU+x ̘hT0t&jh9E069Ff䕮ώ  nؼxAaQ$A 11!%?mL:ˌ h3w-D$ugkg;-!TG,7wެ9sSv#W_VjbRjJbrR"hHgqYQ 44u LGj3+.NIXYM.+l#..&,,"dy fm"Slm)ZZX42Mgpi셋fLrrvqqvNȆl#2^BBLhTTyBfB bI `4/#~0-5-}Q,F02םa1o'y30k.ު]:791.!xCw!7PN:^W`1sCM,G27ak>Ł<(ȋ p:erL&/,,_LJ{M׮BVJR 6<;@[]]j̸c[Y676rI`RRyBLo//7W{0 @iVfyE&T=62"2<4bF5fD r1l=˱vyh sKkKSsCɼE . es$& xkSC=m!Mwvvq?vfFV\FjZj [;~n6qhsy\cGol(8xq.NG { cƌ=n8K9gy2<56R"v#e뉶N&Ovqptwok7X0q}DZJ*7|-L#aYG(>/O7"1ZFMg;#4k s51IO {zĸؘ)J{PY3xOvrrAAI͘1 pt^6#w$7/o C'C*0*Y67EiRv>mJdW/vs8D u8fD1n40T:44e)a%$D'TߏT5BG1 +@&LƆԩ>a]wP|~T B$,ЩFjT#SR \`I?) W$%g8;ww7woC2*\@WȂ>N2y#R'JA0 7L撞f5`~lv^ʌ(:f7}A$0B%A)Y9vN8_SOzJ |v:pyl|9Ruu=J34mj~=`HCQ &GcY~NE.cU3`Pd19BXOf;!9֕ր즁apm79ɁVPIIfMsv;9j(tX?[1B\<]&21x'G9'<wpv0PRPStHXB& ƃ} \WPR@##Es 33#==e"jKf go?yPeu M%GzgIS<:$K-ӌ%Hjb-pwh$3GC5UqS`a``2v8vVgRRP8+%v"LhN*$"dY0܏0[ee.-IC4Ys'UR>HτC :2*%\ M@8;jh4ԠfL|DsÇ#_/[Ћ cU5z!RWs&ړh !.ÔȅH0"4sp1NT@t'FO)*`wHA7biQu]]qܒ*#p 'BUJ`9v6U,]ܡBw7 QȦ|X3!9*yQVc5@OdV #k,/nH3Hid_:V %ʨ9|AlM,--,M1ɓ8@!&;YL6wǛicx2t*d1 ;:|&^xhMM+CNq|6 Պc2b(sU𮢭iFfICYX ,HV&ux&̵# UEHԀ*+)@DhסO_00QoDR14Uv1R/ ٝD>4&͕CkʖD@d #r;vT4o3H@f:%c! K8:1ȐX, ZX}5K)Qg8 cʱhaƪÕjF*؈$*[Pq54m nRIW(._טBÃ^z*p lULBr2p%j%&$A(QxxHu@ Z X%3VAUqU5#:AMZYk DfDV!0t\QR)CTe9c+%RCP}M2x2LPӀ@!jrpj+] ` @OryķS菉:c`IU|2];2ܜZPQjV:nJʄPO7$ `AQH5^WItM#%>+N`LF<~*OuV,qяk,~2ya/ϓpUA\qaZ(+$g ^%O"pHP-Hů'7ɉ0kr|~O j'Ъ @$e:Jy٫W 2ކ/*eWe;Е@2"`H`BUTQjY #X}rED YOl|>i/it PbBfhJ${@z%o"a-K1`hp_T!?p4 "e7>7|ʇ]F$*Ie D"ח@l!DDZ0 K]@+p'hH\1xp+ !q-TOuT*3>a2A20pyEK삱 ]N&?Il?`nDQ1A9IGu?}7vZM L ĊAFT>k@ *?4b=v*`IUC)rw D̐ZVJ&CAN܇^)W&ɡp|U~8PA2EZN~~ Y67)`MH74 (B! h(%:EAI ҉B0 ƥ4af$lCHd_q3`5H| Uj<ϡh}7X#OEr3CQϦSTttD|҅")PeHQ|NpÚ,*Fw4 (*POITЎ@Sg/I~IoP+ؓ!@Q>mD|~:FrDq88>T !?_$Ѕ pb0/."թcCZw c߃L0xCx(J0?p/iHPU .ia F)"IpCl=5XHXsұd* IJ4؊T_%'?=]H$_ 'ӕ44Uh2H"ɤJDQƎ2755ij<\oΐ!a+.g7g턉NNvcF(>|ڈ'~vo^9Yr+)?{V׹?<>d hC'?~݁OR-@ְL;ܒ6\lW|c5eOȒ>&JɚVkCHSp9,? *^ԛ[' |¹c4~|9_`x,H:z)슰:)AߵeNP%oL<'Etz 3 /㣪FK]:b}fǎg;ID%C#̴T}?@]_)s2Ndayԅ=TW]oRw*R]Rޏ;|տS_i>9ۊȖf*#ftY_K>ۊW=$`MgL[[k%|Z׿:b۷ѝ)s[;ߍUcsMo-yϦaEjYǝ8n=Lُo-Y:{(#gս|_S< tjwo-%Z*GLU1wۋdMw~N_օq GN~/xi;4Mqz;u'?vLzQ?>Zo_Jצ[jF NwgɽI$S&>&lǃ)>YisK?lXoc@%5>ߖ}s1'DSյ*ӿzjKbUO ̝{?{psfȷO=UIsm|?mXc?)zRv\ϻH-SfE (te ]1 7M:oՙLTԵu Gu_sߵp|[TP}^t d'?;Iȷ?|^Ii?Xmɼo~~., 7f~֘;@~N{UFߌc?0?QŇh*K)}o#'DMn{|3OXn7>NMryø:~FGP2 c֙?oۗ~5&o[2 ُf5{>s,~V_@ f[(q?m3u s>D}ڣ6_yN}7ߠ6翣%c`~3zJzyח[Sޔk[%V_mp2q?Y$Ҵsy^afx}~64 qN?]eXO.~D[X#7t}?608#}fư83T韮ȊCG ӧO?{Hw^KoMi,Z(ܼM=~#bE0sP,UE{]WE՞õGx͜ e/7?~qo5;nuڲj@Q6H,ݣJN.-nXł[oE ()i䘲S;uQ༃os[ӦL=JeZxд*msX`Sn_,ΰ5L{O)#=շMI.z3^/f)E5]̲R%t"־~ cl[=wR@eݜ-'47dZoϝN Og6aE } T޾_&;Qa(8~|y>Fx[@?; 4͑/~rIޅ7qŽoy3hӣ057Ė) Bz}W|?3RN  H,~ 'Mq=CRGO7T(K66uuCTL<V}lI_ix|Z d53_I:]?!ỷcf;Ҥw> 7i4@L<~ۀxtUm} dŸOp*z?/a$ D5z^εRUAֿ/Z8L郾%W "_$ϥk݆}.9/i<ݑy V`?=F߾ 9$oկ>ܼp(mm wǯػRO߿LRҷ v5V!}!) t oJz/cX>Qɫ9I$]͙ _S3X=~y%@ ЎBz`]CcX>cX>cX>gFO?ҿ&S! 瑆t4-@cшX,^̔ .#0^ ǦX>cX>xտ+}4|,_} ~^'$էO'''էOW>J2 էvX>*R'{Dj _8X>cX>cX>Ò"T47gkS<]J$F+W._t :Ξ=sǏ:"ijl[ԏ7?+Iq~?^~aS'O9xYT_݋?#3M :ի+a :vhE"Wݿn* v]Pgon$E3! 7yCmRQ}]]7pW(E z:Z!JD+ވ8rMX{ǎfZDwl9ԝҎJo oτ7/,"ٳO?<&߷}ӆ#]mh#P gN8zKְƊgҊM~z0Ǐn߹iӂ_a7T嘫W!M8\sڕљ$CE1B.с.iݮkKߕ#hm-Jy4lLW;{ݛ׬|4?}ݲvALb3x4kU;c]*D|-n{e'?uwwmk˗A-Ъj]IϿaDh_cT._p#}m7\)+Q!3Hҥ gOkXZ*m #lOshoڻlIozDw.8 9p̱VC%ܹ#N|PC=kV >ajiΞ8-ٶvYP5sts{/=RpS ]:hn{Ų%ᒫQKHor |J|#_ .Qu<~{wV م6rӒY5U]t4֦ŋ4Y\3u/B_|r@_|nIuKd\eHXleU[T@TԽ}-~zE`kÞMkW.-.,T^X_tي-1QCa?~:6U\lYq2+J׮[k7Ze"» kΝߵu:aRPP~ݺ7oB\Awn\rq>H۷oۆ۾cg*?w;wn.?ul]&nl޿wߞ={wnB_9Fw4< 5EE&i\^ $\`՗/ܿu.]8wcGU=rζViXZJ<(R{X p SJ'9pDRV g . ү\JA:iOg =*!%_}qŁ֖kz|Uyz>ǥJ.{`˽սU[;N]'O;{ıU1ѣǏ?Zp/nwhCﵲ5n 嫔rYYqgW?.ya/n=uT~-aWoa7^HWpwUh%|0/wn=sG摚;5t?KߥW~B:FŏF?wec_SkǑ6ɑO "vdSDD ^w/{<  =wNpO" DDE.ݑW.<{i1}q{[뀸@uDZM!QѠn}GnܻQpG}cöVɡmx{7kX_(k!;Yc%L?}Ob@ (UB^,3ju]bВy\F|_tPo`/n]<(ZT|bEx90R=z$g$2Y%o^\ŋn۽N,mZ;rtECsbmG=>z /)e7Pẕ6:"#;$;׮-w91"0|e7O?XTW$s–Ν)mRI)5 ~h >0YRWW9.3Ϟ?9A$eby-RU.= [V}+-HD'GEF30^*_ 2x H~w%͋g9)JXU *~QHNPC)xt_9rB@X-_[>}%/ ;|EJED˳VX\ZTFvlU,KU,zBT}:iYVQ*vZӚ*.MTM;&BؒB seo~E[wժ0-%pf8ZJO`[!] /V%UWd)u:8{Ju~_T}_5ǨqVp8fx)l!3Z[/} an)2.^n.]T +np|'30 ݿHooZ$ k6F^UgܻO eVX":EzZ$:Zi˧b=\q@\ξ:/u6Z&=Y9x3QnttXj3f+2/UV11*p0b'dDE_۵p4(m{1jQX=EQr~(֋Tz(p KiCMk0_PX'V+^x3ԸC]d4m@5fW7ȧb bB5fy E)[]j·Q3ey(ˊ#y]{ہ];Ȳzc0_7?;U7u '`^`vV&u騨]}LDUe~l'Iow5Auͣ(#)It;9G6.a|'{k`H 3r6gdl/[r)߻ֻEN8>{[NlY!+g`]ЪDHR̍9Y{.[ȋz$C$P$ cӲsTʷkV/-wtGogmxY5ݻQVBW#*H3ėSrM|Ag)b%aaE&Nx꩘r\)D5V%Z-͋,_)ɔgn޸$p e qOD+cnL[xYGӥRu$ψ+g^$nf&X**_A7w#lN" &.~7l,,\^+2G\ȟO_|eiKa"2b,aШmQ=D=|er,:9q.JsfJ%bYlwFy@k+}v?,G/=]Le[6ȿz_0{x\"gfo b@>5U&H "}=pv o LN2qhih qì@B(ɔM¦~ O$JӧL6m=<5NFS|!P@~x4ϺLTLcM4(lIMܝa!y|zIGoyD>;Bvȿ1E5PەD^K?$J9{A"}}x=5BWox*pZq'I[,8nc$Wx!jus}[`6L^~LԦt_$?=&_F!wg&O2z;g47?^[˼RCn)eƑ$2"V ETvݳk~АD*4N?·xƍ )k3n|N-'qC9{[Ǽo o7|BnvלxpK_z 2^yV^'Ooa͘6qav~7Ufq΋?ư@C_ 1;N A8#Z}^|A=v{ӃQk]={НՕ# 8c8!}"f00 S1]{MW^P`Vso_@03AhXT"|]Mf6E㔀a$xx6-* `I~)`̉sCɤw?;al@Ceܣu?;Z`(@nE~rtTAZN~2}^LځT]$',I<$ߑ{xjm-ӫYy3[|-`H)`qll2U Jp%f4|FTH `pǪMZ*O4KUKbj7-`rà4O^@}M#Sp5PdYRd9@a!t=ȧ?QH?fػN츱K2wt7}7gyO1|KDxN-8q|VlW ċ fSxePt_UB!~c>OU/Z`8ÆS0nF^c0<_6\OypB ,vP#(2:0A_Nk2/.p X }d2*)}'.r :u+r ;ᙂ0&G͇zu.!nO:\]U8/m;VXڋDEv(jc=hkS>?W&;2<ޓek'ۇ $þ֖/HO`IOHA,N0nPpp%888;<Пb"Q熆GDq?>2r\Ę#~,@@h›bs*.|$7@=3&d@@X3 K{FD@@¦',D@>#vDۺ08A>]#ȟy ?o zo!% "4Л|uvH*{ uC7ߋ|||||߿ +Oߏǟu$qdOX< `}A'VD``0i'>~4l=0mO ` ?G\/ _:ɣYCo0O qAω vu y?aC/5O?O?O?O?O?O?O?OO0h ?<w!\3}sUfEN.Kp/㓶v|WvʓoMO sxTMh/ 5񂙑pogcW%$UIHX˟9q4u)3f͙2g֌)Y=yD;2"<,fMsOP xt80YlGd{t!P[: Hyo#N {^'—K36 )̜s̙yfK?;kpOVQk_ߕC ?xżyK;,e뺢>Xjeɫmʓ/Lq1DSꮑk7紤Qw03+޻|Fb$$b]JZF?uh+Xn@;:vԼ!g:;}x[ xs%y6ۑШ8/VNe!l㹱ѦK'̗a%N]-@mT(}B[Vzp2U}Y3 SU|r*7o?sF6Iʲ~3i,)n !0vdl} j\hhZOoocqrZÌ.SdHT"EQs}tqriq8":&j"EȪҲU!|%%nek,?*GwSpB,O)ʓ\DSBIx  po\Æ`Ŋs]'M)r*35 pv>{ˌ :?W.g`oY+EE3dR b5#.;F (IW/)xو$bjb̀ Ð+b*|Jl‘$r} ߠE28Ah A`'*Y6y*&ņ A`l˄ еwvփ ; 5AfpLXa2 1!zZZ A5as& ¤A",=>]FxL-}fUŸ-:DUIk+ᱵxDlLS=$L,YLP Gl8B!gBc#a29߿9EUpv==.8`2v,:|ͬ5I4 Tz(4 fu`a2 " 3(͢",a4>S:l8V1t   6γT 5%a2&Om; <0<\,6ϯVh~O&hA}0{ӕH~b h^M3ݠIjGXNǜe/p,N6yP;{}S~g?rf8;<P$ }Nkl_S-w\~)p K71CA{47çͽO3~\G?O=4Gh>5 aIxW?'6>~di>OI04wTz@S"CS )Y |4|2~Đ]w|+kPz51p_b|ńb|aF+L~Ո[~byot*y_~saFz5~!s}b`NKFR)t~~cv[j=s۷oĻw &i/o}A_0Yu]?ge_3tcz:3rCz@@/?FuC8OO ߾(C;]P[?>BTM+}[GƑwZwnE9[w_}K_~q<|`- =DcPCa՚ޠZ h~\?ކGj{O?,ϣN9KGvo^W7?3j&;?ߐ˨o77?.JjV?iB'Ozȇ j밟{ {#¬#Zsvg.8JZ޼ꍛ]\p2+5FOė^zG/t]yEuO8z7'dc/1Y4:skּ4ecG^>;pBR :sPo2$?3%Qwtp[JK\2rEm}z.ը*Ran2!-^ݲmH}ufmk'dR Kk:;[zuyvbesxWSOyInwoέUm&6S֝k_6mbpۅV lQ_[3uuok4aͪU뇻;_ٽkۦFbEu2vl?9zCkRS7 uwqlݙNpK5As"CkZFf|{IH_ K[470tʥ;[;BQG}ʱ݇Wm":+srsW\2oɉΖ ybYJjZ~+`*Q^vFҪ{NBڻ:{:^=y,y d4?;#eIqQQP(zJrh䡬74nuP:uz62jy0OIl֮g:hN{kS2W9uWwk{Y %-5-kdaWt!Oo^s/LI\`"ڎju(^µOMJcVޞRdUı}bsJa5f΍s:NGwEEEFNe#ZE!QQQ9-6ZɈqHLXW 3#c#B7^R.O#He5 EĄzsws̼2* iUcfoX"-^01@!(y(U%K. m# +E2iNeD Պ+,X=hYD"+f͈.+K-^`~J@($宆fBuqL29qՊX.{~P([df=&G**[鹢T&Ufρ&^(.Ze3qiayvpL*gC"SmfyΚ}e1͜uhܩN-%؎.Osppttrd\p6oolmّ mH9zL6Bry5˰օXbG 0gtѲ,0@zLS>Ht#B d': Ϙ4T/mnjC)D80#l^ L1|c -C8bA2WK4%YY<] Ff4L& s"[Vs _GF0Y|fﻦ,815 0\_RM۰vTJzw62S[4r<C`361eلa6&cޖP 0$}Y39¢wX,=$OR7__9j5_m kjePB-sͣmbqX(:8Φ7ITX c1 Ab2Px MoqhUi\hQ{VB5Q6Tқ_,*zŢΦ`P/ 8ޠ/xavL(dg+ec`7  Pc{Y̓Mo\,5w$OI-қ<ѳ,&>{+7U;>ɳ7?=>}?0~:-8b̵?E!zd͇_w3oVbb~#6/1c8=T>-yEok?PMq7kSOF?c:o6 ;ϸQkCio}~ڬ7<.݆? =.6uzY g!=:6?Xø?*}q^#nuo31¹??;=ߩQBCz5Sߌ'?ԇu;4ttZ< haw>Or x].m{1sZ%a<(br>Ӱfbi&/oqsM y_su/첤0)t-hZOXZ][^HC}JOVj7t]t8qzȧ =FνIW.^~V'dbⅡs#?v nܾ#c2Y77G/>wc].^ YR[Ėt{ou^GG^&+%+̃\cm}cƆ޼xj҅k^!wt{f #ytIjrzV"9/_#C޾4rܹ禤efxL6]}##nz+\Wd-{L֎o9waH80|#MFF޸Z^gC|_;:2<4pg?7{Ûs22322&/S7u@w:>~ojnVfJzBvR+#g[ Ftn=u)陙iidC/C޹xr@On&a&=zxhhx`mtloMO΀ti鹱׉Azƶk]9}fzSRRir?]v|L <|~sTwT=72ǯ$LNIINR u*@Uf*Xztlh{εI) JA3eeBZ^ghxdkgޅϬUvj&ON:qx7o5  _vmllp+'ғ!JQYt6?:m"ޡW:=x~x7[krAA d޶\52[;ex+^8vH4%%ee*IMI,wFĩsc94<8;mGϝx-*#>ͤkΛþFm֏^RS@ׅ_>546ũIitĬe׈nzn5w@{\8sD=6=Ƶ%))tvZFj re`@| хu_`_嫭Gzں.'%99Mc|BLW H=ԭ;玟<74pЖ"4i%C=4FM}^_sW@_ػo1:203%i U'#='˝qdo|tc}®dHkߩŒW;oyh_hS/w ^>[-"59#=}\%r}޳ojҷCJ'xJʏ]_9;sF#C=oި*>i)W|H߹F[zz{zn;rj.Wf e Wn q1Jo4rTwoww_/5u~x{ ?3b ̜WAr!p#cG w^͍c0/+3c\cZjf72ԋ?{nӽ}=ݝꑛ=>UdR f8xɚg όBcTuP[]/5gk"B*ЛB_dwx&;egS?(Tw^9zeO.Y-Jd2IqAvFfzRjrrff(dL8 >?ac#}=cڿTKerqq~K$2vvv/ߡQvsˎnO>S[RVQ*ʥ"(hfZBRf("6li"_{jtm=t^}ieYyE\*Yi;M8ӲS"i셬}zfs+,=o~0cMYYyYL*9Pyo6kQw^ygp˚P']lٰzrB.ge篜x,;1<~v$ uWWc5U`R. rfƈ oV񩡞[ʼny Czz_}Jw{µ/T]U[Z]Qd" 1`t?Rvls=]W=CT~j:+囟oT }#$.= Uq|caФAϖlu uj5eR MGE/vw+~gC@ey{lTWS[%X]*)>!2GKzܾgmvG@ގzKe=ؾiTJ$e QtCzl41=io?Ys.(}{6n\__O(//}$5!HpMݺO81f}`OksWfшm[o)_]0D0tU1m-{KMh>YʂC:o<}מujת*T.w(jX>'>Ib [s{wtu^~U(=> -հmf2TSEjvhY[zmmm-פOچ_cbꚖnUÛw Tj?6_#(bmޮcf:9Myt]}22:M>xeݻwذz14Y:) Zbg[{Sm-P;EfΜfco3uvPuZG%eon =;v74lߴv]rӄgTZZ;+;&i2[ۻz{Zw2~M@I3تjw~oFfyv]'#wjNݲf&٤S$ƳM-]}=-/R\m:{vqxyOw4'TuO]}r]voݺsCuSDױdccә S2MP9qv}A5cb[}NbjFZRf;.j;wiضeSXIS|dSMO656uvݣ\h??cEc_DV{ ,>:ܯp0jwlس{۪f$+X6ma23DwRfRrTai)KflQt}crs H'Ϙc8py-bS?RfvL7*AW-Ilmmn>Y'+,*ŋ+wZO>xfR#q,.WHE"T'''įXZ<Z[J TE)B0U>{vu ܸ9tM&ZKyy鉫/MkאPEvFv~~A!,g Ul5Gc콷1,T*/##+#i5酽J=tj0-;';'7?XXm]NhZgk~*$@dfELf\E -vu k|LdNdW.ujRm0^d]]c[.s8#I┪qzFv*ԡ^ ]xpJJԭNM8uL fk^ 7eX:ۇ5UwW@a_o Ĕ.MK/!H5^ >@ϴ]ooteOMWetl5{=6H<=EԺ+} !Xm(f )f4yhÀP4dUrL\510Of''%'&'wBr[y`o\NZo…1/=Y~RBBRRzZĚ5C8KSuoĨȘoežSUI`MĚ[l5xFRc]ˆЈX_Z": +=%3ٙPuЯ/ KoT\ 2smÓ3Wm%+C='jsbEEGŁ+˝<}6bePض[4<4rȸXok2Xk JW1UjTHXdLDDTddD_._ǫ"QF#| }TW NEE91OXf3b"#D?t\*@b.."*D99d~l$U]Ɍp6qQ"cKH*`|e$+"*|߉KD\ 䏊څ- Og9̋_sd\L{jH7k4{?{'_EZz Uمf##m, s~K,MWWnU6(f):^\I٦Uk*JmWyoD/W+J;QL4/sxXQZR^V4WF栺!ׂ .+UyLuhmbsqa-b*,tJ(/6Q_FHs|Ow_gG*TuyXV^VZ"YAe|mi鮖)n>~fFtkADVt]nՊSǥ=}gi}@&RVm)KK _-Y~=U _dyRվ )TT9R+_[xjOFʛ;Sl9{BTJ*4mɯXXR$W*K岍/o)QKOmM pCjO*+KKcdQТL)~HQqyP(+eeÉڬleDigb,wMf\%@QrL*H7!*ʽGQ@(3*p/^[ B𡲬x͉sAdR|Ӿ"\&H̓Q` _8 f))o,.`qq塭bzwZԜ`?O:¹B DUyADC)\5x^1BW%y4HLyyX`vTXtdhp<4e$RQ^J./*5DJhSՊXyR7i_&.а4Z%z`Mj~tp~xdL\tXp2/;EJB)_2IeAia(U W;s.A%R LZ/LR]Š W(d IMkKْH,F{C6DEKEO&m[jjS@#u/6:, ĞaZ\*~UXlA,WZ(CJX Fщ Y}&\ N\ErP*$&+Jʻ|6B(p!2t3{RD"H X". ݪUqi ^U(&rh~xy'3 2h0rH/nݜTS_ښhѕ1|ιA~Ycd2.*_)ynR,FnlAXRJDUj.\`~,XΏ`wQb0͔*%B8;!|ƌbJ6A,Qjnl5dbIxȯK stQ>6_&gKE9B]O\I7#6)Yxbj101&S>bq0c\IN P*m/Y^%d/ @DܼiA2+ $H"x֚9#*9ؾ[b XQ %.6h80t2bAQQ8717S)Eug/ʩbNe-]d01c$1vI`\$ y9˥hzR =*ĕKH0^1Dt&{/1!Fz8sLCJH(+gc4D\|%K͋[[X͌H"*X_[ofRu҅B23*j[a||BJ!Xٷ=5s N,*8f:6 eJH(mH3cT'߶(!)qKArA &Ow^+}EEE S4i_R&%yΚB^Ru011))~eh?{NXOEB{D\hajfoR* 55*)5u,59%5qUJEbmN9iڏ|6YNNFbZZ+Y s3y9"4^A(olj&&Vvӧ;;Njcke1;A"*w˫ sBBe*Tު]]KKMO9IBt]<=} 5DϘ9;zPZ.N kQsW(G W"*߹Cehrb.DGzxC2}ǢbI14"2oIXP0 :e?q{!2r23Ҳ&s,>w??|t4ƺFH ,eȠఈظM_*TnUFML˚s/\0/62,dN 뼪^ 1?ZpfD1! 46%Th T,Zs('7+#=wYo4+.1Q!Aak"1tZE>A!s "#]mm)?`Tm54쌜UfĀkp]ꀁY ?9h?2wnֺ1R!tM)vܛ6@<.X0g/r=gy/.UڊKq0MunШ9\Pc+mٵ}hz'y{T /LJz xZhi;&+b:ΑTɴb R]Z9orЂq0 ! E=fM?0[+6 Z!tlgL9^A3xۈ_VB,BR"\Lshh?A.j &zJ$(;{G'#egJ%Y s┐v.@ɼψ1^^ș7v :ґ<тCݧ-ɓl4tgkgĒ=eI2_99;R?߂Evv;2G.%Պ{b63$vr?ɜ?=sR9r5L8L {gg8DNS!tg(qr$fC2ck&c:M| ]߉ »)]xrA+ԲvP9n:MM-5/X<]+}Еr8 }[bbbVi<`Z?%Cb' KW˚dMܬ@1t ۘ rՄcN`re'8gpVO0gX0h!'QX|{kg,. T65܉9I>|Xfš[q ejM7e߆BcGj3s3̱wҪ' >-p>!Zv,0YgY5aB%l<&3-jZ[!5>TjA'LޝŞ4,f7W&M :QA"-5 6aL4Gm{+43D 2 hm^q69*Z5AbljG=4ģy'S!+` ?I k`:Y!,86VVi9}dÇS!j!–JQAzpkbP4uA*Ԝ1ȂmmL-q:UZk2YcSyv+Z(!-FUghD2h pd&p4塢u!f<*ڜO ;rpN^9g9[gQ+P|c6D.004rzpJ<] zjM<k37o\e JF%s=@wu\.3݋d=  54;I N8;I8<.M 9K04486]߁{\w]Mt`&5cҠ,^#TӬ '8jM hrp\љg=uY-tszT9pd V;EۦX*oB F0^nu#(>GKG {@0`uRa,C$p~;Ѧ״ KsiZ*}(x<yZxNjSӸ378aѝ=82u h4\C$R!t z&ǘULm}z Z^[[rBtp:]]vt U.ˡA@wb@wc04Ck!S0Ǡ[,]={HJПFÃI7&&\tSpf~6ù:,du^olB:8=BŁl?ʆ*I-Ag>C hb?ؼ a % fq& iټ Zc~E|j( Clc!6-݇F"]29]h*bhRFFz:::Z<dl$&bt3N`jlb6a.E6V &e1u6gL_s}o޺Ւ /99;j6z_gRh}N|Ν_]X<ۜ"k3afgH1E)烇Cy^Qw5+g_-|Q[|qF1EE YGosl"p}_=nכ? 3^H;?~3;*_HǴy>:*} ooOOݷ6%yqzPsg=oOqÁ99}v wUMg'~G3MYCCثBL{ۖ󂬞: jw}2LO/6tH{iwk`ax&?O+ 9'}6i֍&ϣp n?o*o⏩7uS'l_p dhYӪ9t kS{G3}C#=Oҿ\XS|޿~:{֭csM/Z?/%gR&pC9,op9LiKZTM3OAo-%N~%P?5̿^n^jzvzzؽ0x3N?!PϋW/qyƁ'6߿Bn|7gl?{_ E=e2sZڄ&2bufw߻]\7*yXg(}${GgXa ''˯TG,>[gC䆛Jw?iۚk5{,[+ǜ O)Xiޘ. ?/^/TN{Ot ~;Ϡ6exOy6tf'*3iZL63`YU|py104awPt溣v9y'Y9 _%S: ^>= mHe˻Osɏҵ<{9 zd>jL%z9&߾$tכ܋x3WC[L-k_l]xR7/͐-gy3[/[}1ᄊ+1.|1suk;?Δ^ЋAݔ<4tQ~=X014w ?ncz? }Bfc Ku{1'3x&.CY8SL?6 1_o{w}c f3o6i D4zu~C'YdL샓s'y異|.J]g 3crkNUO8cMJ^{W{sf'dEśzY|l|DO2NIW^lm鑙#W~⯿m7%)v3yFv+%ꎶ3{>}8t"<`:qVTRE[W~~wkSyTK% c‚C֜{,^?zŔТ}c}ֳ0-$]/s{^"+V,ub=SN>w:ZYzCzXj?z ]lc0u큯ϯ]iL-g-l2o֮r5Feg^j3ygjM:6z[3o.V.w7?9\1͐@a/^Oߧ*,)!9[?=2~cIl/[K+m`WnHx֯0Z&n!˲~:n!|@G]_SԀIJb<͵+^0{/׮s&_p ÷ k؇~h|o'gG~p"]R'6vxqR&M0ۥ&aYCퟨZ,Ay+]pZMwwIᣩ mPju+@Oj#ڟ> =BřKo$ݧO4R|Y:V r@[=Қ2k>s f#s__ 1~b>v,u3f40ڱ--s?%) s6mji}߼ʹuxjʿӶw'>ԭ𷢯k=6:oxUuǿP*? n^V֮{D]|Ew%KV!|޻"gPI   o]:ʹMs?m"mk3lCꥩ7T3yE߭?{S'[禦3#;>S;<޿k6x?gĉ:    0, "Cartridge.Manufacturer" => 1, "Cartridge.ModelNo" => 2, "Cartridge.Name" => 3, "Cartridge.Note" => 4, "Cartridge.Rarity" => 5, "Cartridge.Sound" => 6, "Cartridge.Type" => 7, "Console.LeftDifficulty" => 8, "Console.RightDifficulty" => 9, "Console.TelevisionType" => 10, "Console.SwapPorts" => 11, "Controller.Left" => 12, "Controller.Right" => 13, "Controller.SwapPaddles" => 14, "Controller.MouseAxis" => 15, "Display.Format" => 16, "Display.YStart" => 17, "Display.Height" => 18, "Display.Phosphor" => 19, "Display.PPBlend" => 20 ); my @prop_type_as_string = ( "Cartridge.MD5", "Cartridge.Manufacturer", "Cartridge.ModelNo", "Cartridge.Name", "Cartridge.Note", "Cartridge.Rarity", "Cartridge.Sound", "Cartridge.Type", "Console.LeftDifficulty", "Console.RightDifficulty", "Console.TelevisionType", "Console.SwapPorts", "Controller.Left", "Controller.Right", "Controller.SwapPaddles", "Controller.MouseAxis", "Display.Format", "Display.YStart", "Display.Height", "Display.Phosphor", "Display.PPBlend" ); my @prop_defaults = ( "", "", "", "Untitled", "", "", "MONO", "AUTO", "B", "B", "COLOR", "NO", "JOYSTICK", "JOYSTICK", "NO", "AUTO", "AUTO", "0", "0", "NO", "0" ); # Load and parse a properties file into an hash table of property # objects, indexed by md5sum sub load_prop_set($) { my $file = $_[0]; print "Loading properties from file: $file\n"; my @props = (); while(($key, $value) = each(%prop_type)) { $props[$value] = ""; } my %propset = (); open(INFILE, $file); foreach $line () { chomp $line; # Start a new item if ($line =~ /^""/) { my $key = $props[$prop_type{'Cartridge.MD5'}]; # print "Inserting properties for key = $key\n"; if(defined($propset{$key})) { print "Duplicate: $key\n"; } $propset{$key} = [ @props ]; undef @props; while(($key, $value) = each(%prop_type)) { $props[$value] = ""; } } elsif ($line !~ /^$/) { ($key, $value) = ($line =~ m/"(.*)" "(.*)"/); if (defined $prop_type{$key}) { $index = $prop_type{$key}; $props[$index] = $value; } else { print "ERROR: $line\n"; print "Invalid key = \'$key\' for md5 = \'$props[0]\', ignoring ...\n"; } } } close(INFILE); return %propset; } # Load and parse a properties file into an hash table of property # objects, indexed by md5sum sub save_prop_set { my $file = shift; my $hashref = shift; print "Saving " . keys(%$hashref) . " properties to file: $file\n"; open(OUTFILE, ">$file"); foreach my $md5 (sort keys %$hashref) { my $props = %$hashref{$md5}; my @array = @$props; for (my $i = 0; $i < @array; $i++) { if ($array[$i] ne "") { print OUTFILE "\"$prop_type_as_string[$i]\" \"$array[$i]\"\n"; } } print OUTFILE "\"\"\n\n"; } close(OUTFILE); } # Get the number of property tags in one PropSet element sub num_prop_types { return keys( %prop_type ); } # Convert a properties set into a C++ compatible string sub build_prop_string { my @array = @_; my $result = " { "; my @items = (); for (my $i = 0; $i < @array; $i++) { if($prop_defaults[$i] ne $array[$i]) { push(@items, "\"$array[$i]\""); } else { push(@items, "\"\""); } } $result .= join(", ", @items); $result .= " }"; return $result; } stella-5.1.1/src/tools/check-sig.cxx000066400000000000000000000036571324334165500173330ustar00rootroot00000000000000#include #include #include #include #include #include #include using namespace std; using uInt8 = unsigned char; using uInt32 = unsigned int; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int searchForBytes(const uInt8* image, uInt32 imagesize, const uInt8* signature, uInt32 sigsize, list& locations) { uInt32 count = 0; for(uInt32 i = 0; i < imagesize - sigsize; ++i) { uInt32 matches = 0; for(uInt32 j = 0; j < sigsize; ++j) { if(image[i+j] == signature[j]) ++matches; else break; } if(matches == sigsize) { ++count; locations.push_back(i); } } return count; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int main(int ac, char* av[]) { int offset = 0; if(ac < 3) { cout << "usage: " << av[0] << " [start address]\n"; exit(0); } if(ac > 3) offset = atoi(av[3]); ifstream in(av[1], ios_base::binary); in.seekg(0, ios::end); int i_size = (int) in.tellg(); in.seekg(0, ios::beg); unique_ptr image = make_unique(i_size); in.read((char*)(image.get()), i_size); in.close(); int s_size = 0; unique_ptr sig = make_unique(strlen(av[2])/2); istringstream buf(av[2]); uInt32 c; while(buf >> hex >> c) { sig[s_size++] = (uInt8)c; // cerr << "character = " << hex << (int)sig[s_size-1] << endl; } // cerr << "sig size = " << hex << s_size << endl; list locations; int result = searchForBytes(image.get()+offset, i_size-offset, sig.get(), s_size, locations); if(result > 0) { cout << setw(3) << result << " hits: \'" << av[2] << "\' - \"" << av[1] << "\" @"; for(const auto& it: locations) cout << ' ' << hex << (it + offset); cout << endl; } return 0; } stella-5.1.1/src/tools/convbdf.c000066400000000000000000000611421324334165500165300ustar00rootroot00000000000000/* * Convert BDF files to C++ source. * * Copyright (c) 2002 by Greg Haerr * * Originally writen for the Microwindows Project * * Greg then modified it for Rockbox * * Max Horn took that version and changed it to work for ScummVM. * Changes include: warning fixes, removed .FNT output, output C++ source, * tweak code generator so that the generated code fits into ScummVM code base. * * What fun it is converting font data... * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include #include #include #include #include int READ_UINT16(void *addr) { unsigned char *buf = addr; return (buf[0] << 8) | buf[1]; } void WRITE_UINT16(void *addr, int value) { unsigned char *buf = addr; buf[0] = (value >> 8) & 0xFF; buf[1] = value & 0xFF; } /* BEGIN font.h*/ /* uInt16 helper macros*/ #define BITMAP_WORDS(x) (((x)+15)/16) /* image size in words*/ #define BITMAP_BYTES(x) (BITMAP_WORDS(x)*sizeof(uInt16)) #define BITMAP_BITSPERIMAGE (sizeof(uInt16) * 8) #define BITMAP_BITVALUE(n) ((uInt16) (((uInt16) 1) << (n))) #define BITMAP_FIRSTBIT (BITMAP_BITVALUE(BITMAP_BITSPERIMAGE - 1)) #define BITMAP_TESTBIT(m) ((m) & BITMAP_FIRSTBIT) #define BITMAP_SHIFTBIT(m) ((uInt16) ((m) << 1)) typedef unsigned short uInt16; /* bitmap image unit size*/ typedef struct { signed char w; signed char h; signed char x; signed char y; } BBX; /* builtin C-based proportional/fixed font structure */ /* based on The Microwindows Project http://microwindows.org */ struct font { char * name; /* font name*/ int maxwidth; /* max width in pixels*/ int height; /* height in pixels*/ int fbbw, fbbh, fbbx, fbby; /* max bounding box */ int ascent; /* ascent (baseline) height*/ int firstchar; /* first character in bitmap*/ int size; /* font size in glyphs*/ uInt16* bits; /* 16-bit right-padded bitmap data*/ unsigned long* offset; /* offsets into bitmap data*/ unsigned char* width; /* character widths or NULL if fixed*/ BBX* bbx; /* character bounding box or NULL if fixed*/ int defaultchar; /* default char (not glyph index)*/ long bits_size; /* # words of uInt16 bits*/ /* unused by runtime system, read in by convbdf*/ char * facename; /* facename of font*/ char * copyright; /* copyright info for loadable fonts*/ int pixel_size; int descent; }; /* END font.h*/ #define isprefix(buf,str) (!strncmp(buf, str, strlen(str))) #define strequal(s1,s2) (!strcmp(s1, s2)) #define EXTRA 300 /* # bytes extra allocation for buggy .bdf files*/ int gen_map = 1; int start_char = 0; int limit_char = 65535; int oflag = 0; char outfile[256]; char fontname[256]; char fontnameU[256]; void usage(void); void getopts(int *pac, char ***pav); int convbdf(char *path); void free_font(struct font* pf); struct font* bdf_read_font(char *path); int bdf_read_header(FILE *fp, struct font* pf); int bdf_read_bitmaps(FILE *fp, struct font* pf); char * bdf_getline(FILE *fp, char *buf, int len); uInt16 bdf_hexval(unsigned char *buf); int gen_c_source(struct font* pf, char *path); void error(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vsnprintf(buf, 1024, s, va); va_end(va); fprintf(stderr, "ERROR: %s!\n", buf); exit(1); } void warning(const char *s, ...) { char buf[1024]; va_list va; va_start(va, s); vsnprintf(buf, 1024, s, va); va_end(va); fprintf(stderr, "WARNING: %s!\n", buf); } void usage(void) { char help[] = { "Usage: convbdf [options] [input-files]\n" " convbdf [options] [-o output-file] [single-input-file]\n" "Options:\n" " -s N Start output at character encodings >= N\n" " -l N Limit output to character encodings <= N\n" " -f N Name to use for the font in the C++ code\n" " -n Don't generate bitmaps as comments in .c file\n" }; fprintf(stderr, "%s", help); } /* parse command line options*/ void getopts(int *pac, char ***pav) { const char *p; char **av; int ac; outfile[0] = '\0'; fontname[0] = '\0'; fontnameU[0] = '\0'; ac = *pac; av = *pav; while (ac > 0 && av[0][0] == '-') { p = &av[0][1]; while (*p) { switch (*p++) { case ' ': /* multiple -args on av[]*/ while (*p && *p == ' ') p++; if (*p++ != '-') /* next option must have dash*/ p = ""; break; /* proceed to next option*/ case 'n': /* don't gen bitmap comments*/ gen_map = 0; break; case 'o': /* set output file*/ oflag = 1; if (*p) { strcpy(outfile, p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) strcpy(outfile, av[0]); } break; case 'l': /* set encoding limit*/ if (*p) { limit_char = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) limit_char = atoi(av[0]); } break; case 's': /* set encoding start*/ if (*p) { start_char = atoi(p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) start_char = atoi(av[0]); } break; case 'f': /* set font name*/ if (*p) { strcpy(fontname, p); while (*p && *p != ' ') p++; } else { av++; ac--; if (ac > 0) strcpy(fontname, av[0]); } { char* u; strcpy(fontnameU, fontname); u = fontnameU; while(*u=toupper(*u)) *u++; } break; default: fprintf(stderr, "Unknown option ignored: %c\r\n", *(p-1)); } } ++av; --ac; } *pac = ac; *pav = av; } /* remove directory prefix and file suffix from full path*/ char *basename(char *path) { char *p, *b; static char base[256]; /* remove prepended path and extension*/ b = path; for (p = path; *p; ++p) { if (*p == '/') b = p + 1; } strcpy(base, b); for (p = base; *p; ++p) { if (*p == '.') { *p = 0; break; } } return base; } int convbdf(char *path) { struct font* pf; int ret = 0; pf = bdf_read_font(path); if (!pf) exit(1); if (!oflag) { strcpy(outfile, basename(path)); strcat(outfile, ".hxx"); } ret |= gen_c_source(pf, outfile); free_font(pf); return ret; } int main(int ac, char *av[]) { int ret = 0; ++av; --ac; /* skip av[0]*/ getopts(&ac, &av); /* read command line options*/ if (ac < 1) { usage(); exit(1); } if (oflag && ac > 1) { usage(); exit(1); } while (ac > 0) { ret |= convbdf(av[0]); ++av; --ac; } exit(ret); } /* free font structure*/ void free_font(struct font* pf) { if (!pf) return; free(pf->name); free(pf->facename); free(pf->bits); free(pf->offset); free(pf->width); free(pf); } /* build incore structure from .bdf file*/ struct font* bdf_read_font(char *path) { FILE *fp; struct font* pf; fp = fopen(path, "rb"); if (!fp) { fprintf(stderr, "Error opening file: %s\n", path); return NULL; } pf = (struct font*)calloc(1, sizeof(struct font)); if (!pf) goto errout; pf->name = strdup(basename(path)); if (!bdf_read_header(fp, pf)) { fprintf(stderr, "Error reading font header\n"); goto errout; } if (!bdf_read_bitmaps(fp, pf)) { fprintf(stderr, "Error reading font bitmaps\n"); goto errout; } fclose(fp); return pf; errout: fclose(fp); free_font(pf); return NULL; } /* read bdf font header information, return 0 on error*/ int bdf_read_header(FILE *fp, struct font* pf) { int encoding; int nchars, maxwidth; int firstchar = 65535; int lastchar = -1; char buf[256]; char facename[256]; char copyright[256]; /* set certain values to errors for later error checking*/ pf->defaultchar = -1; pf->ascent = -1; pf->descent = -1; for (;;) { if (!bdf_getline(fp, buf, sizeof(buf))) { fprintf(stderr, "Error: EOF on file\n"); return 0; } if (isprefix(buf, "FONT ")) { /* not required*/ if (sscanf(buf, "FONT %[^\n]", facename) != 1) { fprintf(stderr, "Error: bad 'FONT'\n"); return 0; } pf->facename = strdup(facename); continue; } if (isprefix(buf, "COPYRIGHT ")) { /* not required*/ if (sscanf(buf, "COPYRIGHT \"%[^\"]", copyright) != 1) { fprintf(stderr, "Error: bad 'COPYRIGHT'\n"); return 0; } pf->copyright = strdup(copyright); continue; } if (isprefix(buf, "DEFAULT_CHAR ")) { /* not required*/ if (sscanf(buf, "DEFAULT_CHAR %d", &pf->defaultchar) != 1) { fprintf(stderr, "Error: bad 'DEFAULT_CHAR'\n"); return 0; } } if (isprefix(buf, "FONT_DESCENT ")) { if (sscanf(buf, "FONT_DESCENT %d", &pf->descent) != 1) { fprintf(stderr, "Error: bad 'FONT_DESCENT'\n"); return 0; } continue; } if (isprefix(buf, "FONT_ASCENT ")) { if (sscanf(buf, "FONT_ASCENT %d", &pf->ascent) != 1) { fprintf(stderr, "Error: bad 'FONT_ASCENT'\n"); return 0; } continue; } if (isprefix(buf, "FONTBOUNDINGBOX ")) { if (sscanf(buf, "FONTBOUNDINGBOX %d %d %d %d", &pf->fbbw, &pf->fbbh, &pf->fbbx, &pf->fbby) != 4) { fprintf(stderr, "Error: bad 'FONTBOUNDINGBOX'\n"); return 0; } continue; } if (isprefix(buf, "CHARS ")) { if (sscanf(buf, "CHARS %d", &nchars) != 1) { fprintf(stderr, "Error: bad 'CHARS'\n"); return 0; } continue; } /* * Reading ENCODING is necessary to get firstchar/lastchar * which is needed to pre-calculate our offset and widths * array sizes. */ if (isprefix(buf, "ENCODING ")) { if (sscanf(buf, "ENCODING %d", &encoding) != 1) { fprintf(stderr, "Error: bad 'ENCODING'\n"); return 0; } if (encoding >= 0 && encoding <= limit_char && encoding >= start_char) { if (firstchar > encoding) firstchar = encoding; if (lastchar < encoding) lastchar = encoding; } continue; } if (strequal(buf, "ENDFONT")) break; } /* calc font height*/ if (pf->ascent < 0 || pf->descent < 0 || firstchar < 0) { fprintf(stderr, "Error: Invalid BDF file, requires FONT_ASCENT/FONT_DESCENT/ENCODING\n"); return 0; } pf->height = pf->ascent + pf->descent; /* calc default char*/ if (pf->defaultchar < 0 || pf->defaultchar < firstchar || pf->defaultchar > limit_char ) pf->defaultchar = firstchar; /* calc font size (offset/width entries)*/ pf->firstchar = firstchar; pf->size = lastchar - firstchar + 1; /* use the font boundingbox to get initial maxwidth*/ /*maxwidth = pf->fbbw - pf->fbbx;*/ maxwidth = pf->fbbw; /* initially use font maxwidth * height for bits allocation*/ pf->bits_size = nchars * BITMAP_WORDS(maxwidth) * pf->height; /* allocate bits, offset, and width arrays*/ pf->bits = (uInt16 *)malloc(pf->bits_size * sizeof(uInt16) + EXTRA); pf->offset = (unsigned long *)malloc(pf->size * sizeof(unsigned long)); pf->width = (unsigned char *)malloc(pf->size * sizeof(unsigned char)); pf->bbx = (BBX *)malloc(pf->size * sizeof(BBX)); if (!pf->bits || !pf->offset || !pf->width) { fprintf(stderr, "Error: no memory for font load\n"); return 0; } return 1; } /* read bdf font bitmaps, return 0 on error*/ int bdf_read_bitmaps(FILE *fp, struct font* pf) { long ofs = 0; int maxwidth = 0; int i, k, encoding, width; int bbw, bbh, bbx, bby; int proportional = 0; int need_bbx = 0; int encodetable = 0; long l; char buf[256]; /* reset file pointer*/ fseek(fp, 0L, SEEK_SET); /* initially mark offsets as not used*/ for (i = 0; i < pf->size; ++i) pf->offset[i] = -1; for (;;) { if (!bdf_getline(fp, buf, sizeof(buf))) { fprintf(stderr, "Error: EOF on file\n"); return 0; } if (isprefix(buf, "STARTCHAR")) { encoding = width = bbw = bbh = bbx = bby = -1; continue; } if (isprefix(buf, "ENCODING ")) { if (sscanf(buf, "ENCODING %d", &encoding) != 1) { fprintf(stderr, "Error: bad 'ENCODING'\n"); return 0; } if (encoding < start_char || encoding > limit_char) encoding = -1; continue; } if (isprefix(buf, "DWIDTH ")) { if (sscanf(buf, "DWIDTH %d", &width) != 1) { fprintf(stderr, "Error: bad 'DWIDTH'\n"); return 0; } /* use font boundingbox width if DWIDTH <= 0*/ if (width <= 0) width = pf->fbbw - pf->fbbx; continue; } if (isprefix(buf, "BBX ")) { if (sscanf(buf, "BBX %d %d %d %d", &bbw, &bbh, &bbx, &bby) != 4) { fprintf(stderr, "Error: bad 'BBX'\n"); return 0; } continue; } if (strequal(buf, "BITMAP")) { uInt16 *ch_bitmap = pf->bits + ofs; int ch_words; if (encoding < 0) continue; /* set bits offset in encode map*/ if (pf->offset[encoding-pf->firstchar] != (unsigned long)-1) { fprintf(stderr, "Error: duplicate encoding for character %d (0x%02x), ignoring duplicate\n", encoding, encoding); continue; } pf->offset[encoding-pf->firstchar] = ofs; pf->width[encoding-pf->firstchar] = width; pf->bbx[encoding-pf->firstchar].w = bbw; pf->bbx[encoding-pf->firstchar].h = bbh; pf->bbx[encoding-pf->firstchar].x = bbx; pf->bbx[encoding-pf->firstchar].y = bby; if (width > maxwidth) maxwidth = width; /* clear bitmap*/ memset(ch_bitmap, 0, BITMAP_BYTES(bbw) * bbh); ch_words = BITMAP_WORDS(bbw); /* read bitmaps*/ for (i = 0; i < bbh; ++i) { if (!bdf_getline(fp, buf, sizeof(buf))) { fprintf(stderr, "Error: EOF reading BITMAP data\n"); return 0; } if (isprefix(buf, "ENDCHAR")) break; for (k = 0; k < ch_words; ++k) { uInt16 value; value = bdf_hexval((unsigned char *)buf); if (bbw > 8) { WRITE_UINT16(ch_bitmap, value); } else { WRITE_UINT16(ch_bitmap, value << 8); } ch_bitmap++; } } // If the default glyph is completely empty, the next // glyph will not be dumped. Work around this by // never generating completely empty glyphs. if (bbh == 0 && bbw == 0) { pf->bbx[encoding-pf->firstchar].w = 1; pf->bbx[encoding-pf->firstchar].h = 1; *ch_bitmap++ = 0; ofs++; } else { ofs += ch_words * bbh; } continue; } if (strequal(buf, "ENDFONT")) break; } /* set max width*/ pf->maxwidth = maxwidth; /* change unused offset/width values to default char values*/ for (i = 0; i < pf->size; ++i) { int defchar = pf->defaultchar - pf->firstchar; if (pf->offset[i] == (unsigned long)-1) { pf->offset[i] = pf->offset[defchar]; pf->width[i] = pf->width[defchar]; pf->bbx[i].w = pf->bbx[defchar].w; pf->bbx[i].h = pf->bbx[defchar].h; pf->bbx[i].x = pf->bbx[defchar].x; pf->bbx[i].y = pf->bbx[defchar].y; } } /* determine whether font doesn't require encode table*/ l = 0; for (i = 0; i < pf->size; ++i) { if (pf->offset[i] != l) { encodetable = 1; break; } l += BITMAP_WORDS(pf->bbx[i].w) * pf->bbx[i].h; } if (!encodetable) { free(pf->offset); pf->offset = NULL; } /* determine whether font is fixed-width*/ for (i = 0; i < pf->size; ++i) { if (pf->width[i] != maxwidth) { proportional = 1; break; } } if (!proportional) { free(pf->width); pf->width = NULL; } /* determine if the font needs a bbx table */ for (i = 0; i < pf->size; ++i) { if (pf->bbx[i].w != pf->fbbw || pf->bbx[i].h != pf->fbbh || pf->bbx[i].x != pf->fbbx || pf->bbx[i].y != pf->fbby) { need_bbx = 1; break; } } if (!need_bbx) { free(pf->bbx); pf->bbx = NULL; } /* reallocate bits array to actual bits used*/ if (ofs < pf->bits_size) { pf->bits = realloc(pf->bits, ofs * sizeof(uInt16)); pf->bits_size = ofs; } else { if (ofs > pf->bits_size) { fprintf(stderr, "Warning: DWIDTH spec > max FONTBOUNDINGBOX\n"); if (ofs > pf->bits_size+EXTRA) { fprintf(stderr, "Error: Not enough bits initially allocated\n"); return 0; } pf->bits_size = ofs; } } return 1; } /* read the next non-comment line, returns buf or NULL if EOF*/ char *bdf_getline(FILE *fp, char *buf, int len) { int c; char *b; for (;;) { b = buf; while ((c = getc(fp)) != EOF) { if (c == '\r') continue; if (c == '\n') break; if (b - buf >= (len - 1)) break; *b++ = c; } *b = '\0'; if (c == EOF && b == buf) return NULL; if (b != buf && !isprefix(buf, "COMMENT")) break; } return buf; } /* return hex value of buffer */ uInt16 bdf_hexval(unsigned char *buf) { uInt16 val = 0; unsigned char *ptr; for (ptr = buf; *ptr; ptr++) { int c = *ptr; if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'A' && c <= 'F') c = c - 'A' + 10; else if (c >= 'a' && c <= 'f') c = c - 'a' + 10; else c = 0; val = (val << 4) | c; } return val; } /* generate C source from in-core font*/ int gen_c_source(struct font* pf, char *path) { FILE *ofp; int h, i; int did_defaultchar = 0; int did_syncmsg = 0; time_t t = time(0); uInt16 *ofs = pf->bits; char buf[256]; char obuf[256]; char bbuf[256]; char hdr1[] = { "//============================================================================\n" "//\n" "// SSSS tt lll lll\n" "// SS SS tt ll ll\n" "// SS tttttt eeee ll ll aaaa\n" "// SSSS tt ee ee ll ll aa\n" "// SS tt eeeeee ll ll aaaaa -- \"An Atari 2600 VCS Emulator\"\n" "// SS SS tt ee ll ll aa aa\n" "// SSSS ttt eeeee llll llll aaaaa\n" "//\n" "// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony\n" "// and the Stella Team\n" "//\n" "// See the file \"License.txt\" for information on usage and redistribution of\n" "// this file, and for a DISCLAIMER OF ALL WARRANTIES.\n" "//\n" "// Generated by src/tools/convbdf on %s.\n" "//============================================================================\n" "\n" "#ifndef %s_FONT_DATA_HXX\n" "#define %s_FONT_DATA_HXX\n" "\n" "#include \"Font.hxx\"\n" "\n" "/* Font information:\n" " name: %s\n" " facename: %s\n" " w x h: %dx%d\n" " bbx: %d %d %d %d\n" " size: %d\n" " ascent: %d\n" " descent: %d\n" " first char: %d (0x%02x)\n" " last char: %d (0x%02x)\n" " default char: %d (0x%02x)\n" " proportional: %s\n" " %s\n" "*/\n" "\n" "namespace GUI {\n" "\n" "// Font character bitmap data.\n" "static const uInt16 %s_font_bits[] = {\n" }; ofp = fopen(path, "w"); if (!ofp) { fprintf(stderr, "Can't create %s\n", path); return 1; } strcpy(buf, ctime(&t)); buf[strlen(buf) - 1] = 0; fprintf(ofp, hdr1, buf, fontnameU, fontnameU, pf->name, pf->facename? pf->facename: "", pf->maxwidth, pf->height, pf->fbbw, pf->fbbh, pf->fbbx, pf->fbby, pf->size, pf->ascent, pf->descent, pf->firstchar, pf->firstchar, pf->firstchar+pf->size-1, pf->firstchar+pf->size-1, pf->defaultchar, pf->defaultchar, pf->width? "yes": "no", pf->copyright? pf->copyright: "", fontname); /* generate bitmaps*/ for (i = 0; i < pf->size; ++i) { int x; int bitcount = 0; int width = pf->bbx ? pf->bbx[i].w : pf->fbbw; int height = pf->bbx ? pf->bbx[i].h : pf->fbbh; int xoff = pf->bbx ? pf->bbx[i].x : pf->fbbx; int yoff = pf->bbx ? pf->bbx[i].y : pf->fbby; uInt16 *bits = pf->bits + (pf->offset? pf->offset[i]: (height * i)); uInt16 bitvalue = 0; /* * Generate bitmap bits only if not this index isn't * the default character in encode map, or the default * character hasn't been generated yet. */ if (pf->offset && (pf->offset[i] == pf->offset[pf->defaultchar-pf->firstchar])) { if (did_defaultchar) continue; did_defaultchar = 1; } fprintf(ofp, "\n/* Character %d (0x%02x):\n width %d\n bbx ( %d, %d, %d, %d )\n", i+pf->firstchar, i+pf->firstchar, pf->width ? pf->width[i+pf->firstchar] : pf->maxwidth, width, height, xoff, yoff); if (gen_map) { fprintf(ofp, "\n +"); for (x=0; x 0) { if (x == 0) fprintf(ofp, " |"); if (bitcount <= 0) { bitcount = BITMAP_BITSPERIMAGE; bitvalue = READ_UINT16(bits); bits++; } fprintf(ofp, BITMAP_TESTBIT(bitvalue)? "*": " "); bitvalue = BITMAP_SHIFTBIT(bitvalue); --bitcount; if (++x == width) { fprintf(ofp, "|\n"); --h; x = 0; bitcount = 0; } } fprintf(ofp, " +"); for (x = 0; x < width; ++x) fprintf(ofp, "-"); fprintf(ofp, "+\n*/\n"); } else fprintf(ofp, "\n*/\n"); bits = pf->bits + (pf->offset? pf->offset[i]: (height * i)); for (x = BITMAP_WORDS(width) * height; x > 0; --x) { fprintf(ofp, "0x%04x,\n", READ_UINT16(bits)); if (!did_syncmsg && *bits++ != *ofs++) { fprintf(stderr, "Warning: found encoding values in non-sorted order (not an error).\n"); did_syncmsg = 1; } } } fprintf(ofp, "};\n\n"); if (pf->offset) { /* output offset table*/ fprintf(ofp, "/* Character->glyph mapping. */\n" "static const uInt32 %s_sysfont_offset[] = {\n", fontname); for (i = 0; i < pf->size; ++i) fprintf(ofp, " %ld,\t/* (0x%02x) */\n", pf->offset[i], i+pf->firstchar); fprintf(ofp, "};\n\n"); } /* output width table for proportional fonts*/ if (pf->width) { fprintf(ofp, "/* Character width data. */\n" "static const unsigned char %s_sysfont_width[] = {\n", fontname); for (i = 0; i < pf->size; ++i) fprintf(ofp, " %d,\t/* (0x%02x) */\n", pf->width[i], i+pf->firstchar); fprintf(ofp, "};\n\n"); } /* output bbox table */ if (pf->bbx) { fprintf(ofp, "/* Bounding box data. */\n" "static const BBX %s_sysfont_bbx[] = {\n", fontname); for (i = 0; i < pf->size; ++i) fprintf(ofp, "\t{ %d, %d, %d, %d },\t/* (0x%02x) */\n", pf->bbx[i].w, pf->bbx[i].h, pf->bbx[i].x, pf->bbx[i].y, i+pf->firstchar); fprintf(ofp, "};\n\n"); } /* output struct font struct*/ if (pf->offset) sprintf(obuf, "%s_sysfont_offset,", fontname); else sprintf(obuf, "0, /* no encode table*/"); if (pf->width) sprintf(buf, "%s_sysfont_width,", fontname); else sprintf(buf, "0, /* fixed width*/"); if (pf->bbx) sprintf(bbuf, "%s_sysfont_bbx,", fontname); else sprintf(bbuf, "0, /* fixed bbox*/"); fprintf(ofp, "/* Exported structure definition. */\n" "static const FontDesc %sDesc = {\n" " \"%s\",\n" " %d,\n" " %d,\n" " %d, %d, %d, %d,\n" " %d,\n" " %d,\n" " %d,\n" " %s_font_bits,\n" " %s\n" " %s\n" " %s\n" " %d,\n" " sizeof(%s_font_bits)/sizeof(uInt16)\n" "};\n", fontname, pf->name, pf->maxwidth, pf->height, pf->fbbw, pf->fbbh, pf->fbbx, pf->fbby, pf->ascent, pf->firstchar, pf->size, fontname, obuf, buf, bbuf, pf->defaultchar, fontname); fprintf(ofp, "\n} // End of namespace GUI\n\n#endif\n"); fcloise(ofp); return 0; } stella-5.1.1/src/tools/create_props.pl000077500000000000000000000054371324334165500177760ustar00rootroot00000000000000#!/usr/bin/perl # Locate the 'PropSet' module use FindBin; use lib "$FindBin::Bin"; use PropSet; my $infile = ""; my $outfile = ""; if (@ARGV != 2) { if (@ARGV == 1 && $ARGV[0] == "-help") { usage(); } # Saves me from having to type these paths *every single time* $infile = "src/emucore/stella.pro"; $outfile = "src/emucore/DefProps.hxx"; } else { $infile = $ARGV[0]; $outfile = $ARGV[1]; } my %propset = PropSet::load_prop_set($infile); my $setsize = keys (%propset); my $typesize = PropSet::num_prop_types(); printf "Valid properties found: $setsize\n"; # Construct the output file in C++ format open(OUTFILE, ">$outfile"); print OUTFILE "//============================================================================\n"; print OUTFILE "//\n"; print OUTFILE "// SSSS tt lll lll\n"; print OUTFILE "// SS SS tt ll ll\n"; print OUTFILE "// SS tttttt eeee ll ll aaaa\n"; print OUTFILE "// SSSS tt ee ee ll ll aa\n"; print OUTFILE "// SS tt eeeeee ll ll aaaaa -- \"An Atari 2600 VCS Emulator\"\n"; print OUTFILE "// SS SS tt ee ll ll aa aa\n"; print OUTFILE "// SSSS ttt eeeee llll llll aaaaa\n"; print OUTFILE "//\n"; print OUTFILE "// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony\n"; print OUTFILE "// and the Stella Team\n"; print OUTFILE "//\n"; print OUTFILE "// See the file \"License.txt\" for information on usage and redistribution of\n"; print OUTFILE "// this file, and for a DISCLAIMER OF ALL WARRANTIES.\n"; print OUTFILE "//============================================================================\n"; print OUTFILE "\n"; print OUTFILE "#ifndef DEF_PROPS_HXX\n"; print OUTFILE "#define DEF_PROPS_HXX\n"; print OUTFILE "\n"; print OUTFILE "/**\n"; print OUTFILE " This code is generated using the 'create_props.pl' script,\n"; print OUTFILE " located in the src/tools directory. All properties changes\n"; print OUTFILE " should be made in stella.pro, and then this file should be\n"; print OUTFILE " regenerated and the application recompiled.\n"; print OUTFILE "*/\n"; print OUTFILE "\n#define DEF_PROPS_SIZE " . $setsize; print OUTFILE "\n\n"; print OUTFILE "static const char* const DefProps[DEF_PROPS_SIZE][" . $typesize . "] = {\n"; # Walk the hash map and print each item in order of md5sum my $idx = 0; for my $key ( sort keys %propset ) { print OUTFILE PropSet::build_prop_string(@{ $propset{$key} }); if ($idx+1 < $setsize) { print OUTFILE ","; } print OUTFILE "\n"; $idx++; } print OUTFILE "};\n"; print OUTFILE "\n"; print OUTFILE "#endif\n"; close(OUTFILE); sub usage { print "create_props.pl \n"; print "\n"; print "Convert the given properties file into a C++ compatible header file.\n"; exit(0); } stella-5.1.1/src/tools/evdev-joystick/000077500000000000000000000000001324334165500177055ustar00rootroot00000000000000stella-5.1.1/src/tools/evdev-joystick/80-stelladaptor-joystick.rules000066400000000000000000000012401324334165500255360ustar00rootroot00000000000000# Stelladaptor (Pixels Past / Stelladaptor 2600-to-USB Interface) KERNEL=="event*", NAME="input/%k", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="beef", ACTION=="add", RUN+="/usr/local/bin/evdev-joystick --e /dev/input/%k --d 0" # 2600-daptor (Microchip Technology Inc. / 2600-daptor) KERNEL=="event*", NAME="input/%k", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fa1d", ACTION=="add", RUN+="/usr/local/bin/evdev-joystick --e /dev/input/%k --d 0" # 2600-daptor II (Microchip Technology Inc. / 2600-daptor II) KERNEL=="event*", NAME="input/%k", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="f947", ACTION=="add", RUN+="/usr/local/bin/evdev-joystick --e /dev/input/%k --d 0" stella-5.1.1/src/tools/evdev-joystick/License.txt000066400000000000000000000431151324334165500220340ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. stella-5.1.1/src/tools/evdev-joystick/Makefile000066400000000000000000000004551324334165500213510ustar00rootroot00000000000000all : evdev-joystick evdev-joystick: evdev-joystick.c gcc -Wall -O2 -o evdev-joystick evdev-joystick.c install: evdev-joystick 80-stelladaptor-joystick.rules install -s evdev-joystick /usr/local/bin/ install -m 644 80-stelladaptor-joystick.rules /etc/udev/rules.d/ clean: rm -rf evdev-joystick stella-5.1.1/src/tools/evdev-joystick/Readme.txt000066400000000000000000000066011324334165500216460ustar00rootroot00000000000000EVDEV-JOYSTICK -------------- This program is based on G25manage, located at: https://github.com/VDrift/vdrift/tree/master/tools/G25manage It is developed by Stephen Anthony, and released under the GPL/v2. evdev-joystick is used to set the deadzone for Linux 'evdev' joystick devices. Currently, other than G25manage there is no other standalone program available to perform such calibration. This program was originally developed for Stella (https://stella-emu.github.io), an Atari 2600 emulator, and as such much of this document refers to Stella. The program itself can be used to calibrate any joystick for any application, though, and is not specific to Stella. Short Explanation (Stella users with Stelladaptor, 2600-daptor, etc.) ----------------- 1) Decompress the archive 2) Build the application by typing 'make' 3) Install it by typing 'sudo make install' 4) Unplug your 'daptor device, re-plug them, and play a game. Long Explanation (For the curious, or if something doesn't work, etc.) ---------------- 1) Decompress the archive 2) Build the application by typing 'make' 3) Type './evdev-joystick --l'. For me, it produces output as follows: /dev/input/by-id/usb-Microsoft_Inc._Controller_101F9B0-event-joystick /dev/input/by-id/usb-Microchip_Technology_Inc._2600-daptor_II-event-joystick /dev/input/by-id/usb-RetroUSB.com_SNES_RetroPort-event-joystick 4) Make note of the name of the device. For 2600-daptor II users, this would be: /dev/input/by-id/usb-Microchip_Technology_Inc._2600-daptor_II-event-joystick 5) Check the current deadzone (known as 'flatness') by typing: 'evdev-joystick --s ' Again, for me, this will output the following: Absolute axis 0x00 (0) (X Axis) (min: 0, max: 4095, flatness: 128 (=0.00%), fuzz: 15) Absolute axis 0x01 (1) (Y Axis) (min: 0, max: 4095, flatness: 128 (=0.00%), fuzz: 15) Absolute axis 0x02 (2) (Z Axis) (min: 0, max: 15, flatness: 0 (=0.00%), fuzz: 0) 6) Notice that the flatness/deadzone for axes 0 & 1 is 128. 7) Now, we change the deadzone by typing 'evdev-joystick --s --d 0' 8) Now check the current deadzone again by typing: 'evdev-joystick --s ' Absolute axis 0x00 (0) (X Axis) (min: 0, max: 4095, flatness: 0 (=0.00%), fuzz: 15) Absolute axis 0x01 (1) (Y Axis) (min: 0, max: 4095, flatness: 0 (=0.00%), fuzz: 15) Absolute axis 0x02 (2) (Z Axis) (min: 0, max: 15, flatness: 0 (=0.00%), fuzz: 0) 9) Note that the 'flatness' has changed to 0? If so, then the program is working as intended. 10) Note that there are other options to the program. You can change the 'fuzz' value, change attributes for only certain axis, etc. See the options by typing 'evdev-joystick'. 11) Once you're certain that the application is working, type 'sudo make install' to install it. RULES File ---------- Included in the archive is a udev .rules file that will automatically run evdev-joystick with the correct parameters for a Stelladaptor, 2600-daptor, and 2600-daptor II. If you have another joystick you wish to modify, simply add the proper entry to the .rules file. Note that it is necessary to add all joysticks (where you want to change the deadzone) to this file, since the settings are lost when the device is unplugged and plugged in again. When using a .rules file, the system will automatically re-run evdev-joystick and set your deadzone values again. stella-5.1.1/src/tools/evdev-joystick/evdev-joystick.c000066400000000000000000000272151324334165500230260ustar00rootroot00000000000000/** This program is based on G25manage, located at: https://github.com/VDrift/vdrift/tree/master/tools/G25manage This code is released under the GPLv2, and modified from the original by Stephen Anthony (sa666666@gmail.com). */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* this macro is used to tell if "bit" is set in "array" * it selects a byte from the array, and does a boolean AND * operation with a byte that only has the relevant bit set. * eg. to check for the 12th bit, we do (array[1] & 1<<4) */ #define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) // The default location for evdev devices in Linux #define EVDEV_DIR "/dev/input/by-id/" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void help() { printf("%s","Usage:\n\n" " --help, --h The message you're now reading\n" " --listdevs, --l List all joystick devices found\n" " --showcal, --s [path] Show current calibration for joystick device\n" " --evdev, --e [path] Set the joystick device to modify\n" " --deadzone, --d [val] Change deadzone for current joystick\n" " --fuzz, --f [val] Change fuzz for current joystick\n" " --axis, --a [val] The axis to modify for current joystick (by default, all axes)\n" "\n" "To see calibration information: \n" " evdev-joystick [ --s /path/to/event/device/file ]\n" "\n" "To set the deadzone values:\n" " evdev-joystick [ --e /path/to/event/device/file --d deadzone_value [ --a axis_index ] ]\n" "\n" "Example:\n" "\n" "I want to see the calibration values of my event managed joystick:\n" " evdev-joystick --s /dev/input/event6\n" "\n" "Supported Absolute axes:\n" " Absolute axis 0x00 (0) (X Axis) (min: 0, max: 16383, flatness: 1023 (=6.24%), fuzz: 63)\n" " Absolute axis 0x01 (1) (Y Axis) (min: 0, max: 255, flatness: 15 (=5.88%), fuzz: 0)\n" " Absolute axis 0x02 (2) (Z Axis) (min: 0, max: 255, flatness: 15 (=5.88%), fuzz: 0)\n" " Absolute axis 0x05 (5) (Z Rate Axis) (min: 0, max: 255, flatness: 15 (=5.88%), fuzz: 0)\n" " Absolute axis 0x10 (16) (Hat zero, x axis) (min: -1, max: 1, flatness: 0 (=0.00%), fuzz: 0)\n" " Absolute axis 0x11 (17) (Hat zero, y axis) (min: -1, max: 1, flatness: 0 (=0.00%), fuzz: 0)\n" "\n" "I want to get rid of the deadzone on all axes on my joystick:\n" " evdev-joystick --e /dev/input/event6 --d 0\n" "\n"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void listDevices() { DIR* dirp = opendir(EVDEV_DIR); struct dirent* dp; if(dirp == NULL) return; // Loop over dir entries using readdir int len = strlen("event-joystick"); while((dp = readdir(dirp)) != NULL) { // Only select names that end in 'event-joystick' int devlen = strlen(dp->d_name); if(devlen >= len) { const char* const start = dp->d_name + devlen - len; if(strncmp(start, "event-joystick", len) == 0) printf("%s%s\n", EVDEV_DIR, dp->d_name); } } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void printAxisType(int i) { switch(i) { case ABS_X : printf(" (X Axis) "); break; case ABS_Y : printf(" (Y Axis) "); break; case ABS_Z : printf(" (Z Axis) "); break; case ABS_RX : printf(" (X Rate Axis) "); break; case ABS_RY : printf(" (Y Rate Axis) "); break; case ABS_RZ : printf(" (Z Rate Axis) "); break; case ABS_THROTTLE : printf(" (Throttle) "); break; case ABS_RUDDER : printf(" (Rudder) "); break; case ABS_WHEEL : printf(" (Wheel) "); break; case ABS_GAS : printf(" (Accelerator) "); break; case ABS_BRAKE : printf(" (Brake) "); break; case ABS_HAT0X : printf(" (Hat zero, x axis) "); break; case ABS_HAT0Y : printf(" (Hat zero, y axis) "); break; case ABS_HAT1X : printf(" (Hat one, x axis) "); break; case ABS_HAT1Y : printf(" (Hat one, y axis) "); break; case ABS_HAT2X : printf(" (Hat two, x axis) "); break; case ABS_HAT2Y : printf(" (Hat two, y axis) "); break; case ABS_HAT3X : printf(" (Hat three, x axis) "); break; case ABS_HAT3Y : printf(" (Hat three, y axis) "); break; case ABS_PRESSURE : printf(" (Pressure) "); break; case ABS_DISTANCE : printf(" (Distance) "); break; case ABS_TILT_X : printf(" (Tilt, X axis) "); break; case ABS_TILT_Y : printf(" (Tilt, Y axis) "); break; case ABS_MISC : printf(" (Miscellaneous) "); break; default: printf(" (Unknown absolute feature) "); } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int showCalibration(const char* evdev) { int fd = -1, axisindex; uint8_t abs_bitmask[ABS_MAX/8 + 1]; float percent_deadzone; struct input_absinfo abs_features; if((fd = open(evdev, O_RDONLY)) < 0) { perror("evdev open"); return 1; } memset(abs_bitmask, 0, sizeof(abs_bitmask)); if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) < 0) perror("evdev ioctl"); printf("Supported Absolute axes:\n"); for(axisindex = 0; axisindex < ABS_MAX; ++axisindex) { if(test_bit(axisindex, abs_bitmask)) { // This means that the bit is set in the axes list printf(" Absolute axis 0x%02x (%d)", axisindex, axisindex); printAxisType(axisindex); if(ioctl(fd, EVIOCGABS(axisindex), &abs_features)) perror("evdev EVIOCGABS ioctl"); percent_deadzone = (float)abs_features.flat * 100 / (float)abs_features.maximum; printf("(min: %d, max: %d, flatness: %d (=%.2f%%), fuzz: %d)\n", abs_features.minimum, abs_features.maximum, abs_features.flat, percent_deadzone, abs_features.fuzz); } } close(fd); return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int setDeadzoneAndFuzz(const char* evdev, int axisindex, __s32 deadzonevalue, __s32 fuzzvalue) { int fd = -1; uint8_t abs_bitmask[ABS_MAX/8 + 1]; float percent_deadzone; struct input_absinfo abs_features; if ((fd = open(evdev, O_RDONLY)) < 0) { perror("evdev open"); return 1; } memset(abs_bitmask, 0, sizeof(abs_bitmask)); if(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bitmask)), abs_bitmask) < 0) perror("evdev ioctl"); int axis_first = 0, axis_last = ABS_MAX; if(axisindex >= 0 && axisindex < ABS_MAX) { axis_first = axisindex; axis_last = axisindex + 1; } for(axisindex = axis_first; axisindex < axis_last; ++axisindex) { if(test_bit(axisindex, abs_bitmask)) { /* this means that the bit is set in the axes list */ printf(" Absolute axis 0x%02x (%d)", axisindex, axisindex); printAxisType(axisindex); if(ioctl(fd, EVIOCGABS(axisindex), &abs_features)) { perror("evdev EVIOCGABS ioctl"); return 1; } if(deadzonevalue != -1) { if(deadzonevalue < abs_features.minimum || deadzonevalue > abs_features.maximum ) { printf("Deadzone value must be between %d and %d for this axis, " "value requested : %d\n", abs_features.minimum, abs_features.maximum, deadzonevalue); } printf("Setting deadzone value to : %d\n", deadzonevalue); abs_features.flat = deadzonevalue; } if(fuzzvalue != -1) { if(fuzzvalue < abs_features.minimum || fuzzvalue > abs_features.maximum ) { printf("Fuzz value must be between %d and %d for this axis, " "value requested : %d\n", abs_features.minimum, abs_features.maximum, fuzzvalue); } printf("Setting fuzz value to : %d\n", fuzzvalue); abs_features.fuzz = fuzzvalue; } if(ioctl(fd, EVIOCSABS(axisindex), &abs_features)) { perror("evdev EVIOCSABS ioctl"); return 1; } if(ioctl(fd, EVIOCGABS(axisindex), &abs_features)) { perror("evdev EVIOCGABS ioctl"); return 1; } percent_deadzone = (float)abs_features.flat * 100 / (float)abs_features.maximum; printf(" (min: %d, max: %d, flatness: %d (=%.2f%%), fuzz: %d)\n", abs_features.minimum, abs_features.maximum, abs_features.flat, percent_deadzone, abs_features.fuzz); } } close(fd); return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int main(int argc, char* argv[]) { char* evdevice = NULL; int c, axisindex = -1; __s32 flat = -1, fuzz = -1; // Show help by default if(argc == 1) { help(); exit(0); } while(1) { static struct option long_options[] = { { "help", no_argument, 0, 'h' }, { "listdevs", no_argument, 0, 'l' }, { "showcal", required_argument, 0, 's' }, { "evdev", required_argument, 0, 'e' }, { "deadzone", required_argument, 0, 'd' }, { "fuzz", required_argument, 0, 'f' }, { "axis", required_argument, 0, 'a' }, { 0, 0, 0, 0 } }; // getopt_long stores the option index here int option_index = 0; c = getopt_long(argc, argv, "h:l:s:e:d:f:a:", long_options, &option_index); // Detect the end of the options if(c == -1) break; switch(c) { case 0: // If this option set a flag, do nothing else now. if(long_options[option_index].flag != 0) break; printf("option %s", long_options[option_index].name); if(optarg) printf(" with arg %s", optarg); printf("\n"); break; case 'h': help(); break; case 'l': listDevices(); break; case 's': evdevice = optarg; showCalibration(evdevice); break; case 'e': evdevice = optarg; printf("Event device file: %s\n", evdevice); break; case 'd': flat = atoi(optarg); printf("New dead zone value: %d\n", flat); break; case 'f': fuzz = atoi(optarg); printf("New fuzz value: %d\n", fuzz); break; case 'a': axisindex = atoi(optarg); printf("Axis index to deal with: %d\n", axisindex); break; case '?': // getopt_long already printed an error message. break; default: abort(); } } // Print any remaining command line arguments (not options). if(optind < argc) { printf("non-option ARGV-elements: "); while(optind < argc) printf("%s ", argv[optind++]); putchar('\n'); } if(flat != -1 || fuzz != -1) { if(evdevice == NULL) { printf( "You must specify the event device for your joystick\n" ); exit(1); } else { if(axisindex == -1) { if(flat != -1) printf( "Trying to set all axes deadzone to: %d\n", flat); if(fuzz != -1) printf( "Trying to set all axes fuzz to: %d\n", fuzz); } else { if(flat != -1) printf( "Trying to set axis %d deadzone to: %d\n", axisindex, flat); if(fuzz != -1) printf( "Trying to set axis %d fuzz to: %d\n", axisindex, fuzz); } setDeadzoneAndFuzz(evdevice, axisindex, flat, fuzz); } } exit(0); } stella-5.1.1/src/tools/merge_props.pl000077500000000000000000000031711324334165500176230ustar00rootroot00000000000000#!/usr/bin/perl # Locate the 'PropSet' module use FindBin; use lib "$FindBin::Bin"; use PropSet; my $usr_file = ""; my $sys_file = ""; if (@ARGV != 2) { if (@ARGV == 1 && $ARGV[0] == "-help") { usage(); } # Saves me from having to type these paths *every single time* $usr_file = "$ENV{HOME}/.config/stella/stella.pro"; $sys_file = "src/emucore/stella.pro"; } else { $usr_file = $ARGV[0]; $sys_file = $ARGV[1]; } print "$usr_file\n"; my %usr_propset = PropSet::load_prop_set($usr_file); my %sys_propset = PropSet::load_prop_set($sys_file); print "\n"; print "Valid properties found in user file: " . keys (%usr_propset) . "\n"; print "Valid properties found in system file: " . keys (%sys_propset) . "\n"; # Determine which properties exist in both files for my $key ( keys %usr_propset ) { if (defined $sys_propset{$key}) { $sys_propset{$key} = $usr_propset{$key}; delete $usr_propset{$key}; } } print "\n"; print "Updated properties found in user file: " . keys (%usr_propset) . "\n"; print "Updated properties found in system file: " . keys (%sys_propset) . "\n"; print "\n"; # Write both files back to disk PropSet::save_prop_set($usr_file, \%usr_propset); PropSet::save_prop_set($sys_file, \%sys_propset); print "\nRun create_props [yN]: "; chomp ($input = ); if($input eq 'y') { system("./src/tools/create_props.pl"); } sub usage { print "merge_props.pl \n"; print "\n"; print "Scan both properties files, and for every entry found in both files,\n"; print "remove it from the USER file and overwrite it in the SYSTEM file.\n"; exit(0); } stella-5.1.1/src/tools/prune_snapshots.pl000077500000000000000000000035531324334165500205400ustar00rootroot00000000000000#!/usr/bin/perl use File::Basename; usage() if @ARGV < 2; my %builtin = (); my %directory = (); my @missing = (); my @delete = (); # Get all snapshot files from the built-in database in Stella # This data comes from 'stella -listrominfo' (first commandline arg) # We use a hashmap to get constant lookup time open(INFILE, "$ARGV[0]"); foreach $line () { if($line =~ /\|/) { chomp $line; ($md5, $name, $other) = split (/\|/, $line); $key = $name . ".png"; $builtin{$key} = $key; } } close(INFILE); # Get all snapshot files from the actual directory (second commandline arg) # We use a hashmap to get constant lookup time opendir(SNAPDIR, $ARGV[1]) or die "Directory '$ARGV[1]' not found\n"; my @files = grep !/^\.\.?$/, readdir SNAPDIR; close(SNAPDIR); foreach $file (@files) { ($base,$path,$type) = fileparse($file); $directory{$base} = $base; } # All files in %builtin but not in %directory are 'missing' snapshots while(($key, $value) = each(%builtin)) { if(!defined $directory{$key}) { push(@missing, $key); } } # All files in %directory but not in %builtin are redundant, and should be deleted while(($key, $value) = each(%directory)) { if(!defined $builtin{$key}) { $file = $ARGV[1] . "/" . $key; push(@delete, $file); } } $size = @missing; print "Missing snapshots: ($size)\n\n"; if($size > 0) { @missing = sort(@missing); foreach $file (@missing) { print "$file\n"; } } $size = @delete; print "\n\nExtra snapshots: ($size)\n\n"; if($size > 0) { @delete = sort(@delete); foreach $file (@delete) { print "$file\n"; } print "\nDelete extra snapshots [yN]: "; chomp ($input = ); if($input eq 'y') { foreach $file (@delete) { $cmd = "rm \"$file\""; system($cmd); } } } sub usage { print "prune_snapshots.pl [listrominfo data] [snapshot dir]\n"; exit(0); } stella-5.1.1/src/tools/rom_diff.pl000077500000000000000000000042531324334165500170700ustar00rootroot00000000000000#!/usr/bin/perl use File::Basename; usage() if @ARGV != 2; # Generate md5sums for source and destination directories my @src_files = `md5sum $ARGV[0]/*`; my @dest_files = `md5sum $ARGV[1]/*`; # Build hash for source ROMs my %src_md5 = (); foreach $file (@src_files) { chomp $file; ($md5, $name) = split(" ", $file); $src_md5{ $md5 } = $name; } print "Found " . keys( %src_md5 ) . " ROMs in " . $ARGV[0] . "\n"; # Build hash for destination ROMs my %dest_md5 = (); foreach $file (@dest_files) { chomp $file; ($md5, $name) = split(" ", $file); $dest_md5{ $md5 } = $name; } print "Found " . keys( %dest_md5 ) . " ROMs in " . $ARGV[1] . "\n"; my @added = (), @removed = (), @changed = (); # Check for added ROMs for my $key ( keys %dest_md5 ) { if (defined $src_md5{$key}) { ($src_rom,$path,$type) = fileparse($src_md5{$key}); ($dest_rom,$path,$type) = fileparse($dest_md5{$key}); if($src_rom ne $dest_rom) { push(@changed, $dest_md5{$key}); } } else { push(@added, $dest_md5{$key}); } } # Check for removed ROMs for my $key ( keys %src_md5 ) { if (!defined $dest_md5{$key}) { push(@removed, $src_md5{$key}); } } # Report our findings, create directories and copy files print "\n"; my $numAdded = @added; print "Added ROMs: $numAdded\n"; if ($numAdded > 0) { system("mkdir -p ADDED"); foreach $rom (@added) { system("cp \"$rom\" ADDED/"); } } my $numRemoved = @removed; print "Removed ROMs: $numRemoved\n"; if ($numRemoved > 0) { system("mkdir -p REMOVED"); foreach $rom (@removed) { system("cp \"$rom\" REMOVED/"); } } my $numChanged = @changed; print "Changed ROMs: $numChanged\n"; if ($numChanged > 0) { system("mkdir -p CHANGED"); foreach $rom (@changed) { system("cp \"$rom\" CHANGED/"); } } sub usage { print "rom_diff.pl \n"; print "\n"; print "Analyze the ROMs in both directories by md5sum and name.\n"; print "Three directories are created named 'ADDED', 'REMOVED' and 'CHANGED',\n"; print "indicating the differences in ROMs from the source and destination\n"; print "directories. ROMs are then copied into these new directories as specified.\n"; exit(0); } stella-5.1.1/src/tools/romtohex.cxx000066400000000000000000000024451324334165500173350ustar00rootroot00000000000000/** Simple program that produces a hex list of a binary object file @author Bradford W. Mott */ #include #include #include #include using namespace std; using uInt8 = unsigned char; using uInt32 = unsigned int; int main(int ac, char* av[]) { if(ac < 2) { cout << av[0] << " [values per line = 8] [startpos = 0]" << endl << endl << " Read data from INPUT_FILE, and convert to unsigned char" << endl << " (in hex format), writing to standard output." << endl << endl; return 0; } int values_per_line = ac >= 3 ? atoi(av[2]) : 8; int offset = ac >= 4 ? atoi(av[3]) : 0; ifstream in(av[1]); if(in.is_open()) { in.seekg(0, ios::end); int len = (int)in.tellg(); in.seekg(0, ios::beg); unique_ptr data = make_unique(len); in.read((char*)data.get(), len); in.close(); cout << "SIZE = " << len << endl << " "; // Skip first 'offset' bytes; they shouldn't be used for(int t = offset; t < len; ++t) { cout << "0x" << setw(2) << setfill('0') << hex << (int)data[t]; if(t < len - 1) cout << ", "; if(((t-offset) % values_per_line) == (values_per_line-1)) cout << endl << " "; } cout << endl; } } stella-5.1.1/src/tools/scrom.asm000066400000000000000000000121351324334165500165660ustar00rootroot00000000000000;;============================================================================ ;; ;; SSSS tt lll lll ;; SS SS tt ll ll ;; SS tttttt eeee ll ll aaaa ;; SSSS tt ee ee ll ll aa ;; SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" ;; SS SS tt ee ll ll aa aa ;; SSSS ttt eeeee llll llll aaaaa ;; ;; Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony ;; and the Stella Team ;; ;; See the file "License.txt" for information on usage and redistribution of ;; this file, and for a DISCLAIMER OF ALL WARRANTIES. ;;============================================================================ ;; ;; This file contains a "dummy" Supercharger BIOS for Stella. It is based ;; on routines developed by Eckhard Stolberg. ;; ;;============================================================================ processor 6502 VSYNC equ $00 VBLANK equ $01 WSYNC equ $02 COLUPF equ $08 COLUBK equ $09 CTRLPF equ $0a PF0 equ $0d PF1 equ $0e PF2 equ $0f RESP0 equ $10 RESP1 equ $11 AUDC0 equ $15 AUDF0 equ $17 AUDV0 equ $19 AUDV1 equ $1a GRP0 equ $1b GRP1 equ $1c ENAM0 equ $1d ENAM1 equ $1e ENABL equ $1f HMP0 equ $20 HMP1 equ $21 HMOVE equ $2a ;; ;; Entry point for multi-load reading ;; org $F800 LDA $FA ; Grab the load number and store it in $80 where the STA $80 ; emulator will grab it when it does the loading JMP clrp7 ; Go clear page 7 of RAM bank 1 like the real SC ;; ;; Entry point for initial load (invoked when the system is reset) ;; org $F80A start SEI CLD ;; ;; Clear page zero routine for initial load (e.g., RAM and TIA registers) ;; LDY #$00 LDX #$00 ilclr STY $00,X INX BNE ilclr JMP load ;; ;; Clear page 7 of RAM bank 1 (used for stars in the real SC) ;; clrp7 LDX #$00 LDA $F006,X LDA $FFF8 LDX #$00 mlclr3 LDA $F000 NOP LDA $F700,X DEX BNE mlclr3 JMP load ;; ;; NOTE: The emulator does the actual reading of the new load when the ;; next instruction is accessed. The emulator expects the load number to ;; to be stored in location $80. As a side-effect the emulator sets $80 ;; to contain the bank selection byte from the load's header and sets ;; $FE and $FF to contain the starting address from the load's header. ;; load org $F850 ;; ;; Copy code into page zero to do the bank switching ;; LDX #$03 copy LDY code,X STY $FA,X DEX BPL copy ;; ;; Clear some of the 2600's RAM and TIA registers like the real SC BIOS does ;; LDY #$00 LDX #$28 mlclr1 STY $04,X DEX BPL mlclr1 LDX #$1C mlclr2 STY $81,X DEX BPL mlclr2 ;; ;; Display the "emulated" Supercharger loading progress bar ;; ;; Check if we should skip the loading progress bar ;; Note that the following code seems to never do a jump ;; However, the comparison value can be patched outside this code ;; LDA #$FF CMP #$00 ; patch this value to $FF outside ROM to do a jump BNE startbars JMP skipbars ;; Otherwise we display them startbars: LDA #$00 STA GRP0 STA GRP1 STA ENAM0 STA ENAM1 STA ENABL STA AUDV0 STA AUDV1 STA COLUPF STA VBLANK LDA #$10 STA HMP1 STA WSYNC LDX #$07 DEX pos DEX BNE pos LDA #$00 STA HMP0 STA RESP0 STA RESP1 STA WSYNC STA HMOVE LDA #%00000101 STA CTRLPF LDA #$FF STA PF0 STA PF1 STA PF2 STA $84 STA $85 LDA #$F0 STA $83 LDA #$74 STA COLUBK LDA #$0C STA AUDC0 LDA #$1F STA AUDF0 STA $82 LDA #$07 STA AUDV0 a1 LDX #$08 LDY #$00 a2 STA WSYNC DEY BNE a2 STA WSYNC STA WSYNC LDA #$02 STA WSYNC STA VSYNC STA WSYNC STA WSYNC STA WSYNC LDA #$00 STA VSYNC DEX BPL a2 ASL $83 ROR $84 ROL $85 LDA $83 STA PF0 LDA $84 STA PF1 LDA $85 STA PF2 LDX $82 DEX STX $82 STX AUDF0 CPX #$0A BNE a1 LDA #%00000010 STA VBLANK LDX #$1C LDY #$00 STY AUDV0 STY COLUBK clear: STY $81,x DEX BPL clear skipbars: ;; ;; Setup value to be stored in the bank switching control register ;; LDX $80 CMP $F000,X ;; ;; Initialize A, X, Y, and SP registers ;; LDA #$9a ;; This is patched outside the ROM to a random value LDX #$FF LDY #$00 TXS ;; ;; Execute the code to do bank switch and start running cartridge code ;; JMP $FA code dc.b $cd, $f8, $ff ;; CMP $fff8 dc.b $4c ;; JMP $???? stella-5.1.1/src/unix/000077500000000000000000000000001324334165500145625ustar00rootroot00000000000000stella-5.1.1/src/unix/FSNodePOSIX.cxx000066400000000000000000000144221324334165500172520ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "FSNodePOSIX.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FilesystemNodePOSIX::setFlags() { struct stat st; _isValid = (0 == stat(_path.c_str(), &st)); if(_isValid) { _isDirectory = S_ISDIR(st.st_mode); _isFile = S_ISREG(st.st_mode); // Add a trailing slash, if necessary if (_isDirectory && _path.length() > 0 && _path[_path.length()-1] != '/') _path += '/'; } else _isDirectory = _isFile = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodePOSIX::FilesystemNodePOSIX() : _path("/"), // The root dir. _displayName(_path), _isValid(true), _isFile(false), _isDirectory(true) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodePOSIX::FilesystemNodePOSIX(const string& p, bool verify) : _isValid(true), _isFile(false), _isDirectory(true) { // Default to home directory _path = p.length() > 0 ? p : "~"; // Expand '~' to the HOME environment variable if(_path[0] == '~') { const char* home = getenv("HOME"); if (home != nullptr) _path.replace(0, 1, home); } // Get absolute path char buf[MAXPATHLEN]; if(realpath(_path.c_str(), buf)) _path = buf; _displayName = lastPathComponent(_path); if(verify) setFlags(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FilesystemNodePOSIX::getShortPath() const { // If the path starts with the home directory, replace it with '~' const char* home = getenv("HOME"); if(home != nullptr && BSPF::startsWithIgnoreCase(_path, home)) { string path = "~"; const char* offset = _path.c_str() + strlen(home); if(*offset != '/') path += "/"; path += offset; return path; } return _path; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode, bool hidden) const { assert(_isDirectory); DIR* dirp = opendir(_path.c_str()); struct dirent* dp; if (dirp == nullptr) return false; // loop over dir entries using readdir while ((dp = readdir(dirp)) != nullptr) { // Skip 'invisible' files if necessary if (dp->d_name[0] == '.' && !hidden) continue; // Skip '.' and '..' to avoid cycles if ((dp->d_name[0] == '.' && dp->d_name[1] == 0) || (dp->d_name[0] == '.' && dp->d_name[1] == '.')) continue; string newPath(_path); if (newPath.length() > 0 && newPath[newPath.length()-1] != '/') newPath += '/'; newPath += dp->d_name; FilesystemNodePOSIX entry(newPath, false); #if defined(SYSTEM_NOT_SUPPORTING_D_TYPE) /* TODO: d_type is not part of POSIX, so it might not be supported * on some of our targets. For those systems where it isn't supported, * add this #elif case, which tries to use stat() instead. * * The d_type method is used to avoid costly recurrent stat() calls in big * directories. */ entry.setFlags(); #else if (dp->d_type == DT_UNKNOWN) { // Fall back to stat() entry.setFlags(); } else { entry._isValid = (dp->d_type == DT_DIR) || (dp->d_type == DT_REG) || (dp->d_type == DT_LNK); if (dp->d_type == DT_LNK) { struct stat st; if (stat(entry._path.c_str(), &st) == 0) { entry._isDirectory = S_ISDIR(st.st_mode); entry._isFile = S_ISREG(st.st_mode); } else entry._isDirectory = entry._isFile = false; } else { entry._isDirectory = (dp->d_type == DT_DIR); entry._isFile = (dp->d_type == DT_REG); } if (entry._isDirectory) entry._path += "/"; } #endif // Skip files that are invalid for some reason (e.g. because we couldn't // properly stat them). if (!entry._isValid) continue; // Honor the chosen mode if ((mode == FilesystemNode::kListFilesOnly && !entry._isFile) || (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) continue; myList.emplace_back(new FilesystemNodePOSIX(entry)); } closedir(dirp); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodePOSIX::makeDir() { if(mkdir(_path.c_str(), 0777) == 0) { // Get absolute path char buf[MAXPATHLEN]; if(realpath(_path.c_str(), buf)) _path = buf; _displayName = lastPathComponent(_path); setFlags(); // Add a trailing slash, if necessary if (_path.length() > 0 && _path[_path.length()-1] != '/') _path += '/'; return true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodePOSIX::rename(const string& newfile) { if(std::rename(_path.c_str(), newfile.c_str()) == 0) { _path = newfile; // Get absolute path char buf[MAXPATHLEN]; if(realpath(_path.c_str(), buf)) _path = buf; _displayName = lastPathComponent(_path); setFlags(); // Add a trailing slash, if necessary if (_isDirectory && _path.length() > 0 && _path[_path.length()-1] != '/') _path += '/'; return true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AbstractFSNode* FilesystemNodePOSIX::getParent() const { if (_path == "/") return nullptr; const char* start = _path.c_str(); const char* end = lastPathComponent(_path); return new FilesystemNodePOSIX(string(start, size_t(end - start))); } stella-5.1.1/src/unix/FSNodePOSIX.hxx000066400000000000000000000065111324334165500172570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FS_NODE_POSIX_HXX #define FS_NODE_POSIX_HXX #include "FSNode.hxx" #ifdef MACOSX #include #endif #include #include #include #include #include #include #include #include #ifndef MAXPATHLEN // No MAXPATHLEN, as happens on Hurd #define MAXPATHLEN 1024 #endif /* * Implementation of the Stella file system API based on POSIX (for Linux and OSX) * * Parts of this class are documented in the base interface class, AbstractFSNode. */ class FilesystemNodePOSIX : public AbstractFSNode { public: /** * Creates a FilesystemNodePOSIX with the root node as path. */ FilesystemNodePOSIX(); /** * Creates a FilesystemNodePOSIX for a given path. * * @param path String with the path the new node should point to. * @param verify true if the isValid and isDirectory/isFile flags should * be verified during the construction. */ FilesystemNodePOSIX(const string& path, bool verify = true); bool exists() const override { return access(_path.c_str(), F_OK) == 0; } const string& getName() const override { return _displayName; } const string& getPath() const override { return _path; } string getShortPath() const override; bool isDirectory() const override { return _isDirectory; } bool isFile() const override { return _isFile; } bool isReadable() const override { return access(_path.c_str(), R_OK) == 0; } bool isWritable() const override { return access(_path.c_str(), W_OK) == 0; } bool makeDir() override; bool rename(const string& newfile) override; bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override; AbstractFSNode* getParent() const override; protected: string _path; string _displayName; bool _isValid; bool _isFile; bool _isDirectory; private: /** * Tests and sets the _isValid and _isDirectory/_isFile flags, * using the stat() function. */ virtual void setFlags(); /** * Returns the last component of a given path. * * Examples: * /foo/bar.txt would return /bar.txt * /foo/bar/ would return /bar/ * * @param str String containing the path. * @return Pointer to the first char of the last component inside str. */ static const char* lastPathComponent(const string& str) { if(str.empty()) return ""; const char* start = str.c_str(); const char* cur = start + str.size() - 2; while (cur >= start && *cur != '/') --cur; return cur + 1; } }; #endif stella-5.1.1/src/unix/OSystemUNIX.cxx000066400000000000000000000024721324334165500174220ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "OSystemUNIX.hxx" /** Each derived class is responsible for calling the following methods in its constructor: setBaseDir() setConfigFile() See OSystem.hxx for a further explanation */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystemUNIX::OSystemUNIX() : OSystem() { // Use XDG_CONFIG_HOME if defined, otherwise use the default const char* configDir = getenv("XDG_CONFIG_HOME"); if(configDir == nullptr) configDir = "~/.config"; string stellaDir = string(configDir) + "/stella"; setBaseDir(stellaDir); setConfigFile(stellaDir + "/stellarc"); } stella-5.1.1/src/unix/OSystemUNIX.hxx000066400000000000000000000024751324334165500174320ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef OSYSTEM_UNIX_HXX #define OSYSTEM_UNIX_HXX #include "OSystem.hxx" /** This class defines UNIX-like OS's (Linux) system specific settings. @author Stephen Anthony */ class OSystemUNIX : public OSystem { public: /** Create a new UNIX-specific operating system object */ OSystemUNIX(); virtual ~OSystemUNIX() = default; private: // Following constructors and assignment operators not supported OSystemUNIX(const OSystemUNIX&) = delete; OSystemUNIX(OSystemUNIX&&) = delete; OSystemUNIX& operator=(const OSystemUNIX&) = delete; OSystemUNIX& operator=(OSystemUNIX&&) = delete; }; #endif stella-5.1.1/src/unix/SerialPortUNIX.cxx000066400000000000000000000041401324334165500200750ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include #include #include #include #include #include #include #include "SerialPortUNIX.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortUNIX::SerialPortUNIX() : SerialPort(), myHandle(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortUNIX::~SerialPortUNIX() { closePort(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SerialPortUNIX::openPort(const string& device) { myHandle = open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); if(myHandle <= 0) return false; struct termios termios; memset(&termios, 0, sizeof(struct termios)); termios.c_cflag = CREAD | CLOCAL; termios.c_cflag |= B19200; termios.c_cflag |= CS8; tcflush(myHandle, TCIFLUSH); tcsetattr(myHandle, TCSANOW, &termios); return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SerialPortUNIX::closePort() { if(myHandle) { close(myHandle); myHandle = 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SerialPortUNIX::writeByte(const uInt8* data) { if(myHandle) { // cerr << "SerialPortUNIX::writeByte " << (int)(*data) << endl; return write(myHandle, data, 1) == 1; } return false; } stella-5.1.1/src/unix/SerialPortUNIX.hxx000066400000000000000000000036661324334165500201160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SERIALPORT_UNIX_HXX #define SERIALPORT_UNIX_HXX #include "SerialPort.hxx" /** Implement reading and writing from a serial port under UNIX. For now, it seems to be Linux-only, and reading isn't actually supported at all. @author Stephen Anthony */ class SerialPortUNIX : public SerialPort { public: SerialPortUNIX(); virtual ~SerialPortUNIX(); /** Open the given serial port with the specified attributes. @param device The name of the port @return False on any errors, else true */ bool openPort(const string& device) override; /** Close a previously opened serial port. */ void closePort() override; /** Write a byte to the serial port. @param data The byte to write to the port @return True if a byte was written, else false */ bool writeByte(const uInt8* data) override; private: // File descriptor for serial connection int myHandle; private: // Following constructors and assignment operators not supported SerialPortUNIX(const SerialPortUNIX&) = delete; SerialPortUNIX(SerialPortUNIX&&) = delete; SerialPortUNIX& operator=(const SerialPortUNIX&) = delete; SerialPortUNIX& operator=(SerialPortUNIX&&) = delete; }; #endif stella-5.1.1/src/unix/SettingsUNIX.cxx000066400000000000000000000015541324334165500176170ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "SettingsUNIX.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsUNIX::SettingsUNIX(OSystem& osystem) : Settings(osystem) { } stella-5.1.1/src/unix/SettingsUNIX.hxx000066400000000000000000000025701324334165500176230ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SETTINGS_UNIX_HXX #define SETTINGS_UNIX_HXX class OSystem; #include "Settings.hxx" /** This class defines UNIX-like OS's (Linux) system specific settings. @author Stephen Anthony */ class SettingsUNIX : public Settings { public: /** Create a new UNIX settings object */ SettingsUNIX(OSystem& osystem); virtual ~SettingsUNIX() = default; private: // Following constructors and assignment operators not supported SettingsUNIX() = delete; SettingsUNIX(const SettingsUNIX&) = delete; SettingsUNIX(SettingsUNIX&&) = delete; SettingsUNIX& operator=(const SettingsUNIX&) = delete; SettingsUNIX& operator=(SettingsUNIX&&) = delete; }; #endif stella-5.1.1/src/unix/module.mk000066400000000000000000000003431324334165500164000ustar00rootroot00000000000000MODULE := src/unix MODULE_OBJS := \ src/unix/FSNodePOSIX.o \ src/unix/OSystemUNIX.o \ src/unix/SerialPortUNIX.o \ src/unix/SettingsUNIX.o MODULE_DIRS += \ src/unix # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/unix/stella.desktop000066400000000000000000000002611324334165500174400ustar00rootroot00000000000000[Desktop Entry] Name=Stella Comment=A multi-platform Atari 2600 emulator Exec=stella %f Icon=stella Terminal=false Type=Application StartupNotify=true Categories=Emulator;Game; stella-5.1.1/src/unix/stella.spec000066400000000000000000000165331324334165500167320ustar00rootroot00000000000000%define name stella %define version 5.1.1 %define rel 1 %define enable_sound 1 %define enable_debugger 1 %define enable_joystick 1 %define enable_cheats 1 %define enable_static 0 %define release %rel Summary: An Atari 2600 Video Computer System emulator Name: %{name} Version: %{version} Release: %{release} Group: Emulators License: GPL URL: https://stella-emu.github.io Source: %{name}-%{version}.tar.xz BuildRoot: %_tmppath/%name-%version-%release-root BuildRequires: SDL2-devel MesaGLU-devel %description The Atari 2600 Video Computer System (VCS), introduced in 1977, was the most popular home video game system of the early 1980's. This emulator will run most Atari ROM images, so that you can play your favorite old Atari 2600 games on your PC. %prep %setup -q %build export CXXFLAGS=$RPM_OPT_FLAGS %configure \ %if %enable_sound --enable-sound \ %else --disable-sound \ %endif %if %enable_debugger --enable-debugger \ %else --disable-debugger \ %endif %if %enable_joystick --enable-joystick \ %else --disable-joystick \ %endif %if %enable_cheats --enable-cheats \ %else --disable-cheats \ %endif %if %enable_static --enable-static \ %else --enable-shared \ %endif --force-builtin-libpng \ --docdir=%{_docdir}/stella %make %install rm -rf $RPM_BUILD_ROOT make install-strip DESTDIR=%{buildroot} # Mandriva menu entries install -d -m0755 %{buildroot}%{_menudir} cat > %{buildroot}%{_menudir}/%{name} << EOF ?package(%{name}): command="stella" \ icon="stella.png" \ needs="x11" \ title="Stella" \ longtitle="A multi-platform Atari 2600 emulator" \ section="More Applications/Emulators" \ xdg="true" EOF %clean rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_DIR/%{name}-%{version} %post %update_menus %postun %clean_menus %files %defattr(-,root,root,-) %_bindir/* %{_menudir}/%{name} %{_datadir}/applications/%{name}.desktop %_docdir/stella/* %_datadir/icons/%{name}.png %_datadir/icons/mini/%{name}.png %_datadir/icons/large/%{name}.png %changelog * Wed Feb 21 2018 Stephen Anthony 5.1.1-1 - Version 5.1.1 release * Sun Feb 04 2018 Stephen Anthony 5.1-1 - Version 5.1 release * Sun Aug 20 2017 Stephen Anthony 5.0.2-1 - Version 5.0.2 release * Sun Jul 23 2017 Stephen Anthony 5.0.1-1 - Version 5.0.1 release * Sun Jul 16 2017 Stephen Anthony 5.0-1 - Version 5.0 release * Mon Nov 21 2016 Stephen Anthony 4.7.3-1 - Version 4.7.3 release * Fri Mar 25 2016 Stephen Anthony 4.7.2-1 - Version 4.7.2 release * Sat Feb 13 2016 Stephen Anthony 4.7.1-1 - Version 4.7.1 release * Mon Jan 25 2016 Stephen Anthony 4.7-1 - Version 4.7 release * Wed Oct 28 2015 Stephen Anthony 4.6.7-1 - Version 4.6.7 release * Sun Oct 11 2015 Stephen Anthony 4.6.6-1 - Version 4.6.6 release * Sat Sep 26 2015 Stephen Anthony 4.6.5-1 - Version 4.6.5 release * Wed Apr 22 2015 Stephen Anthony 4.6.1-1 - Version 4.6.1 release * Sat Mar 21 2015 Stephen Anthony 4.6-1 - Version 4.6 release * Thu Jan 1 2015 Stephen Anthony 4.5-1 - Version 4.5 release * Tue Oct 28 2014 Stephen Anthony 4.2-1 - Version 4.2 release * Sun Sep 14 2014 Stephen Anthony 4.1.1-1 - Version 4.1.1 release * Mon Sep 1 2014 Stephen Anthony 4.1-1 - Version 4.1 release * Tue Jul 1 2014 Stephen Anthony 4.0-1 - Version 4.0 release * Mon Jan 20 2014 Stephen Anthony 3.9.3-1 - Version 3.9.3 release * Sat Aug 31 2013 Stephen Anthony 3.9.2-1 - Version 3.9.2 release * Wed Aug 21 2013 Stephen Anthony 3.9.1-1 - Version 3.9.1 release * Thu Jun 27 2013 Stephen Anthony 3.9-1 - Version 3.9 release * Sun Mar 3 2013 Stephen Anthony 3.8.1-1 - Version 3.8.1 release * Thu Feb 21 2013 Stephen Anthony 3.8-1 - Version 3.8 release * Sat Dec 22 2012 Stephen Anthony 3.7.5-1 - Version 3.7.5 release * Wed Oct 31 2012 Stephen Anthony 3.7.4-1 - Version 3.7.4 release * Fri Oct 26 2012 Stephen Anthony 3.7.3-1 - Version 3.7.3 release * Sun Jun 10 2012 Stephen Anthony 3.7.2-1 - Version 3.7.2 release * Fri Jun 8 2012 Stephen Anthony 3.7.1-1 - Version 3.7.1 release * Fri Jun 1 2012 Stephen Anthony 3.7-1 - Version 3.7 release * Fri Mar 30 2012 Stephen Anthony 3.6.1-1 - Version 3.6.1 release * Fri Mar 16 2012 Stephen Anthony 3.6-1 - Version 3.6 release * Sat Feb 4 2012 Stephen Anthony 3.5.5-1 - Version 3.5.5 release * Thu Dec 29 2011 Stephen Anthony 3.5-1 - Version 3.5 release * Sat Jun 11 2011 Stephen Anthony 3.4.1-1 - Version 3.4.1 release * Sun May 29 2011 Stephen Anthony 3.4-1 - Version 3.4 release * Fri Nov 12 2010 Stephen Anthony 3.3-1 - Version 3.3 release * Wed Aug 25 2010 Stephen Anthony 3.2.1-1 - Version 3.2.1 release * Fri Aug 20 2010 Stephen Anthony 3.2-1 - Version 3.2 release * Mon May 3 2010 Stephen Anthony 3.1.2-1 - Version 3.1.2 release * Mon Apr 26 2010 Stephen Anthony 3.1.1-1 - Version 3.1.1 release * Thu Apr 22 2010 Stephen Anthony 3.1-1 - Version 3.1 release * Fri Sep 11 2009 Stephen Anthony 3.0-1 - Version 3.0 release * Thu Jul 4 2009 Stephen Anthony 2.8.4-1 - Version 2.8.4 release * Thu Jun 25 2009 Stephen Anthony 2.8.3-1 - Version 2.8.3 release * Tue Jun 23 2009 Stephen Anthony 2.8.2-1 - Version 2.8.2 release * Fri Jun 19 2009 Stephen Anthony 2.8.1-1 - Version 2.8.1 release * Tue Jun 9 2009 Stephen Anthony 2.8-1 - Version 2.8 release * Tue May 1 2009 Stephen Anthony 2.7.7-1 - Version 2.7.7 release * Tue Apr 14 2009 Stephen Anthony 2.7.6-1 - Version 2.7.6 release * Fri Mar 27 2009 Stephen Anthony 2.7.5-1 - Version 2.7.5 release * Mon Feb 9 2009 Stephen Anthony 2.7.3-1 - Version 2.7.3 release * Tue Jan 27 2009 Stephen Anthony 2.7.2-1 - Version 2.7.2 release * Mon Jan 26 2009 Stephen Anthony 2.7.1-1 - Version 2.7.1 release * Sat Jan 17 2009 Stephen Anthony 2.7-1 - Version 2.7 release * Thu May 22 2008 Stephen Anthony 2.6.1-1 - Version 2.6.1 release * Fri May 16 2008 Stephen Anthony 2.6-1 - Version 2.6 release * Wed Apr 9 2008 Stephen Anthony 2.5.1-1 - Version 2.5.1 release * Fri Mar 28 2008 Stephen Anthony 2.5-1 - Version 2.5 release * Mon Aug 27 2007 Stephen Anthony 2.4.1-1 - Version 2.4.1 release stella-5.1.1/src/windows/000077500000000000000000000000001324334165500152715ustar00rootroot00000000000000stella-5.1.1/src/windows/Create_Builds.bat000066400000000000000000000072731324334165500204770ustar00rootroot00000000000000@echo off & setlocal enableextensions echo Stella build script for creating win32 and x64 builds. echo This will create installers (based on InnoSetup) for both 32 and 64-bit, echo as well as a ZIP archive containing both versions. echo. echo ! InnoSetup must be linked to this directory as 'iscc.lnk' (for EXE files) echo ! 'zip.exe' must be installed in this directory (for ZIP files) echo ! 'flip.exe' must be be installed in this directory (for readable TXT files) echo. echo !!! Make sure the code has already been compiled in Visual Studio echo !!! before launching this command. echo. :: Make sure all tools are available set HAVE_ISCC=1 set HAVE_ZIP=1 set HAVE_FLIP=1 if not exist "iscc.lnk" ( echo InnoSetup 'iscc.lnk' not found - EXE files will not be created set HAVE_ISCC=0 ) if not exist "zip.exe" ( echo ZIP command not found - ZIP files will not be created set HAVE_ZIP=0 ) if %HAVE_ISCC% == 0 ( if %HAVE_ZIP% == 0 ( echo Both EXE and ZIP files cannot be created, exiting goto done ) ) if not exist "flip.exe" ( echo FLIP command not found - TXT files will be unreadable in Notepad set HAVE_FLIP=0 ) set RELEASE_32=Release set RELEASE_64=x64\Release echo. set /p STELLA_VER=Enter Stella version: echo. set /p TO_BUILD=Version to build (32/64/a=all): set BUILD_32=0 set BUILD_64=0 if %TO_BUILD% == 32 ( set BUILD_32=1 ) if %TO_BUILD% == 64 ( set BUILD_64=1 ) if %TO_BUILD% == a ( set BUILD_32=1 set BUILD_64=1 ) if %BUILD_32% == 1 ( if not exist %RELEASE_32% ( echo The 32-bit build was not found in the '%RELEASE_32%' directory goto done ) ) if %BUILD_64% == 1 ( if not exist %RELEASE_64% ( echo The 64-bit build was not found in the '%RELEASE_64%' directory goto done ) ) :: Create ZIP folder first set STELLA_DIR=Stella-%STELLA_VER% if exist %STELLA_DIR% ( echo Removing old %STELLA_DIR% directory rmdir /s /q %STELLA_DIR% ) echo Creating %STELLA_DIR% ... mkdir %STELLA_DIR% mkdir %STELLA_DIR%\32-bit mkdir %STELLA_DIR%\64-bit mkdir %STELLA_DIR%\docs if %BUILD_32% == 1 ( echo Copying 32-bit files ... copy %RELEASE_32%\Stella.exe %STELLA_DIR%\32-bit copy %RELEASE_32%\*.dll %STELLA_DIR%\32-bit ) if %BUILD_64% == 1 ( echo Copying 64-bit files ... copy %RELEASE_64%\Stella.exe %STELLA_DIR%\64-bit copy %RELEASE_64%\*.dll %STELLA_DIR%\64-bit ) echo Copying DOC files ... xcopy ..\..\docs\* %STELLA_DIR%\docs /s /q copy ..\..\Announce.txt %STELLA_DIR%\docs copy ..\..\Changes.txt %STELLA_DIR%\docs copy ..\..\Copyright.txt %STELLA_DIR%\docs copy ..\..\License.txt %STELLA_DIR%\docs copy ..\..\Readme.txt %STELLA_DIR%\docs copy ..\..\README-SDL.txt %STELLA_DIR%\docs copy ..\..\Todo.txt %STELLA_DIR%\docs if %HAVE_FLIP% == 1 ( for %%a in (%STELLA_DIR%\docs\*.txt) do ( flip -d "%%a" ) ) :: Create output directory for release files if not exist Output ( echo Creating output directory ... mkdir Output ) :: Actually create the ZIP file if %HAVE_ZIP% == 1 ( echo Creating ZIP file ... zip -q -r Output\%STELLA_DIR%-windows.zip %STELLA_DIR% ) :: Now create the Inno EXE files if %HAVE_ISCC% == 1 ( if %BUILD_32% == 1 ( echo Creating 32-bit EXE ... iscc.lnk "%CD%\stella.iss" /q "/dSTELLA_VER=%STELLA_VER%" "/dSTELLA_ARCH=win32" "/dSTELLA_PATH=%STELLA_DIR%\32-bit" "/dSTELLA_DOCPATH=%STELLA_DIR%\docs" ) if %BUILD_64% == 1 ( echo Creating 64-bit EXE ... iscc.lnk "%CD%\stella.iss" /q "/dSTELLA_VER=%STELLA_VER%" "/dSTELLA_ARCH=x64" "/dSTELLA_PATH=%STELLA_DIR%\64-bit" "/dSTELLA_DOCPATH=%STELLA_DIR%\docs" ) ) :: Cleanup time echo Cleaning up files, ... rmdir %STELLA_DIR% /s /q :done echo. pause 5stella-5.1.1/src/windows/FSNodeWINDOWS.cxx000066400000000000000000000206551324334165500202160ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #pragma warning( disable : 4091 ) #include #ifdef ARRAYSIZE #undef ARRAYSIZE #endif #include #include #include // winnt.h defines ARRAYSIZE, but we want our own one... #undef ARRAYSIZE // F_OK, R_OK and W_OK are not defined under MSVC, so we define them here // For more information on the modes used by MSVC, check: // http://msdn2.microsoft.com/en-us/library/1w06ktdy(VS.80).aspx #ifndef F_OK #define F_OK 0 #endif #ifndef R_OK #define R_OK 4 #endif #ifndef W_OK #define W_OK 2 #endif #include "FSNodeWINDOWS.hxx" /** * Returns the last component of a given path. * * Examples: * c:\foo\bar.txt would return "\bar.txt" * c:\foo\bar\ would return "\bar\" * * @param str Path to obtain the last component from. * @return Pointer to the first char of the last component inside str. */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const char* lastPathComponent(const string& str) { if(str.empty()) return ""; const char* start = str.c_str(); const char* cur = start + str.size() - 2; while(cur >= start && *cur != '\\') --cur; return cur + 1; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWINDOWS::exists() const { return _access(_path.c_str(), F_OK) == 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWINDOWS::isReadable() const { return _access(_path.c_str(), R_OK) == 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWINDOWS::isWritable() const { return _access(_path.c_str(), W_OK) == 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FilesystemNodeWINDOWS::setFlags() { // Get absolute path TCHAR buf[4096]; if(GetFullPathName(_path.c_str(), 4096, buf, NULL)) _path = buf; _displayName = lastPathComponent(_path); // Check whether it is a directory, and whether the file actually exists DWORD fileAttribs = GetFileAttributes(toUnicode(_path.c_str())); if(fileAttribs == INVALID_FILE_ATTRIBUTES) { _isDirectory = _isFile = _isValid = false; } else { _isDirectory = ((fileAttribs & FILE_ATTRIBUTE_DIRECTORY) != 0); _isFile = !_isDirectory;//((fileAttribs & FILE_ATTRIBUTE_NORMAL) != 0); _isValid = true; // Add a trailing backslash, if necessary if (_isDirectory && _path.length() > 0 && _path[_path.length()-1] != '\\') _path += '\\'; } _isPseudoRoot = false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FilesystemNodeWINDOWS::addFile(AbstractFSList& list, ListMode mode, const char* base, WIN32_FIND_DATA* find_data) { FilesystemNodeWINDOWS entry; char* asciiName = toAscii(find_data->cFileName); bool isDirectory, isFile; // Skip local directory (.) and parent (..) if(!strncmp(asciiName, ".", 1) || !strncmp(asciiName, "..", 2)) return; isDirectory = (find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? true : false); isFile = !isDirectory;//(find_data->dwFileAttributes & FILE_ATTRIBUTE_NORMAL ? true : false); if((isFile && mode == FilesystemNode::kListDirectoriesOnly) || (isDirectory && mode == FilesystemNode::kListFilesOnly)) return; entry._isDirectory = isDirectory; entry._isFile = isFile; entry._displayName = asciiName; entry._path = base; entry._path += asciiName; if(entry._isDirectory) entry._path += "\\"; entry._isValid = true; entry._isPseudoRoot = false; list.emplace_back(new FilesystemNodeWINDOWS(entry)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - char* FilesystemNodeWINDOWS::toAscii(TCHAR* str) { #ifndef UNICODE return (char*)str; #else static char asciiString[MAX_PATH]; WideCharToMultiByte(CP_ACP, 0, str, _tcslen(str) + 1, asciiString, sizeof(asciiString), NULL, NULL); return asciiString; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const TCHAR* FilesystemNodeWINDOWS::toUnicode(const char* str) { #ifndef UNICODE return (const TCHAR *)str; #else static TCHAR unicodeString[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, str, strlen(str) + 1, unicodeString, sizeof(unicodeString) / sizeof(TCHAR)); return unicodeString; #endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeWINDOWS::FilesystemNodeWINDOWS() { // Create a virtual root directory for standard Windows system _isDirectory = true; _isFile = false; _isValid = false; _path = ""; _isPseudoRoot = true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - FilesystemNodeWINDOWS::FilesystemNodeWINDOWS(const string& p) { // Default to home directory _path = p.length() > 0 ? p : "~"; // Expand '~' to the users 'home' directory if(_path[0] == '~') _path.replace(0, 1, myHomeFinder.getHomePath()); setFlags(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string FilesystemNodeWINDOWS::getShortPath() const { // If the path starts with the home directory, replace it with '~' const string& home = myHomeFinder.getHomePath(); if(home != "" && BSPF::startsWithIgnoreCase(_path, home)) { string path = "~"; const char* offset = _path.c_str() + home.length(); if(*offset != '\\') path += '\\'; path += offset; return path; } return _path; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWINDOWS:: getChildren(AbstractFSList& myList, ListMode mode, bool hidden) const { assert(_isDirectory); //TODO: honor the hidden flag if(_isPseudoRoot) { // Drives enumeration TCHAR drive_buffer[100]; GetLogicalDriveStrings(sizeof(drive_buffer) / sizeof(TCHAR), drive_buffer); for(TCHAR *current_drive = drive_buffer; *current_drive; current_drive += _tcslen(current_drive) + 1) { FilesystemNodeWINDOWS entry; char drive_name[2]; drive_name[0] = toAscii(current_drive)[0]; drive_name[1] = '\0'; entry._displayName = drive_name; entry._isDirectory = true; entry._isFile = false; entry._isValid = true; entry._isPseudoRoot = false; entry._path = toAscii(current_drive); myList.emplace_back(new FilesystemNodeWINDOWS(entry)); } } else { // Files enumeration WIN32_FIND_DATA desc; HANDLE handle; char searchPath[MAX_PATH + 10]; sprintf(searchPath, "%s*", _path.c_str()); handle = FindFirstFile(toUnicode(searchPath), &desc); if(handle == INVALID_HANDLE_VALUE) return false; addFile(myList, mode, _path.c_str(), &desc); while(FindNextFile(handle, &desc)) addFile(myList, mode, _path.c_str(), &desc); FindClose(handle); } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWINDOWS::makeDir() { if(!_isPseudoRoot && CreateDirectory(_path.c_str(), NULL) != 0) { setFlags(); return true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FilesystemNodeWINDOWS::rename(const string& newfile) { if(!_isPseudoRoot && MoveFile(_path.c_str(), newfile.c_str()) != 0) { setFlags(); return true; } else return false; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - AbstractFSNode* FilesystemNodeWINDOWS::getParent() const { if(_isPseudoRoot) return nullptr; if(_path.size() > 3) { const char* start = _path.c_str(); const char* end = lastPathComponent(_path); return new FilesystemNodeWINDOWS(string(start, size_t(end - start))); } else return new FilesystemNodeWINDOWS(); } stella-5.1.1/src/windows/FSNodeWINDOWS.hxx000066400000000000000000000074321324334165500202210ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef FS_NODE_WINDOWS_HXX #define FS_NODE_WINDOWS_HXX #include #include "FSNode.hxx" #include "HomeFinder.hxx" static HomeFinder myHomeFinder; // TODO - fix isFile() functionality so that it actually determines if something // is a file; for now, it assumes a file if it isn't a directory /* * Implementation of the Stella file system API based on Windows API. * * Parts of this class are documented in the base interface class, * AbstractFSNode. */ class FilesystemNodeWINDOWS : public AbstractFSNode { public: /** * Creates a FilesystemNodeWINDOWS with the root node as path. * * In regular windows systems, a virtual root path is used "". * In windows CE, the "\" root is used instead. */ FilesystemNodeWINDOWS(); /** * Creates a FilesystemNodeWINDOWS for a given path. * * Examples: * path=c:\foo\bar.txt, currentDir=false -> c:\foo\bar.txt * path=c:\foo\bar.txt, currentDir=true -> current directory * path=NULL, currentDir=true -> current directory * * @param path String with the path the new node should point to. */ FilesystemNodeWINDOWS(const string& path); bool exists() const override; const string& getName() const override { return _displayName; } const string& getPath() const override { return _path; } string getShortPath() const override; bool isDirectory() const override { return _isDirectory; } bool isFile() const override { return _isFile; } bool isReadable() const override; bool isWritable() const override; bool makeDir() override; bool rename(const string& newfile) override; bool getChildren(AbstractFSList& list, ListMode mode, bool hidden) const override; AbstractFSNode* getParent() const override; protected: string _displayName; string _path; bool _isDirectory; bool _isFile; bool _isPseudoRoot; bool _isValid; private: /** * Tests and sets the _isValid and _isDirectory/_isFile flags, * using the GetFileAttributes() function. */ virtual void setFlags(); /** * Adds a single FilesystemNodeWINDOWS to a given list. * This method is used by getChildren() to populate the directory entries list. * * @param list List to put the file entry node in. * @param mode Mode to use while adding the file entry to the list. * @param base String with the directory being listed. * @param find_data Describes a file that the FindFirstFile, FindFirstFileEx, or FindNextFile functions find. */ static void addFile(AbstractFSList& list, ListMode mode, const char* base, WIN32_FIND_DATA* find_data); /** * Converts a Unicode string to Ascii format. * * @param str String to convert from Unicode to Ascii. * @return str in Ascii format. */ static char* toAscii(TCHAR *str); /** * Converts an Ascii string to Unicode format. * * @param str String to convert from Ascii to Unicode. * @return str in Unicode format. */ static const TCHAR* toUnicode(const char* str); }; #endif stella-5.1.1/src/windows/HomeFinder.hxx000066400000000000000000000054571324334165500200550ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef __HOME_FINDER_ #define __HOME_FINDER_ #pragma warning( disable : 4091 ) #include /* * Used to determine the location of the various Win32 user/system folders. */ class HomeFinder { public: HomeFinder() = default; ~HomeFinder() = default; // Return the 'HOME/User' folder, or an empty string if the folder couldn't be determined. const string& getHomePath() const { if(ourHomePath == "") { char folder_path[MAX_PATH]; HRESULT const result = SHGetFolderPathA(NULL, CSIDL_PROFILE | CSIDL_FLAG_CREATE, NULL, 0, folder_path); ourHomePath = (result == S_OK) ? folder_path : EmptyString; } return ourHomePath; } // Return the 'APPDATA' folder, or an empty string if the folder couldn't be determined. const string& getAppDataPath() const { if(ourAppDataPath == "") { char folder_path[MAX_PATH]; HRESULT const result = SHGetFolderPathA(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, folder_path); ourAppDataPath = (result == S_OK) ? folder_path : EmptyString; } return ourAppDataPath; } // Return the 'My Documents' folder, or an empty string if the folder couldn't be determined. const string& getDocumentsPath() const { if(ourDocumentsPath == "") { char folder_path[MAX_PATH]; HRESULT const result = SHGetFolderPathA(NULL, CSIDL_MYDOCUMENTS | CSIDL_FLAG_CREATE, NULL, 0, folder_path); ourDocumentsPath = (result == S_OK) ? folder_path : EmptyString; } return ourDocumentsPath; } private: static string ourHomePath, ourAppDataPath, ourDocumentsPath; // Following constructors and assignment operators not supported HomeFinder(const HomeFinder&) = delete; HomeFinder(HomeFinder&&) = delete; HomeFinder& operator=(const HomeFinder&) = delete; HomeFinder& operator=(HomeFinder&&) = delete; }; __declspec(selectany) string HomeFinder::ourHomePath = ""; __declspec(selectany) string HomeFinder::ourAppDataPath = ""; __declspec(selectany) string HomeFinder::ourDocumentsPath = ""; #endif stella-5.1.1/src/windows/OSystemWINDOWS.cxx000066400000000000000000000055731324334165500205050ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "bspf.hxx" #include "FSNode.hxx" #include "HomeFinder.hxx" #include "OSystemWINDOWS.hxx" /** Each derived class is responsible for calling the following methods in its constructor: setBaseDir() setConfigFile() See OSystem.hxx for a further explanation */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - OSystemWINDOWS::OSystemWINDOWS() : OSystem() { string basedir = ""; // Check if the base directory should be overridden // Shouldn't normally be necessary, but is useful for those people that // don't want to clutter their 'My Documents' folder bool overrideBasedir = false; FilesystemNode basedirfile("basedir.txt"); if(basedirfile.exists()) { ifstream in(basedirfile.getPath()); if(in && in.is_open()) { getline(in, basedir); // trim leading and trailing spaces size_t spos = basedir.find_first_not_of(" \t"); size_t epos = basedir.find_last_not_of(" \t"); if(spos != string::npos && epos != string::npos) basedir = basedir.substr(spos, epos-spos+1); if(basedir != "") overrideBasedir = true; } } // If basedir hasn't been specified, use the 'home' directory if(!overrideBasedir) { HomeFinder homefinder; FilesystemNode appdata(homefinder.getAppDataPath()); if(appdata.isDirectory()) { basedir = appdata.getShortPath(); if(basedir.length() > 1 && basedir[basedir.length()-1] != '\\') basedir += '\\'; basedir += "Stella\\"; } else basedir = ".\\"; // otherwise, default to current directory } setBaseDir(basedir); setConfigFile(basedir + "stella.ini"); // Create default save/load dir FilesystemNode node(defaultSaveDir()); if(!node.exists()) node.makeDir(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemWINDOWS::defaultSaveDir() const { HomeFinder homefinder; FilesystemNode documents(homefinder.getDocumentsPath()); return documents.isDirectory() ? documents.getShortPath() + "\\Stella\\" : "~\\"; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - string OSystemWINDOWS::defaultLoadDir() const { return defaultSaveDir(); } stella-5.1.1/src/windows/OSystemWINDOWS.hxx000066400000000000000000000027371324334165500205110ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef OSYSTEM_WINDOWS_HXX #define OSYSTEM_WINDOWS_HXX #include "OSystem.hxx" /** This class defines Windows system specific settings. */ class OSystemWINDOWS : public OSystem { public: /** Create a new WINDOWS operating system object */ OSystemWINDOWS(); virtual ~OSystemWINDOWS() = default; public: /** Returns the default paths for loading/saving files. */ string defaultSaveDir() const override; string defaultLoadDir() const override; private: // Following constructors and assignment operators not supported OSystemWINDOWS(const OSystemWINDOWS&) = delete; OSystemWINDOWS(OSystemWINDOWS&&) = delete; OSystemWINDOWS& operator=(const OSystemWINDOWS&) = delete; OSystemWINDOWS& operator=(OSystemWINDOWS&&) = delete; }; #endif stella-5.1.1/src/windows/SerialPortWINDOWS.cxx000066400000000000000000000043061324334165500211570ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include #include "SerialPortWINDOWS.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortWINDOWS::SerialPortWINDOWS() : SerialPort(), myHandle(0) { } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SerialPortWINDOWS::~SerialPortWINDOWS() { closePort(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SerialPortWINDOWS::openPort(const string& device) { if(!myHandle) { myHandle = CreateFile(device.c_str(), GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(myHandle) { DCB dcb; FillMemory(&dcb, sizeof(dcb), 0); dcb.DCBlength = sizeof(dcb); if(!BuildCommDCB("19200,n,8,1", &dcb)) { closePort(); return false; } memset(&dcb, 0, sizeof(DCB)); dcb.BaudRate = CBR_19200; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; SetCommState(myHandle, &dcb); } else return false; } return true; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void SerialPortWINDOWS::closePort() { if(myHandle) { CloseHandle(myHandle); myHandle = 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool SerialPortWINDOWS::writeByte(const uInt8* data) { if(myHandle) { DWORD written; return WriteFile(myHandle, data, 1, &written, 0) == TRUE; } return false; } stella-5.1.1/src/windows/SerialPortWINDOWS.hxx000066400000000000000000000036011324334165500211610ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SERIALPORT_WINDOWS_HXX #define SERIALPORT_WINDOWS_HXX #include #include "SerialPort.hxx" /** Implement reading and writing from a serial port under Windows systems. */ class SerialPortWINDOWS : public SerialPort { public: SerialPortWINDOWS(); virtual ~SerialPortWINDOWS(); /** Open the given serial port with the specified attributes. @param device The name of the port @return False on any errors, else true */ bool openPort(const string& device) override; /** Close a previously opened serial port. */ void closePort() override; /** Write a byte to the serial port. @param data The byte to write to the port @return True if a byte was written, else false */ bool writeByte(const uInt8* data) override; private: // Handle to serial port HANDLE myHandle; private: // Following constructors and assignment operators not supported SerialPortWINDOWS(const SerialPortWINDOWS&) = delete; SerialPortWINDOWS(SerialPortWINDOWS&&) = delete; SerialPortWINDOWS& operator=(const SerialPortWINDOWS&) = delete; SerialPortWINDOWS& operator=(SerialPortWINDOWS&&) = delete; }; #endif stella-5.1.1/src/windows/SettingsWINDOWS.cxx000066400000000000000000000016301324334165500206700ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #include "SettingsWINDOWS.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SettingsWINDOWS::SettingsWINDOWS(OSystem& osystem) : Settings(osystem) { setInternal("fragsize", "1024"); } stella-5.1.1/src/windows/SettingsWINDOWS.hxx000066400000000000000000000024711324334165500207010ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef SETTINGS_WINDOWS_HXX #define SETTINGS_WINDOWS_HXX class OSystem; #include "Settings.hxx" class SettingsWINDOWS : public Settings { public: /** Create a new UNIX settings object */ SettingsWINDOWS(OSystem& osystem); virtual ~SettingsWINDOWS() = default; private: // Following constructors and assignment operators not supported SettingsWINDOWS() = delete; SettingsWINDOWS(const SettingsWINDOWS&) = delete; SettingsWINDOWS(SettingsWINDOWS&&) = delete; SettingsWINDOWS& operator=(const SettingsWINDOWS&) = delete; SettingsWINDOWS& operator=(SettingsWINDOWS&&) = delete; }; #endif stella-5.1.1/src/windows/Stella.sln000077500000000000000000000023131324334165500172350ustar00rootroot00000000000000Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Stella", "Stella.vcxproj", "{D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug|Win32.ActiveCfg = Debug|Win32 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug|Win32.Build.0 = Debug|Win32 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug|x64.ActiveCfg = Debug|x64 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Debug|x64.Build.0 = Debug|x64 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Release|Win32.ActiveCfg = Release|Win32 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Release|Win32.Build.0 = Release|Win32 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Release|x64.ActiveCfg = Release|x64 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal stella-5.1.1/src/windows/Stella.vcxproj000066400000000000000000001355431324334165500201450ustar00rootroot00000000000000 Debug Win32 Debug x64 Release Win32 Release x64 {D7FCEC7F-33E1-49DD-A4B0-D5FC222250AD} Stella Win32Proj 7.0 Application MultiByte v141_xp Application MultiByte v141_xp Application MultiByte v141_xp Application MultiByte v141_xp <_ProjectFileVersion>10.0.30319.1 Debug\ Debug\ true $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ true Release\ Release\ $(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ AllRules.ruleset AllRules.ruleset AllRules.ruleset AllRules.ruleset $(ProjectDir)\SDL\lib\x86;$(LibraryPath) $(ProjectDir)\SDL\include;$(IncludePath) $(ProjectDir)\SDL\lib\x86;$(LibraryPath) $(ProjectDir)\SDL\include;$(IncludePath) $(ProjectDir)\SDL\lib\x64;$(LibraryPath) $(ProjectDir)\SDL\include;$(IncludePath) $(ProjectDir)\SDL\lib\x64;$(LibraryPath) $(ProjectDir)\SDL\include;$(IncludePath) /MP /std:c++latest %(AdditionalOptions) Disabled ..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) BSPF_WINDOWS;WIN32;NDEBUG;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDLL Level2 EditAndContinue $(IntDir)%(RelativeDir) SDL2.lib;SDL2main.lib;SDL2main.lib;%(AdditionalDependencies) $(OutDir)Stella.exe true $(OutDir)Stella.pdb Console false MachineX86 Default X64 /MP /std:c++latest %(AdditionalOptions) Disabled ..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) BSPF_WINDOWS;WIN32;NDEBUG;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) false EnableFastChecks MultiThreadedDLL Level2 ProgramDatabase $(IntDir)%(RelativeDir) SDL2.lib;SDL2main.lib;SDL2main.lib;%(AdditionalDependencies) $(OutDir)Stella.exe true $(OutDir)Stella.pdb Console false MachineX64 Default /MP /std:c++latest %(AdditionalOptions) true false ..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) BSPF_WINDOWS;WIN32;NDEBUG;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) MultiThreadedDLL false Level2 ProgramDatabase $(IntDir)%(RelativeDir) SDL2.lib;SDL2main.lib;SDL2main.lib;%(AdditionalDependencies) $(OutDir)Stella.exe true Windows true true false MachineX86 Default X64 /MP /std:c++latest %(AdditionalOptions) Full Default true ..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;%(AdditionalIncludeDirectories) BSPF_WINDOWS;WIN32;NDEBUG;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions) MultiThreadedDLL false Level2 ProgramDatabase $(IntDir)%(RelativeDir) SDL2.lib;SDL2main.lib;%(AdditionalDependencies) $(OutDir)Stella.exe false Windows true true false MachineX64 Default stella-5.1.1/src/windows/Stella.vcxproj.filters000066400000000000000000002140071324334165500216050ustar00rootroot00000000000000 {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx {5188eb42-0dec-46ba-b181-46760495045d} {668555cd-5471-4274-8f88-ada71c1994ec} {65430770-f470-43b9-b3ee-0fb9c1b1048d} {e031c7d2-674c-472b-9a04-70707ac75a7e} {31501e98-40f8-4bcd-bf6f-52b133725061} {9ca218eb-55db-44fa-abba-f20cf9d69d48} {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hpp;hxx;hm;inl;inc;xsd {fe8200d9-0cf5-4591-8a11-74b7ac2d9095} {6e05e22d-63c1-469a-abd6-0c768e73f573} {22234c67-4cb3-43d1-ab09-94b81fc02aed} {ccb2b3e4-7db7-4397-8160-5a68059c656e} {6ae0e432-d0ce-419a-8909-bc4c03fc0e23} {b4ef4876-8f8c-4035-bc4a-0cbdbe2a5a44} {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx {81542c6c-60bf-4329-8243-f5caad4deffa} {ffa3642d-aa8a-43a5-8ac5-acd8878dd091} Source Files Source Files Source Files Source Files Source Files Source Files Source Files Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\cheat Source Files\cheat Source Files\cheat Source Files\cheat Source Files\cheat Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\gui Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\zlib Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\libpng Source Files\gui Source Files Source Files\emucore Source Files\emucore Source Files\emucore Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\emucore Source Files Source Files Source Files\emucore Source Files Source Files Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\gui Source Files\debugger Source Files\gui Source Files Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\emucore Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files Source Files\emucore Source Files\emucore Source Files\emucore Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\emucore Source Files\debugger Source Files\emucore Source Files Source Files\emucore Source Files\debugger Source Files\gui Source Files\debugger Source Files\emucore Source Files\debugger Source Files\debugger Source Files\emucore Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\debugger Source Files\debugger Source Files\emucore Source Files\emucore Source Files\debugger Source Files Source Files\emucore Source Files\gui Source Files\emucore Source Files Source Files Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\debugger Source Files\gui Source Files\debugger Source Files\gui Source Files\emucore Source Files\emucore Source Files\debugger Source Files\debugger Source Files\gui Source Files\gui Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\emucore\tia Source Files\gui Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\cheat Header Files\cheat Header Files\cheat Header Files\cheat Header Files\cheat Header Files\cheat Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\gui Header Files\zlib Header Files\zlib Header Files\zlib Header Files\zlib Header Files\zlib Header Files\zlib Header Files\zlib Header Files\zlib Header Files\zlib Header Files\zlib Header Files\zlib Header Files\libpng Header Files\libpng Header Files\libpng Header Files\libpng Header Files\libpng Header Files\libpng Header Files\libpng Header Files Header Files\gui Header Files Header Files\emucore Header Files\emucore Header Files\emucore Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files Header Files\emucore Header Files Header Files Header Files\emucore Header Files\emucore Header Files Header Files Header Files Header Files Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\gui Header Files Header Files\debugger Header Files\gui Header Files Header Files\gui Header Files\gui Header Files\gui Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files Header Files\emucore Header Files\emucore Header Files\emucore Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\emucore Header Files\debugger Header Files Header Files Header Files\emucore Header Files\debugger Header Files\gui Header Files\debugger Header Files\debugger Header Files\emucore Header Files\debugger Header Files\emucore Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore\tia Header Files\emucore Header Files\emucore Header Files\debugger Header Files\debugger Header Files\debugger Header Files\emucore\tia Header Files\emucore\tia Header Files Header Files\emucore Header Files\emucore Header Files\gui Header Files\emucore Header Files Header Files Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files\debugger Header Files Header Files\gui Header Files\emucore Header Files\emucore Header Files\emucore Header Files\emucore Header Files\debugger Header Files\debugger Header Files\gui Header Files\gui Header Files\gui Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\emucore\tia Header Files\gui Resource Files Resource Files stella-5.1.1/src/windows/module.mk000066400000000000000000000004351324334165500171110ustar00rootroot00000000000000MODULE := src/windows MODULE_OBJS := \ src/windows/FSNodeWINDOWS.o \ src/windows/OSystemWINDOWS.o \ src/windows/SerialPortWINDOWS.o \ src/windows/SettingsWINDOWS.o \ src/windows/stella_icon.o MODULE_DIRS += \ src/windows # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/windows/resource.h000066400000000000000000000006051324334165500172720ustar00rootroot00000000000000//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by stella.rc // // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1000 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif stella-5.1.1/src/windows/stella.ico000066400000000000000000003073661324334165500172700ustar00rootroot00000000000000 (f@@ (B00 %J  ^p  h(  (:FIA0 2NfuyoY<  7Vv^8 :Z|}S+ <] $ l? =_ "*A-J!6V-#?` )&F)K)I)Gm@'Cd (&I)L'I$H)H#5V,+Ii#%C&N)G)D%G%J)Dl?,Ln **E*K'I'F(E'F&G(H!5S*,Lo%'G*K(H(F'F'F'F'E'G'Di< 0Np *&A)K(H'G'E'F(F'F'F'F(G!7~Q) 6Ts *?+K)J(G'F'F'F'F(F'F'F'F'F'E i> ;[z%A)M)J(F'F'E'F(E'F'F'F(F'F'F(I!7V- =^ #:(H(K%I&F'F(F(E'F'F'F(E&G'F'E(G'Cm? =` .#G(I)F'F&H%H(F)D&G%I(E)D&G%H(E)D'H 3}N% !=`%23Q*O$G&F'F(E)D%H$H'F'F&G(F(E'F&F'F(E'G)G (U)  "?` ':LuHu1V)C(B&G%H'F&G%H'F'F'E'F'F'F'F'F'E'F)G%B P&  *5>@9+ $Bc!3RiT8\(D&B'E&H$I%H(F)E'F'E(E&F'F'E(E&F'F*I&F oB   /ATdnphS8 &Df $5Stu]?j&JA&C)D&G%H'F&G$H(E*C&G%H(E+C&G&K)H*W00DZozX3%Dg'9Yu{vfL~1W E!C)C)D&G$I%H&G(E'F'F'G'F)D+F'G)a; &?YqwL&  !Af *?]wytqm^Aj,O%C%B'E&G#I'E*C&G$I(E*C'G&K+I .fA" -Ig  d8 ;a  3L_wvsqpriO7_(G#A&C&F%I'E(E&G'F'F'E)H*L !5 jE$3Po&;5U=a ,@ zL$  7[  9Tdyvqqoqtn^Eq-S!D$B'F+M'L%I(E*B'F%K+J&6 oI($<Yw ,D7]:ce=j9d7a7^;c8])tE 0Sy 7MbyupqqnpoqsobJu0U%B"B$H)D)C&G%K*J $7U2 0On!>^Ft;i7_6\6\7\:a9`#? X-)Mt+8TvwqoprnpnqqqmW   >b (;CiDo8e4_5`6_6a6_6]6`6`6a6`6a7a;d8^9 !~]MY|&Iuqwropopopqpoorttstutn_m:j7g9gJ{fwuollklqvmYFs:c:c;hmYormkkkjmvqfR>i5`:g:g>i=i;h;h8f8g8d5_7d8`&F( " ':bkvqrnmqropqstttsprpggPz zK# %?]z.=dNM|KuJsFpAmAl@k=i:e7c5b6c6`3Y1W@oarolkkkkpvp_Gv9e8c:f;h;h;g;g;g;g;g;hi>h?kAmBoAm4U/   'K]wvqmqqmnrtttttqqsgfja *<h8,Lmj>h8c4b5c6e6e6a6[6X4U0S6aQkplkkkkqyseK|7e6b9e>i>i?j@k@kAl@kBoGt>f%>"%;cmxqopopoprtttsqq|uhhfi` #0`2,Mp.BjOL{KvIsFpEpBn@jjj9f9e7d5c6e6b6]6]7[7Z7Z5Y0T3W5Y1Q2R-N-NFofrnkkkmmtynZFr=g=g?jCnEpEqDpEpJvKwl>m;j7h8h8f6c7]6[6Y5W0S3X5Z1V3V1R-O,P1O4L0I'G6]\rqlkljks{q^JxAkCmFpFqEpEpGrFqDq@i'E!>Myvvoopstttttrp{wihfc`^`e Ip T( .h , @=9879;< @$G,N/V3^:c;d9`8[8[8\6Z2U3W1T-Q-Q,Q,Q/P-O*G'B?"E?hdrpkkkjlxoVFuDmEnCnDpGsFqAlAnBl0M*ISvtmotutttttqsiefec`_aaGq W* *w9ZCj@g;c6_0X*N#E>70+-29&B/J1R6Y:]:_;_7Y0R.R3S+N'M(L-H(I"H%D#C=)HFwisnklkjq{cOEoDmGqGsHsDo?jAmAn2U0QYwtoostttttsq|qffec`^^]`Hr Z, !] %4ankeb`ZQK{Cp8`*M"A8.)+2!=(G.Q7[5V.S.S0P.P,O'I'D&E(D*E(D#:8,RUrqlkkiit~r]IxAmGqGsGrCo@k@li?k@kAklbwtuttttttsr}ohhd_^]\^Z\O}h8'c ):bnihifihhlnoppneVGv6\'D3('.8#;+@+G)K'H$C"<5 7241WZrplopom{qZDqiAkAki=eCqcvutttsstsqr{igd^^_[YXU[P!p?/v 1HgoiiikifjigkmqspmeVHm2S9( $&+#6(C'@'<$;7!96-8:desmnrnlq}lP=h9c:e;g;h:e7aDrfywtttsttsoutffb[``YWVVZP 'zJ!  : Dkpkghkjgihgjiknmpspm`Jw/S:/'%,2!8 :"< :63,>Hvnsppoonst]Fr4`2^5b5b3`0\Aqh{wttttttspxnddb\\^ZTUVXP !1V* "Q '`qkhjjjgfjlllllmnprso_Iy4]%F1&#'1#; :75( %'JXtvononnzrU8f/[3_5b3`0\?mfzvtsttttrqkb^`^ZXVUVRTT 0Jc5-u 6RmpkljihhjiklhjkklmorsoaN9^'C- ")471) -6bfxspomoteFx4`1]4a4a0[;jd{wttttttqr~ga[[]]WU\VPSXAf rB : Jwnmkkkmmonomiikkkkkmosrk^Kz8X: ' !+4)%! ;Ixovtonnmzv\Do4_2_4a/[8h_ywtttttsptyb`^[Y[[WYUPQTGt R'  F  ?`IsHoIpSdiklnppqpnlkkklmorqj\Ap'M5..$%  ")LWsupnmno~tY?i1^3_0\6eZvwtttttsput_]^_[XYWRQRPPJ{ /c5 A  & #1 *; -C 6SQgnoqqpmllklnprqdS=e(L;.((! -9cgwtoopmrmKz4`0\0\5bVuxtttttspuo[[\\YWTTRQQOLM1QsD ):>?DXt  !. -D ?b[lpqqnllllnprpcK~6_.J%:+  =Otwrponnz|[>j1\/[3_M~pyuttttspulZ\[UUVSQQOPMI}NCoU+ !&.6=Hc  " ,A Ek_nqqpnlllnqqhXFq2V>,   #.U`wupoomosO8e0\/[AshzvttttspykYYZYWURQQOMJ~H|MK} %8h: $.;T ) 4NShprpnllmoqm_Fx3\(H 6$3BnnwqpoontaDt2`,W:jazwtsttspykWVYZUSRRSPLH|H{K~N6S{M&  !-@a  *= Encprpmkloqn]NCi3Q <) ''IXuusnpol}sS9g,W4dYvxtsttsovkVU[WSRQQPMI}H|H|J{O}Ejc7 #0Cj  %3 Elbqqnllmpmg[Fs4[&E/28\cwuopplskJ{1^1aQsyutttsovnWTXTSSRNMJ}G{H{IzItMxIu)<yL%  (=e $3 Hqgtqmlnrrm^Mo1bEzl{vtttspuqVRURQRQMLI|G|H{HwIsKvJx<^b6&:d  7PaqqmnsrsobR@j-I7(IQsvposruxR9j=nazwtttsputUQURQQOLJ}H|H}IyHtItKvLzFq$7wJ$ (C  %0JsitrtrsspfTBk*K!@7]autrttpykDz;jWvyuttsptxVQRQQNMJ~G{H|IzHsIrIsGrFsFt7Yb75h  8QcswrorsmeZDm,Q,QK|mutttqrX@pJ{lzusttqr{YOOQMMMI~H}I{HvHrIsItEpBmBp@m#7zN&  &F !0 Gmiwsrppnj\Bq0[:h^vyuttqttNCt\wwtttrp`OOQNMJ}H|I|IxItHsJtItEpBm@l?o2V f;2\  9Rkwtstqpm]Cr7dIzk{wstroygI{Omyuttrn}fPNPNJ|H{H|IyIwIuItJtGqBm@k=i:j9f1~R) %B 5Katvsqrrn]Cs;iRqyuttqqXK~`xwstsnzlPI}J~H}G{H|I{HvIvHuItHsDo@k;i7d6e9i4W j>:}#/KtlutqpqnZBrBr]vxutsounPUoxutsoywUI~HzGzH{IzIxItHsFqGrFqBn>j9f5c5c8c;c*BU, 0a  BcmytrsqlXCuJjyvtsro}`Pbwwssqu_NIzH{H|HyIuIsIsFqEpBm@kh?i?j9g4b5a6_6a6`6a6a6b6_6]6b6`6b8g;g*AY/&QTyvumltutsnr ghvyvn}%(uKn6b5a5b6d6`6]6a6a6a6`6a6a6a6`6a6_6^8d=i-K ^52  :Spxwwjrtssrs ndpyvnw ) wG{4b0]4b6c6_6]6b6a6a6`6b6`6a6`6a6_6]6b;f9b *xM' @ Eapv|oouuwtnw dewzro+[;k0]2a6`6`6`6a6`6a6_6a6_6^6a6`6a6a6b8c "R Bbmtmqwyxsquao{xq~tGx3a1]4]6`6b6`6a6`6a6`6`6_6a6`6`6`6b6a9f:d !2Y1(W  Gpoxxluwwyutlfw{rs \=l3\2]5^6`6`6a6`6a6`6a6a6_6a6_6]6a6`7c;i4WtI$ -j)7bv} onvwwuqv  fmzyr{ }P9f2^3]6]6`6`6a6`6`6_6`6`6a6_6]6a6a6b9e;g(?c7 ; Baou~jszustq}sbq~upkDx3a3^6^6a6a6a6`6b6_6^6a6`6`6`6b6`6a7a:h:b ,zM&  "P Wvv pkwzuwsqffyyqu !ZzM% 7 o2^2_5c6c6c6_6`6_6a6c6`6a7d8a%tI$ 7  =\ow #tiszwyvv $li{}t}*R9g2^4a6c6c6_6`6_6a6c6`7b8b#8X1 !M  Ktq|'onzxyyt) fn}xs%( pCu2_1^5b6c6c6c6d6c6^6a9i/O f> *j)8ex( nuzwxwv *rdt|wy-U4f/Z4`6b6c6c6d6c6`7c8`%wL'9 ;Ynx *"|py{{zt|(fi|~v( uCz0]2\5a6c6c6c6c7e8e %:\4 I  Jss,vs|{zwv& |guzv%b^4O&$W}vL{HxFxEvErEuFsIx4.)#} /?- 2j[`\TPJ}G|h~~hHuL|M|J{FyErIy@- %Zw gC2L`[WPL|FvEvDn@kw}}WGvJzKzM{N~P-N %6}z]S LJr`YVN|M{DuEwFsFmAiJy~~~qHxK{Q~QP~WFm&4YzyNnEJ([_XSN{HxEwFtEnEkGmFm=dg}}aJxQQTYNz$<Kwywx>Y> D#3e`[TQGxEwFwEnGmFn?h>f?cAg{}~~UN{WVYVBfyvv3H;3]1U4Y:`>jFtH{IxGnFm@i?h>f;c>_2TJv~mSVWVT1Sxywqv0F=lf\M{-M>cHqBi>f8a5Z1Y3V*J^~|_VYRQ=e|zytoq/IC D^|vV4\=7+M:^;`4Z7W4X-L-R}zRQQM~Gvzvpqo;WL rq}{|{~uX3S5;2K6Z0N*G?DqhKyO}M|N{xpojkBb\"0z}{z}f4^:4$C.M#F6aP@qCtDvytnlghOvs5Py~~||}h>`05B.E}qDsDuArtnnilbd4 L2H4MJlZa}~Z,R:0 &?kf?p?q{mpkicca$S  '0Lk &5Uzw~wQ|-M *)iK{=nllkhdb_]Act  B  4Jf~Z>`2'PlpEvEwFxEs@gD DSw5'QAqEvEvHz cy,0"EwCtFz.J4"9M'${5i>pHvT CRy9" $Q-y' |z,6+ uE  3G! ]ezhh @O':Qx^ !*NMVB7;9.$"???>????(0` % kZ"{*=(}4[2V u.2U4X3Y.<8&<5X4Y3X4Y0Rr ?,3Z2Y4Y4Y3X6\(8*( A>YS3V3Z2Y4W3Y4Y6[4<r@DLpk3[3W2Z3Y4X6["e[/H {9 NqO{.T4[4X4Y"4s(w;\JvN|2;. Gdt9a1V6\ $4#4-HsFsEqIs1RhFdZ7^"3#7%9VEtFsEsHv9a:T%6z6T(-<=:0@3MN}CqFtFsEtHw>h& `+?P!b%5tXCrEuFsEtGuDo+ 4Kt 5@`NqCf4R 1V}|N}GxFxFtFtIy3)/!1RM)@Y^UM~H|N~}oJyL{J{JyM}!A $_m2dBg\XO}JzFwErBiN~~YIzP~P~V:]4||X|#e U_UM|GxEuFoFkFm=cg}zO~QSYHr6XxzFdV =bJuJuKzI{HyFqDlBk=f?a>dv~gP}WXNzItwx=X^YIw7a%I$F3VDmDk>f7_4Z2THt~[WTN}Zyst:Z0a|b05aIyCtbpokhbY!-A5MLoWs|~[,Q7-_s?o[mlgcb&1 R+?Knb}wIu<%JTLihd_\Af=D*?c~a,PMwJ}eea[ZU s ?Ecxk3Yjisbc]Z[Y(A=+=doNbb]ZZZQAk v FIirezuiZZYUJzHy(>E-LlnzrY[XN}EwFqJu  3Ilu}Y[RFwFuEsHu2MV + @\hQ}JzEtFtEtEtFt&) 3_HzFvFtFuFtFtGu6Wa'ai  ~"]@pEtFuFtFtFsIy#:  I|ErEuFsFtEsGvEow @\ uCqFtEuFuFtEtIz0OA;_ OCrFtEtFtFtEtFsa (6~ ?oErFvFtFuEsDs)F Hd"eAqEtEsEsFu9_ A` $L~DvFuFvFt9 !,rx* xBsFwH{1a Ms&UCt9`& HfBs-L |)% _>Zb`k a 9G9VV{ ")(  ?|80?????( @ '" I*2V+J32T4X5[H>2W2Y4X3X,IaE'9a2Y3X4X+Id8 0L"4i6(5i/V4Y0NX)L{En:_$Cm1Q l-CL}ErEtBl _wr7.FbDrFsEtFs(CcY{? b,S{Nv8][O~IzFwIx1:  7X^P~GwEqO}vGwO}S =Vi T\N}EwFoEl?dl~^QW7\swYlZEj?i2Z/W?fFn=f8]2V~}VWCl}rSoevQ/P%H6W/NAlrO|KxuoX8y~k3V98cN@rojb O-A>XVuc)J0=lleb916PizAiBlco|hbZ:UAaO{n`b[[W2Xq^ZZXIz/K4mo{X[N}EuJv B2o zSFvFtEs8ZCDwFuFuFtJz T *x qCqEuFsEsAj"QtIyFtFuFtGw#;i"r @oFuFtEt@jw "/p aEtEsGw2!Ls@sFw8\W &x Ex ,n 6V7GkZsRwIl!(jDc{ Hp ??????(0 ` 8  1 ,M5\!0)2U3Z4Y-M~"  5$2qZ0U4X4);!3Eo8[y #include #include "y.tab.h" static YYSTYPE result; static string errMsg; void yyerror(const char* e); #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wold-style-cast" #pragma clang diagnostic ignored "-Wimplicit-fallthrough" #pragma clang diagnostic ignored "-Wmissing-variable-declarations" #include "y.tab.c" #pragma clang diagnostic pop #else #include "y.tab.c" #endif enum class State { DEFAULT, IDENTIFIER, OPERATOR, SPACE }; static State state = State::DEFAULT; static const char *input, *c; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const string& errorMessage() { return errMsg; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Expression* getResult() { lastExp = nullptr; return result.exp; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void setInput(const string& in) { input = c = in.c_str(); state = State::DEFAULT; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int parse(const string& in) { lastExp = nullptr; errMsg = "(no error)"; setInput(in); return yyparse(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // hand-rolled lexer. Hopefully faster than flex... inline bool is_base_prefix(char x) { return ( (x=='\\' || x=='$' || x=='#') ); } inline bool is_identifier(char x) { return ( (x>='0' && x<='9') || (x>='a' && x<='z') || (x>='A' && x<='Z') || x=='.' || x=='_' ); } inline bool is_operator(char x) { return ( (x=='+' || x=='-' || x=='*' || x=='/' || x=='<' || x=='>' || x=='|' || x=='&' || x=='^' || x=='!' || x=='~' || x=='(' || x==')' || x=='=' || x=='%' || x=='[' || x==']' ) ); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // const_to_int converts a string into a number, in either the // current base, or (if there's a base override) the selected base. // Returns -1 on error, since negative numbers are the parser's // responsibility, not the lexer's int const_to_int(char* ch) { // what base is the input in? Common::Base::Format format = Common::Base::format(); switch(*ch) { case '\\': format = Common::Base::F_2; ch++; break; case '#': format = Common::Base::F_10; ch++; break; case '$': format = Common::Base::F_16; ch++; break; default: // not a base_prefix, use default base break; } int ret = 0; switch(format) { case Common::Base::F_2: while(*ch) { if(*ch != '0' && *ch != '1') return -1; ret *= 2; ret += (*ch - '0'); ch++; } return ret; case Common::Base::F_10: while(*ch) { if(!isdigit(*ch)) return -1; ret *= 10; ret += (*ch - '0'); ch++; } return ret; case Common::Base::F_16: while(*ch) { // FIXME: error check! if(!isxdigit(*ch)) return -1; int dig = (*ch - '0'); if(dig > 9) dig = tolower(*ch) - 'a' + 10; ret *= 16; ret += dig; ch++; } return ret; default: cerr << "INVALID BASE in lexer!" << endl; return 0; } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // special methods that get Cart RAM/ROM internal state CartMethod getCartSpecial(char* ch) { if(BSPF::equalsIgnoreCase(ch, "_bank")) return &CartDebug::getBank; else if(BSPF::equalsIgnoreCase(ch, "_rwport")) return &CartDebug::readFromWritePort; else if(BSPF::equalsIgnoreCase(ch, "__lastread")) return &CartDebug::lastReadBaseAddress; else if(BSPF::equalsIgnoreCase(ch, "__lastwrite")) return &CartDebug::lastWriteBaseAddress; else return nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // special methods that get e.g. CPU registers CpuMethod getCpuSpecial(char* ch) { if(BSPF::equalsIgnoreCase(ch, "a")) return &CpuDebug::a; else if(BSPF::equalsIgnoreCase(ch, "x")) return &CpuDebug::x; else if(BSPF::equalsIgnoreCase(ch, "y")) return &CpuDebug::y; else if(BSPF::equalsIgnoreCase(ch, "pc")) return &CpuDebug::pc; else if(BSPF::equalsIgnoreCase(ch, "sp")) return &CpuDebug::sp; else if(BSPF::equalsIgnoreCase(ch, "c")) return &CpuDebug::c; else if(BSPF::equalsIgnoreCase(ch, "z")) return &CpuDebug::z; else if(BSPF::equalsIgnoreCase(ch, "n")) return &CpuDebug::n; else if(BSPF::equalsIgnoreCase(ch, "v")) return &CpuDebug::v; else if(BSPF::equalsIgnoreCase(ch, "d")) return &CpuDebug::d; else if(BSPF::equalsIgnoreCase(ch, "i")) return &CpuDebug::i; else if(BSPF::equalsIgnoreCase(ch, "b")) return &CpuDebug::b; else if(BSPF::equalsIgnoreCase(ch, "_icycles")) return &CpuDebug::icycles; else return nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // special methods that get TIA internal state TiaMethod getTiaSpecial(char* ch) { if(BSPF::equalsIgnoreCase(ch, "_scan")) return &TIADebug::scanlines; if(BSPF::equalsIgnoreCase(ch, "_scycles")) return &TIADebug::cyclesThisLine; else if(BSPF::equalsIgnoreCase(ch, "_fcount")) return &TIADebug::frameCount; else if(BSPF::equalsIgnoreCase(ch, "_fcycles")) return &TIADebug::frameCycles; else if(BSPF::equalsIgnoreCase(ch, "_cyclesLo")) return &TIADebug::cyclesLo; else if(BSPF::equalsIgnoreCase(ch, "_cyclesHi")) return &TIADebug::cyclesHi; else if(BSPF::equalsIgnoreCase(ch, "_cclocks")) return &TIADebug::clocksThisLine; else if(BSPF::equalsIgnoreCase(ch, "_vsync")) return &TIADebug::vsyncAsInt; else if(BSPF::equalsIgnoreCase(ch, "_vblank")) return &TIADebug::vblankAsInt; else return nullptr; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - int yylex() { static char idbuf[255]; char o, p; yylval.val = 0; while(*c != '\0') { switch(state) { case State::SPACE: yylval.val = 0; if(isspace(*c)) { c++; } else if(is_identifier(*c) || is_base_prefix(*c)) { state = State::IDENTIFIER; } else if(is_operator(*c)) { state = State::OPERATOR; } else { state = State::DEFAULT; } break; case State::IDENTIFIER: { CartMethod cartMeth; CpuMethod cpuMeth; TiaMethod tiaMeth; char *bufp = idbuf; *bufp++ = *c++; // might be a base prefix while(is_identifier(*c)) { // may NOT be base prefixes *bufp++ = *c++; } *bufp = '\0'; state = State::DEFAULT; // Note: specials (like "a" for accumulator) have priority over // numbers. So "a" always means accumulator, not hex 0xa. User // is welcome to use a base prefix ("$a"), or a capital "A", // to mean 0xa. // Also, labels have priority over specials, so Bad Things will // happen if the user defines a label that matches one of // the specials. Who would do that, though? if(Debugger::debugger().cartDebug().getAddress(idbuf) > -1) { yylval.Equate = idbuf; return EQUATE; } else if( (cpuMeth = getCpuSpecial(idbuf)) ) { yylval.cpuMethod = cpuMeth; return CPU_METHOD; } else if( (cartMeth = getCartSpecial(idbuf)) ) { yylval.cartMethod = cartMeth; return CART_METHOD; } else if( (tiaMeth = getTiaSpecial(idbuf)) ) { yylval.tiaMethod = tiaMeth; return TIA_METHOD; } else if( Debugger::debugger().getFunctionDef(idbuf) != EmptyString ) { yylval.DefinedFunction = idbuf; return FUNCTION; } else { yylval.val = const_to_int(idbuf); if(yylval.val >= 0) return NUMBER; else return ERR; } } case State::OPERATOR: o = *c++; if(!*c) return o; if(isspace(*c)) { state = State::SPACE; return o; } else if(is_identifier(*c) || is_base_prefix(*c)) { state = State::IDENTIFIER; return o; } else { state = State::DEFAULT; p = *c++; if(o == '>' && p == '=') return GTE; else if(o == '<' && p == '=') return LTE; else if(o == '!' && p == '=') return NE; else if(o == '=' && p == '=') return EQ; else if(o == '|' && p == '|') return LOG_OR; else if(o == '&' && p == '&') return LOG_AND; else if(o == '<' && p == '<') return SHL; else if(o == '>' && p == '>') return SHR; else { c--; return o; } } // break; Never executed case State::DEFAULT: yylval.val = 0; if(isspace(*c)) { state = State::SPACE; } else if(is_identifier(*c) || is_base_prefix(*c)) { state = State::IDENTIFIER; } else if(is_operator(*c)) { state = State::OPERATOR; } else { yylval.val = *c++; return yylval.val; } break; } } return 0; // hit NUL, end of input. } } // namespace YaccParser stella-5.1.1/src/yacc/YaccParser.hxx000066400000000000000000000023241324334165500173040ustar00rootroot00000000000000//============================================================================ // // SSSS tt lll lll // SS SS tt ll ll // SS tttttt eeee ll ll aaaa // SSSS tt ee ee ll ll aa // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" // SS SS tt ee ll ll aa aa // SSSS ttt eeeee llll llll aaaaa // // Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony // and the Stella Team // // See the file "License.txt" for information on usage and redistribution of // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ #ifndef PARSER_HXX #define PARSER_HXX #include "Expression.hxx" #include "CartDebug.hxx" #include "CpuDebug.hxx" #include "TIADebug.hxx" #include "bspf.hxx" // FIXME - Convert this to a proper C++ class using Bison and Flex C++ mode namespace YaccParser { Expression* getResult(); const string& errorMessage(); void setInput(const string& in); int parse(const string& in); int const_to_int(char* ch); CartMethod getCartSpecial(char* ch); CpuMethod getCpuSpecial(char* ch); TiaMethod getTiaSpecial(char* ch); } #endif stella-5.1.1/src/yacc/calctest.c000066400000000000000000000010371324334165500164650ustar00rootroot00000000000000 #include #include #include "YaccParser.hxx" //extern int YaccParser::yyparse(); //extern void YaccParser::set_input(const char *); //extern int yyrestart(FILE *); int main(int argc, char **argv) { #ifndef BM YaccParser::parse(argv[1]); printf("\n= %d\n", YaccParser::getResult()->evaluate()); #else char buf[30]; sprintf(buf, "1+2+3+4+5+6+7"); YaccParser::parse(buf); Expression *e = YaccParser::getResult(); for(int i=0; i<100000000; i++) { // printf("%d\n", e->evaluate()); e->evaluate(); } #endif } stella-5.1.1/src/yacc/module.mk000066400000000000000000000002201324334165500163260ustar00rootroot00000000000000MODULE := src/yacc MODULE_OBJS := \ src/yacc/YaccParser.o MODULE_DIRS += \ src/yacc # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/yacc/stella.y000066400000000000000000000121051324334165500161730ustar00rootroot00000000000000%{ #include Expression* lastExp = nullptr; #define YYERROR_VERBOSE 1 /* dump Expression stack during parsing? */ #define DEBUG_EXP 0 int yylex(); char *yytext; void yyerror(const char *e) { //if(DEBUG_EXP) fprintf(stderr, "%s at token \"%s\"\n", e, yytext); if(DEBUG_EXP) fprintf(stderr, "%s\n", e); errMsg = e; // be extra paranoid about deletion if(lastExp && reinterpret_cast(lastExp)) delete lastExp; lastExp = nullptr; } %} %union { int val; char* Equate; CartMethod cartMethod; CpuMethod cpuMethod; TiaMethod tiaMethod; Expression* exp; char* DefinedFunction; } /* Terminals */ %token NUMBER %token ERR %token EQUATE %token CART_METHOD %token CPU_METHOD %token TIA_METHOD %token FUNCTION /* Non-terminals */ %type expression /* Operator associativity and precedence */ %left '-' '+' %left '*' '/' '%' %left LOG_OR %left LOG_AND %left LOG_NOT %left '|' '^' %left '&' %left SHR SHL %nonassoc '<' '>' GTE LTE NE EQ %nonassoc DEREF %nonassoc UMINUS %nonassoc '[' %% statement: expression { if(DEBUG_EXP) fprintf(stderr, "\ndone\n"); result.exp = $1; } ; expression: expression '+' expression { if(DEBUG_EXP) fprintf(stderr, " +"); $$ = new PlusExpression($1, $3); lastExp = $$; } | expression '-' expression { if(DEBUG_EXP) fprintf(stderr, " -"); $$ = new MinusExpression($1, $3); lastExp = $$; } | expression '*' expression { if(DEBUG_EXP) fprintf(stderr, " *"); $$ = new MultExpression($1, $3); lastExp = $$; } | expression '/' expression { if(DEBUG_EXP) fprintf(stderr, " /"); $$ = new DivExpression($1, $3); lastExp = $$; } | expression '%' expression { if(DEBUG_EXP) fprintf(stderr, " %%"); $$ = new ModExpression($1, $3); lastExp = $$; } | expression '&' expression { if(DEBUG_EXP) fprintf(stderr, " &"); $$ = new BinAndExpression($1, $3); lastExp = $$; } | expression '|' expression { if(DEBUG_EXP) fprintf(stderr, " |"); $$ = new BinOrExpression($1, $3); lastExp = $$; } | expression '^' expression { if(DEBUG_EXP) fprintf(stderr, " ^"); $$ = new BinXorExpression($1, $3); lastExp = $$; } | expression '<' expression { if(DEBUG_EXP) fprintf(stderr, " <"); $$ = new LessExpression($1, $3); lastExp = $$; } | expression '>' expression { if(DEBUG_EXP) fprintf(stderr, " >"); $$ = new GreaterExpression($1, $3); lastExp = $$; } | expression GTE expression { if(DEBUG_EXP) fprintf(stderr, " >="); $$ = new GreaterEqualsExpression($1, $3); lastExp = $$; } | expression LTE expression { if(DEBUG_EXP) fprintf(stderr, " <="); $$ = new LessEqualsExpression($1, $3); lastExp = $$; } | expression NE expression { if(DEBUG_EXP) fprintf(stderr, " !="); $$ = new NotEqualsExpression($1, $3); lastExp = $$; } | expression EQ expression { if(DEBUG_EXP) fprintf(stderr, " =="); $$ = new EqualsExpression($1, $3); lastExp = $$; } | expression SHR expression { if(DEBUG_EXP) fprintf(stderr, " >>"); $$ = new ShiftRightExpression($1, $3); lastExp = $$; } | expression SHL expression { if(DEBUG_EXP) fprintf(stderr, " <<"); $$ = new ShiftLeftExpression($1, $3); lastExp = $$; } | expression LOG_OR expression { if(DEBUG_EXP) fprintf(stderr, " ||"); $$ = new LogOrExpression($1, $3); lastExp = $$; } | expression LOG_AND expression { if(DEBUG_EXP) fprintf(stderr, " &&"); $$ = new LogAndExpression($1, $3); lastExp = $$; } | '-' expression %prec UMINUS { if(DEBUG_EXP) fprintf(stderr, " U-"); $$ = new UnaryMinusExpression($2); lastExp = $$; } | '~' expression %prec UMINUS { if(DEBUG_EXP) fprintf(stderr, " ~"); $$ = new BinNotExpression($2); lastExp = $$; } | '!' expression %prec UMINUS { if(DEBUG_EXP) fprintf(stderr, " !"); $$ = new LogNotExpression($2); lastExp = $$; } | '*' expression %prec DEREF { if(DEBUG_EXP) fprintf(stderr, " U*"); $$ = new ByteDerefExpression($2); lastExp = $$; } | '@' expression %prec DEREF { if(DEBUG_EXP) fprintf(stderr, " U@"); $$ = new WordDerefExpression($2); lastExp = $$; } | '<' expression { if(DEBUG_EXP) fprintf(stderr, " U<"); $$ = new LoByteExpression($2); lastExp = $$; } | '>' expression { if(DEBUG_EXP) fprintf(stderr, " U>"); $$ = new HiByteExpression($2); lastExp = $$; } | '(' expression ')' { if(DEBUG_EXP) fprintf(stderr, " ()"); $$ = $2; lastExp = $$; } | expression '[' expression ']' { if(DEBUG_EXP) fprintf(stderr, " []"); $$ = new ByteDerefOffsetExpression($1, $3); lastExp = $$; } | NUMBER { if(DEBUG_EXP) fprintf(stderr, "const %d", $1); $$ = new ConstExpression($1); lastExp = $$; } | EQUATE { if(DEBUG_EXP) fprintf(stderr, "equate %s", $1); $$ = new EquateExpression($1); lastExp = $$; } | CPU_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CpuMethod)"); $$ = new CpuMethodExpression($1); lastExp = $$; } | CART_METHOD { if(DEBUG_EXP) fprintf(stderr, " (CartMethod)"); $$ = new CartMethodExpression($1); lastExp = $$; } | TIA_METHOD { if(DEBUG_EXP) fprintf(stderr, " (TiaMethod)"); $$ = new TiaMethodExpression($1); lastExp = $$; } | FUNCTION { if(DEBUG_EXP) fprintf(stderr, " (DefinedFunction)"); $$ = new FunctionExpression($1); lastExp = $$; } | ERR { if(DEBUG_EXP) fprintf(stderr, " ERR: "); yyerror((const char*)"Invalid label or constant"); return 1; } ; %% stella-5.1.1/src/yacc/y.tab.c000066400000000000000000001612161324334165500157060ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison implementation for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ /* C LALR(1) parser skeleton written by Richard Stallman, by simplifying the original so-called "semantic" parser. */ /* All symbols defined below should begin with yy or YY, to avoid infringing on user name space. This should be done even for local variables, as they might otherwise be expanded by user macros. There are some unavoidable exceptions within include files to define necessary library symbols; they are noted "INFRINGES ON USER NAME SPACE" below. */ /* Identify Bison output. */ #define YYBISON 1 /* Bison version. */ #define YYBISON_VERSION "3.0.4" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" /* Pure parsers. */ #define YYPURE 0 /* Push parsers. */ #define YYPUSH 0 /* Pull parsers. */ #define YYPULL 1 /* Copy the first part of user declarations. */ #line 1 "stella.y" /* yacc.c:339 */ #include Expression* lastExp = nullptr; #define YYERROR_VERBOSE 1 /* dump Expression stack during parsing? */ #define DEBUG_EXP 0 int yylex(); char *yytext; void yyerror(const char *e) { //if(DEBUG_EXP) fprintf(stderr, "%s at token \"%s\"\n", e, yytext); if(DEBUG_EXP) fprintf(stderr, "%s\n", e); errMsg = e; // be extra paranoid about deletion if(lastExp && reinterpret_cast(lastExp)) delete lastExp; lastExp = nullptr; } #line 93 "y.tab.c" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus # define YY_NULLPTR nullptr # else # define YY_NULLPTR 0 # endif # endif /* Enabling verbose error messages. */ #ifdef YYERROR_VERBOSE # undef YYERROR_VERBOSE # define YYERROR_VERBOSE 1 #else # define YYERROR_VERBOSE 0 #endif /* In a future release of Bison, this section will be replaced by #include "y.tab.h". */ #ifndef YY_YY_Y_TAB_H_INCLUDED # define YY_YY_Y_TAB_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { NUMBER = 258, ERR = 259, EQUATE = 260, CART_METHOD = 261, CPU_METHOD = 262, TIA_METHOD = 263, FUNCTION = 264, LOG_OR = 265, LOG_AND = 266, LOG_NOT = 267, SHR = 268, SHL = 269, GTE = 270, LTE = 271, NE = 272, EQ = 273, DEREF = 274, UMINUS = 275 }; #endif /* Tokens. */ #define NUMBER 258 #define ERR 259 #define EQUATE 260 #define CART_METHOD 261 #define CPU_METHOD 262 #define TIA_METHOD 263 #define FUNCTION 264 #define LOG_OR 265 #define LOG_AND 266 #define LOG_NOT 267 #define SHR 268 #define SHL 269 #define GTE 270 #define LTE 271 #define NE 272 #define EQ 273 #define DEREF 274 #define UMINUS 275 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 28 "stella.y" /* yacc.c:355 */ int val; char* Equate; CartMethod cartMethod; CpuMethod cpuMethod; TiaMethod tiaMethod; Expression* exp; char* DefinedFunction; #line 183 "y.tab.c" /* yacc.c:355 */ }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; int yyparse (void); #endif /* !YY_YY_Y_TAB_H_INCLUDED */ /* Copy the second part of user declarations. */ #line 200 "y.tab.c" /* yacc.c:358 */ #ifdef short # undef short #endif #ifdef YYTYPE_UINT8 typedef YYTYPE_UINT8 yytype_uint8; #else typedef unsigned char yytype_uint8; #endif #ifdef YYTYPE_INT8 typedef YYTYPE_INT8 yytype_int8; #else typedef signed char yytype_int8; #endif #ifdef YYTYPE_UINT16 typedef YYTYPE_UINT16 yytype_uint16; #else typedef unsigned short int yytype_uint16; #endif #ifdef YYTYPE_INT16 typedef YYTYPE_INT16 yytype_int16; #else typedef short int yytype_int16; #endif #ifndef YYSIZE_T # ifdef __SIZE_TYPE__ # define YYSIZE_T __SIZE_TYPE__ # elif defined size_t # define YYSIZE_T size_t # elif ! defined YYSIZE_T # include /* INFRINGES ON USER NAME SPACE */ # define YYSIZE_T size_t # else # define YYSIZE_T unsigned int # endif #endif #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) #ifndef YY_ # if defined YYENABLE_NLS && YYENABLE_NLS # if ENABLE_NLS # include /* INFRINGES ON USER NAME SPACE */ # define YY_(Msgid) dgettext ("bison-runtime", Msgid) # endif # endif # ifndef YY_ # define YY_(Msgid) Msgid # endif #endif #ifndef YY_ATTRIBUTE # if (defined __GNUC__ \ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C # define YY_ATTRIBUTE(Spec) __attribute__(Spec) # else # define YY_ATTRIBUTE(Spec) /* empty */ # endif #endif #ifndef YY_ATTRIBUTE_PURE # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) #endif #ifndef YY_ATTRIBUTE_UNUSED # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) #endif #if !defined _Noreturn \ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) # if defined _MSC_VER && 1200 <= _MSC_VER # define _Noreturn __declspec (noreturn) # else # define _Noreturn YY_ATTRIBUTE ((__noreturn__)) # endif #endif /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ # define YYUSE(E) ((void) (E)) #else # define YYUSE(E) /* empty */ #endif #if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else # define YY_INITIAL_VALUE(Value) Value #endif #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN # define YY_IGNORE_MAYBE_UNINITIALIZED_END #endif #ifndef YY_INITIAL_VALUE # define YY_INITIAL_VALUE(Value) /* Nothing. */ #endif #if ! defined yyoverflow || YYERROR_VERBOSE /* The parser invokes alloca or malloc; define the necessary symbols. */ # ifdef YYSTACK_USE_ALLOCA # if YYSTACK_USE_ALLOCA # ifdef __GNUC__ # define YYSTACK_ALLOC __builtin_alloca # elif defined __BUILTIN_VA_ARG_INCR # include /* INFRINGES ON USER NAME SPACE */ # elif defined _AIX # define YYSTACK_ALLOC __alloca # elif defined _MSC_VER # include /* INFRINGES ON USER NAME SPACE */ # define alloca _alloca # else # define YYSTACK_ALLOC alloca # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS # include /* INFRINGES ON USER NAME SPACE */ /* Use EXIT_SUCCESS as a witness for stdlib.h. */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # endif # endif # endif # ifdef YYSTACK_ALLOC /* Pacify GCC's 'empty if-body' warning. */ # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) # ifndef YYSTACK_ALLOC_MAXIMUM /* The OS might guarantee only one guard page at the bottom of the stack, and a page size can be as small as 4096 bytes. So we cannot safely invoke alloca (N) if N exceeds 4096. Use a slightly smaller number to allow for a few compiler-allocated temporary stack slots. */ # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ # endif # else # define YYSTACK_ALLOC YYMALLOC # define YYSTACK_FREE YYFREE # ifndef YYSTACK_ALLOC_MAXIMUM # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM # endif # if (defined __cplusplus && ! defined EXIT_SUCCESS \ && ! ((defined YYMALLOC || defined malloc) \ && (defined YYFREE || defined free))) # include /* INFRINGES ON USER NAME SPACE */ # ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 # endif # endif # ifndef YYMALLOC # define YYMALLOC malloc # if ! defined malloc && ! defined EXIT_SUCCESS void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ # endif # endif # ifndef YYFREE # define YYFREE free # if ! defined free && ! defined EXIT_SUCCESS void free (void *); /* INFRINGES ON USER NAME SPACE */ # endif # endif # endif #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ #if (! defined yyoverflow \ && (! defined __cplusplus \ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) /* A type that is properly aligned for any stack member. */ union yyalloc { yytype_int16 yyss_alloc; YYSTYPE yyvs_alloc; }; /* The size of the maximum gap between one aligned stack and the next. */ # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) /* The size of an array large to enough to hold all stacks, each with N elements. */ # define YYSTACK_BYTES(N) \ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + YYSTACK_GAP_MAXIMUM) # define YYCOPY_NEEDED 1 /* Relocate STACK from its old location to the new one. The local variables YYSIZE and YYSTACKSIZE give the old and new number of elements in the stack, and YYPTR gives the new location of the stack. Advance YYPTR to a properly aligned location for the next stack. */ # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ do \ { \ YYSIZE_T yynewbytes; \ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ Stack = &yyptr->Stack_alloc; \ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ yyptr += yynewbytes / sizeof (*yyptr); \ } \ while (0) #endif #if defined YYCOPY_NEEDED && YYCOPY_NEEDED /* Copy COUNT objects from SRC to DST. The source and destination do not overlap. */ # ifndef YYCOPY # if defined __GNUC__ && 1 < __GNUC__ # define YYCOPY(Dst, Src, Count) \ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) # else # define YYCOPY(Dst, Src, Count) \ do \ { \ YYSIZE_T yyi; \ for (yyi = 0; yyi < (Count); yyi++) \ (Dst)[yyi] = (Src)[yyi]; \ } \ while (0) # endif # endif #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 26 /* YYLAST -- Last index in YYTABLE. */ #define YYLAST 227 /* YYNTOKENS -- Number of terminals. */ #define YYNTOKENS 38 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 3 /* YYNRULES -- Number of rules. */ #define YYNRULES 36 /* YYNSTATES -- Number of states. */ #define YYNSTATES 67 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 #define YYMAXUTOK 275 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM as returned by yylex, without out-of-bounds checking. */ static const yytype_uint8 yytranslate[] = { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 2, 2, 2, 14, 20, 2, 35, 36, 12, 11, 2, 10, 2, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 23, 2, 24, 2, 34, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 31, 2, 37, 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 18, 2, 32, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 17, 21, 22, 25, 26, 27, 28, 29, 30 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { 0, 66, 66, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102 }; #endif #if YYDEBUG || YYERROR_VERBOSE || 0 /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. First, the terminals, then, starting at YYNTOKENS, nonterminals. */ static const char *const yytname[] = { "$end", "error", "$undefined", "NUMBER", "ERR", "EQUATE", "CART_METHOD", "CPU_METHOD", "TIA_METHOD", "FUNCTION", "'-'", "'+'", "'*'", "'/'", "'%'", "LOG_OR", "LOG_AND", "LOG_NOT", "'|'", "'^'", "'&'", "SHR", "SHL", "'<'", "'>'", "GTE", "LTE", "NE", "EQ", "DEREF", "UMINUS", "'['", "'~'", "'!'", "'@'", "'('", "')'", "']'", "$accept", "statement", "expression", YY_NULLPTR }; #endif # ifdef YYPRINT /* YYTOKNUM[NUM] -- (External) token number corresponding to the (internal) symbol number NUM (which must be that of a token). */ static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 45, 43, 42, 47, 37, 265, 266, 267, 124, 94, 38, 268, 269, 60, 62, 270, 271, 272, 273, 274, 275, 91, 126, 33, 64, 40, 41, 93 }; # endif #define YYPACT_NINF -15 #define yypact_value_is_default(Yystate) \ (!!((Yystate) == (-15))) #define YYTABLE_NINF -1 #define yytable_value_is_error(Yytable_value) \ (!!((Yytable_value) == (-1))) /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ static const yytype_int16 yypact[] = { 35, -15, -15, -15, -15, -15, -15, -15, 35, 35, 35, 35, 35, 35, 35, 35, 16, 116, -14, -14, 187, 187, -14, -14, -14, 89, -15, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, -15, 136, 136, 150, 150, 150, 164, 178, 29, 29, -13, 196, 196, 187, 187, 187, 187, 187, 187, 61, -15 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. Performed when YYTABLE does not specify something else to do. Zero means the default is an error. */ static const yytype_uint8 yydefact[] = { 0, 30, 36, 31, 33, 32, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 21, 24, 26, 27, 22, 23, 25, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 4, 3, 5, 6, 7, 19, 20, 9, 10, 8, 17, 18, 11, 12, 13, 14, 15, 16, 0, 29 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { -15, -15, -8 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { -1, 16, 17 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule whose number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int8 yytable[] = { 18, 19, 20, 21, 22, 23, 24, 25, 37, 38, 39, 40, 41, 42, 43, 44, 26, 45, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 1, 2, 3, 4, 5, 6, 7, 8, 0, 9, 0, 36, 37, 38, 39, 40, 41, 42, 43, 44, 10, 11, 45, 0, 0, 0, 0, 0, 0, 12, 13, 14, 15, 27, 28, 29, 30, 31, 32, 33, 0, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 0, 45, 0, 0, 0, 0, 0, 66, 27, 28, 29, 30, 31, 32, 33, 0, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 0, 45, 0, 0, 0, 0, 46, 27, 28, 29, 30, 31, 32, 33, 0, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 0, 45, 29, 30, 31, 32, 33, 0, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 32, 33, 45, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 33, 45, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 0, 45, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 0, 0, 45, -1, -1, -1, -1, -1, -1, 0, 0, 45, 39, 40, 41, 42, 43, 44, 0, 0, 45 }; static const yytype_int8 yycheck[] = { 8, 9, 10, 11, 12, 13, 14, 15, 21, 22, 23, 24, 25, 26, 27, 28, 0, 31, 31, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 3, 4, 5, 6, 7, 8, 9, 10, -1, 12, -1, 20, 21, 22, 23, 24, 25, 26, 27, 28, 23, 24, 31, -1, -1, -1, -1, -1, -1, 32, 33, 34, 35, 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, -1, -1, 31, -1, -1, -1, -1, -1, 37, 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, -1, -1, 31, -1, -1, -1, -1, 36, 10, 11, 12, 13, 14, 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, -1, -1, 31, 12, 13, 14, 15, 16, -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 15, 16, 31, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, -1, 16, 31, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, -1, -1, 31, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, -1, -1, 31, 23, 24, 25, 26, 27, 28, -1, -1, 31, 23, 24, 25, 26, 27, 28, -1, -1, 31 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 12, 23, 24, 32, 33, 34, 35, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 36, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 37 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { 0, 38, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { 0, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, 4, 1, 1, 1, 1, 1, 1, 1 }; #define yyerrok (yyerrstatus = 0) #define yyclearin (yychar = YYEMPTY) #define YYEMPTY (-2) #define YYEOF 0 #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab #define YYRECOVERING() (!!yyerrstatus) #define YYBACKUP(Token, Value) \ do \ if (yychar == YYEMPTY) \ { \ yychar = (Token); \ yylval = (Value); \ YYPOPSTACK (yylen); \ yystate = *yyssp; \ goto yybackup; \ } \ else \ { \ yyerror (YY_("syntax error: cannot back up")); \ YYERROR; \ } \ while (0) /* Error token number */ #define YYTERROR 1 #define YYERRCODE 256 /* Enable debugging if requested. */ #if YYDEBUG # ifndef YYFPRINTF # include /* INFRINGES ON USER NAME SPACE */ # define YYFPRINTF fprintf # endif # define YYDPRINTF(Args) \ do { \ if (yydebug) \ YYFPRINTF Args; \ } while (0) /* This macro is provided for backward compatibility. */ #ifndef YY_LOCATION_PRINT # define YY_LOCATION_PRINT(File, Loc) ((void) 0) #endif # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ do { \ if (yydebug) \ { \ YYFPRINTF (stderr, "%s ", Title); \ yy_symbol_print (stderr, \ Type, Value); \ YYFPRINTF (stderr, "\n"); \ } \ } while (0) /*----------------------------------------. | Print this symbol's value on YYOUTPUT. | `----------------------------------------*/ static void yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) { FILE *yyo = yyoutput; YYUSE (yyo); if (!yyvaluep) return; # ifdef YYPRINT if (yytype < YYNTOKENS) YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); # endif YYUSE (yytype); } /*--------------------------------. | Print this symbol on YYOUTPUT. | `--------------------------------*/ static void yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) { YYFPRINTF (yyoutput, "%s %s (", yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); yy_symbol_value_print (yyoutput, yytype, yyvaluep); YYFPRINTF (yyoutput, ")"); } /*------------------------------------------------------------------. | yy_stack_print -- Print the state stack from its BOTTOM up to its | | TOP (included). | `------------------------------------------------------------------*/ static void yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) { YYFPRINTF (stderr, "Stack now"); for (; yybottom <= yytop; yybottom++) { int yybot = *yybottom; YYFPRINTF (stderr, " %d", yybot); } YYFPRINTF (stderr, "\n"); } # define YY_STACK_PRINT(Bottom, Top) \ do { \ if (yydebug) \ yy_stack_print ((Bottom), (Top)); \ } while (0) /*------------------------------------------------. | Report that the YYRULE is going to be reduced. | `------------------------------------------------*/ static void yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) { unsigned long int yylno = yyrline[yyrule]; int yynrhs = yyr2[yyrule]; int yyi; YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", yyrule - 1, yylno); /* The symbols being reduced. */ for (yyi = 0; yyi < yynrhs; yyi++) { YYFPRINTF (stderr, " $%d = ", yyi + 1); yy_symbol_print (stderr, yystos[yyssp[yyi + 1 - yynrhs]], &(yyvsp[(yyi + 1) - (yynrhs)]) ); YYFPRINTF (stderr, "\n"); } } # define YY_REDUCE_PRINT(Rule) \ do { \ if (yydebug) \ yy_reduce_print (yyssp, yyvsp, Rule); \ } while (0) /* Nonzero means print parse trace. It is left uninitialized so that multiple parsers can coexist. */ int yydebug; #else /* !YYDEBUG */ # define YYDPRINTF(Args) # define YY_SYMBOL_PRINT(Title, Type, Value, Location) # define YY_STACK_PRINT(Bottom, Top) # define YY_REDUCE_PRINT(Rule) #endif /* !YYDEBUG */ /* YYINITDEPTH -- initial size of the parser's stacks. */ #ifndef YYINITDEPTH # define YYINITDEPTH 200 #endif /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only if the built-in stack extension method is used). Do not make this value too large; the results are undefined if YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) evaluated with infinite-precision integer arithmetic. */ #ifndef YYMAXDEPTH # define YYMAXDEPTH 10000 #endif #if YYERROR_VERBOSE # ifndef yystrlen # if defined __GLIBC__ && defined _STRING_H # define yystrlen strlen # else /* Return the length of YYSTR. */ static YYSIZE_T yystrlen (const char *yystr) { YYSIZE_T yylen; for (yylen = 0; yystr[yylen]; yylen++) continue; return yylen; } # endif # endif # ifndef yystpcpy # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE # define yystpcpy stpcpy # else /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in YYDEST. */ static char * yystpcpy (char *yydest, const char *yysrc) { char *yyd = yydest; const char *yys = yysrc; while ((*yyd++ = *yys++) != '\0') continue; return yyd - 1; } # endif # endif # ifndef yytnamerr /* Copy to YYRES the contents of YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. If YYRES is null, do not copy; instead, return the length of what the result would have been. */ static YYSIZE_T yytnamerr (char *yyres, const char *yystr) { if (*yystr == '"') { YYSIZE_T yyn = 0; char const *yyp = yystr; for (;;) switch (*++yyp) { case '\'': case ',': goto do_not_strip_quotes; case '\\': if (*++yyp != '\\') goto do_not_strip_quotes; /* Fall through. */ default: if (yyres) yyres[yyn] = *yyp; yyn++; break; case '"': if (yyres) yyres[yyn] = '\0'; return yyn; } do_not_strip_quotes: ; } if (! yyres) return yystrlen (yystr); return yystpcpy (yyres, yystr) - yyres; } # endif /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message about the unexpected token YYTOKEN for the state stack whose top is YYSSP. Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is not large enough to hold the message. In that case, also set *YYMSG_ALLOC to the required number of bytes. Return 2 if the required number of bytes is too large to store. */ static int yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, yytype_int16 *yyssp, int yytoken) { YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); YYSIZE_T yysize = yysize0; enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; /* Internationalized format string. */ const char *yyformat = YY_NULLPTR; /* Arguments of yyformat. */ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; /* Number of reported tokens (one for the "unexpected", one per "expected"). */ int yycount = 0; /* There are many possibilities here to consider: - If this state is a consistent state with a default action, then the only way this function was invoked is if the default action is an error action. In that case, don't check for expected tokens because there are none. - The only way there can be no lookahead present (in yychar) is if this state is a consistent state with a default action. Thus, detecting the absence of a lookahead is sufficient to determine that there is no unexpected or expected token to report. In that case, just report a simple "syntax error". - Don't assume there isn't a lookahead just because this state is a consistent state with a default action. There might have been a previous inconsistent state, consistent state with a non-default action, or user semantic action that manipulated yychar. - Of course, the expected token list depends on states to have correct lookahead information, and it depends on the parser not to perform extra reductions after fetching a lookahead from the scanner and before detecting a syntax error. Thus, state merging (from LALR or IELR) and default reductions corrupt the expected token list. However, the list is correct for canonical LR with one exception: it will still contain any token that will not be accepted due to an error action in a later state. */ if (yytoken != YYEMPTY) { int yyn = yypact[*yyssp]; yyarg[yycount++] = yytname[yytoken]; if (!yypact_value_is_default (yyn)) { /* Start YYX at -YYN if negative to avoid negative indexes in YYCHECK. In other words, skip the first -YYN actions for this state because they are default actions. */ int yyxbegin = yyn < 0 ? -yyn : 0; /* Stay within bounds of both yycheck and yytname. */ int yychecklim = YYLAST - yyn + 1; int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; int yyx; for (yyx = yyxbegin; yyx < yyxend; ++yyx) if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR && !yytable_value_is_error (yytable[yyx + yyn])) { if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) { yycount = 1; yysize = yysize0; break; } yyarg[yycount++] = yytname[yyx]; { YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } } } } switch (yycount) { # define YYCASE_(N, S) \ case N: \ yyformat = S; \ break YYCASE_(0, YY_("syntax error")); YYCASE_(1, YY_("syntax error, unexpected %s")); YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); # undef YYCASE_ } { YYSIZE_T yysize1 = yysize + yystrlen (yyformat); if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) return 2; yysize = yysize1; } if (*yymsg_alloc < yysize) { *yymsg_alloc = 2 * yysize; if (! (yysize <= *yymsg_alloc && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; return 1; } /* Avoid sprintf, as that infringes on the user's name space. Don't have undefined behavior even if the translation produced a string with the wrong number of "%s"s. */ { char *yyp = *yymsg; int yyi = 0; while ((*yyp = *yyformat) != '\0') if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) { yyp += yytnamerr (yyp, yyarg[yyi++]); yyformat += 2; } else { yyp++; yyformat++; } } return 0; } #endif /* YYERROR_VERBOSE */ /*-----------------------------------------------. | Release the memory associated to this symbol. | `-----------------------------------------------*/ static void yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) { YYUSE (yyvaluep); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN YYUSE (yytype); YY_IGNORE_MAYBE_UNINITIALIZED_END } /* The lookahead symbol. */ int yychar; /* The semantic value of the lookahead symbol. */ YYSTYPE yylval; /* Number of syntax errors so far. */ int yynerrs; /*----------. | yyparse. | `----------*/ int yyparse (void) { int yystate; /* Number of tokens to shift before error messages enabled. */ int yyerrstatus; /* The stacks and their tools: 'yyss': related to states. 'yyvs': related to semantic values. Refer to the stacks through separate pointers, to allow yyoverflow to reallocate them elsewhere. */ /* The state stack. */ yytype_int16 yyssa[YYINITDEPTH]; yytype_int16 *yyss; yytype_int16 *yyssp; /* The semantic value stack. */ YYSTYPE yyvsa[YYINITDEPTH]; YYSTYPE *yyvs; YYSTYPE *yyvsp; YYSIZE_T yystacksize; int yyn; int yyresult; /* Lookahead token as an internal (translated) token number. */ int yytoken = 0; /* The variables used to return semantic value and location from the action routines. */ YYSTYPE yyval; #if YYERROR_VERBOSE /* Buffer for error messages, and its allocated size. */ char yymsgbuf[128]; char *yymsg = yymsgbuf; YYSIZE_T yymsg_alloc = sizeof yymsgbuf; #endif #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) /* The number of symbols on the RHS of the reduced rule. Keep to zero when no symbol should be popped. */ int yylen = 0; yyssp = yyss = yyssa; yyvsp = yyvs = yyvsa; yystacksize = YYINITDEPTH; YYDPRINTF ((stderr, "Starting parse\n")); yystate = 0; yyerrstatus = 0; yynerrs = 0; yychar = YYEMPTY; /* Cause a token to be read. */ goto yysetstate; /*------------------------------------------------------------. | yynewstate -- Push a new state, which is found in yystate. | `------------------------------------------------------------*/ yynewstate: /* In all cases, when you get here, the value and location stacks have just been pushed. So pushing a state here evens the stacks. */ yyssp++; yysetstate: *yyssp = yystate; if (yyss + yystacksize - 1 <= yyssp) { /* Get the current used size of the three stacks, in elements. */ YYSIZE_T yysize = yyssp - yyss + 1; #ifdef yyoverflow { /* Give user a chance to reallocate the stack. Use copies of these so that the &'s don't force the real ones into memory. */ YYSTYPE *yyvs1 = yyvs; yytype_int16 *yyss1 = yyss; /* Each stack pointer address is followed by the size of the data in use in that stack, in bytes. This used to be a conditional around just the two extra args, but that might be undefined if yyoverflow is a macro. */ yyoverflow (YY_("memory exhausted"), &yyss1, yysize * sizeof (*yyssp), &yyvs1, yysize * sizeof (*yyvsp), &yystacksize); yyss = yyss1; yyvs = yyvs1; } #else /* no yyoverflow */ # ifndef YYSTACK_RELOCATE goto yyexhaustedlab; # else /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) goto yyexhaustedlab; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; { yytype_int16 *yyss1 = yyss; union yyalloc *yyptr = (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); if (! yyptr) goto yyexhaustedlab; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE if (yyss1 != yyssa) YYSTACK_FREE (yyss1); } # endif #endif /* no yyoverflow */ yyssp = yyss + yysize - 1; yyvsp = yyvs + yysize - 1; YYDPRINTF ((stderr, "Stack size increased to %lu\n", (unsigned long int) yystacksize)); if (yyss + yystacksize - 1 <= yyssp) YYABORT; } YYDPRINTF ((stderr, "Entering state %d\n", yystate)); if (yystate == YYFINAL) YYACCEPT; goto yybackup; /*-----------. | yybackup. | `-----------*/ yybackup: /* Do appropriate processing given the current state. Read a lookahead token if we need one and don't already have one. */ /* First try to decide what to do without reference to lookahead token. */ yyn = yypact[yystate]; if (yypact_value_is_default (yyn)) goto yydefault; /* Not known => get a lookahead token if don't already have one. */ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ if (yychar == YYEMPTY) { YYDPRINTF ((stderr, "Reading a token: ")); yychar = yylex (); } if (yychar <= YYEOF) { yychar = yytoken = YYEOF; YYDPRINTF ((stderr, "Now at end of input.\n")); } else { yytoken = YYTRANSLATE (yychar); YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); } /* If the proper action on seeing token YYTOKEN is to reduce or to detect an error, take that action. */ yyn += yytoken; if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) goto yydefault; yyn = yytable[yyn]; if (yyn <= 0) { if (yytable_value_is_error (yyn)) goto yyerrlab; yyn = -yyn; goto yyreduce; } /* Count tokens shifted since error; after three, turn off error status. */ if (yyerrstatus) yyerrstatus--; /* Shift the lookahead token. */ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); /* Discard the shifted token. */ yychar = YYEMPTY; yystate = yyn; YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END goto yynewstate; /*-----------------------------------------------------------. | yydefault -- do the default action for the current state. | `-----------------------------------------------------------*/ yydefault: yyn = yydefact[yystate]; if (yyn == 0) goto yyerrlab; goto yyreduce; /*-----------------------------. | yyreduce -- Do a reduction. | `-----------------------------*/ yyreduce: /* yyn is the number of a rule to reduce with. */ yylen = yyr2[yyn]; /* If YYLEN is nonzero, implement the default value of the action: '$$ = $1'. Otherwise, the following line sets YYVAL to garbage. This behavior is undocumented and Bison users should not rely upon it. Assigning to YYVAL unconditionally makes the parser a bit smaller, and it avoids a GCC warning that YYVAL may be used uninitialized. */ yyval = yyvsp[1-yylen]; YY_REDUCE_PRINT (yyn); switch (yyn) { case 2: #line 66 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, "\ndone\n"); result.exp = (yyvsp[0].exp); } #line 1344 "y.tab.c" /* yacc.c:1646 */ break; case 3: #line 69 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " +"); (yyval.exp) = new PlusExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1350 "y.tab.c" /* yacc.c:1646 */ break; case 4: #line 70 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " -"); (yyval.exp) = new MinusExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1356 "y.tab.c" /* yacc.c:1646 */ break; case 5: #line 71 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " *"); (yyval.exp) = new MultExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1362 "y.tab.c" /* yacc.c:1646 */ break; case 6: #line 72 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " /"); (yyval.exp) = new DivExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1368 "y.tab.c" /* yacc.c:1646 */ break; case 7: #line 73 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " %%"); (yyval.exp) = new ModExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1374 "y.tab.c" /* yacc.c:1646 */ break; case 8: #line 74 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " &"); (yyval.exp) = new BinAndExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1380 "y.tab.c" /* yacc.c:1646 */ break; case 9: #line 75 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " |"); (yyval.exp) = new BinOrExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1386 "y.tab.c" /* yacc.c:1646 */ break; case 10: #line 76 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " ^"); (yyval.exp) = new BinXorExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1392 "y.tab.c" /* yacc.c:1646 */ break; case 11: #line 77 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " <"); (yyval.exp) = new LessExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1398 "y.tab.c" /* yacc.c:1646 */ break; case 12: #line 78 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " >"); (yyval.exp) = new GreaterExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1404 "y.tab.c" /* yacc.c:1646 */ break; case 13: #line 79 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " >="); (yyval.exp) = new GreaterEqualsExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1410 "y.tab.c" /* yacc.c:1646 */ break; case 14: #line 80 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " <="); (yyval.exp) = new LessEqualsExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1416 "y.tab.c" /* yacc.c:1646 */ break; case 15: #line 81 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " !="); (yyval.exp) = new NotEqualsExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1422 "y.tab.c" /* yacc.c:1646 */ break; case 16: #line 82 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " =="); (yyval.exp) = new EqualsExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1428 "y.tab.c" /* yacc.c:1646 */ break; case 17: #line 83 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " >>"); (yyval.exp) = new ShiftRightExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1434 "y.tab.c" /* yacc.c:1646 */ break; case 18: #line 84 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " <<"); (yyval.exp) = new ShiftLeftExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1440 "y.tab.c" /* yacc.c:1646 */ break; case 19: #line 85 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " ||"); (yyval.exp) = new LogOrExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1446 "y.tab.c" /* yacc.c:1646 */ break; case 20: #line 86 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " &&"); (yyval.exp) = new LogAndExpression((yyvsp[-2].exp), (yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1452 "y.tab.c" /* yacc.c:1646 */ break; case 21: #line 87 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " U-"); (yyval.exp) = new UnaryMinusExpression((yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1458 "y.tab.c" /* yacc.c:1646 */ break; case 22: #line 88 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " ~"); (yyval.exp) = new BinNotExpression((yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1464 "y.tab.c" /* yacc.c:1646 */ break; case 23: #line 89 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " !"); (yyval.exp) = new LogNotExpression((yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1470 "y.tab.c" /* yacc.c:1646 */ break; case 24: #line 90 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " U*"); (yyval.exp) = new ByteDerefExpression((yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1476 "y.tab.c" /* yacc.c:1646 */ break; case 25: #line 91 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " U@"); (yyval.exp) = new WordDerefExpression((yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1482 "y.tab.c" /* yacc.c:1646 */ break; case 26: #line 92 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " U<"); (yyval.exp) = new LoByteExpression((yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1488 "y.tab.c" /* yacc.c:1646 */ break; case 27: #line 93 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " U>"); (yyval.exp) = new HiByteExpression((yyvsp[0].exp)); lastExp = (yyval.exp); } #line 1494 "y.tab.c" /* yacc.c:1646 */ break; case 28: #line 94 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " ()"); (yyval.exp) = (yyvsp[-1].exp); lastExp = (yyval.exp); } #line 1500 "y.tab.c" /* yacc.c:1646 */ break; case 29: #line 95 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " []"); (yyval.exp) = new ByteDerefOffsetExpression((yyvsp[-3].exp), (yyvsp[-1].exp)); lastExp = (yyval.exp); } #line 1506 "y.tab.c" /* yacc.c:1646 */ break; case 30: #line 96 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, "const %d", (yyvsp[0].val)); (yyval.exp) = new ConstExpression((yyvsp[0].val)); lastExp = (yyval.exp); } #line 1512 "y.tab.c" /* yacc.c:1646 */ break; case 31: #line 97 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, "equate %s", (yyvsp[0].Equate)); (yyval.exp) = new EquateExpression((yyvsp[0].Equate)); lastExp = (yyval.exp); } #line 1518 "y.tab.c" /* yacc.c:1646 */ break; case 32: #line 98 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " (CpuMethod)"); (yyval.exp) = new CpuMethodExpression((yyvsp[0].cpuMethod)); lastExp = (yyval.exp); } #line 1524 "y.tab.c" /* yacc.c:1646 */ break; case 33: #line 99 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " (CartMethod)"); (yyval.exp) = new CartMethodExpression((yyvsp[0].cartMethod)); lastExp = (yyval.exp); } #line 1530 "y.tab.c" /* yacc.c:1646 */ break; case 34: #line 100 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " (TiaMethod)"); (yyval.exp) = new TiaMethodExpression((yyvsp[0].tiaMethod)); lastExp = (yyval.exp); } #line 1536 "y.tab.c" /* yacc.c:1646 */ break; case 35: #line 101 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " (DefinedFunction)"); (yyval.exp) = new FunctionExpression((yyvsp[0].DefinedFunction)); lastExp = (yyval.exp); } #line 1542 "y.tab.c" /* yacc.c:1646 */ break; case 36: #line 102 "stella.y" /* yacc.c:1646 */ { if(DEBUG_EXP) fprintf(stderr, " ERR: "); yyerror((const char*)"Invalid label or constant"); return 1; } #line 1548 "y.tab.c" /* yacc.c:1646 */ break; #line 1552 "y.tab.c" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires that yytoken be updated with the new translation. We take the approach of translating immediately before every use of yytoken. One alternative is translating here after every semantic action, but that translation would be missed if the semantic action invokes YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an incorrect destructor might then be invoked immediately. In the case of YYERROR or YYBACKUP, subsequent parser actions might lead to an incorrect destructor call or verbose syntax error message before the lookahead is translated. */ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); *++yyvsp = yyval; /* Now 'shift' the result of the reduction. Determine what state that goes to, based on the state we popped back to and the rule number reduced by. */ yyn = yyr1[yyn]; yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) yystate = yytable[yystate]; else yystate = yydefgoto[yyn - YYNTOKENS]; goto yynewstate; /*--------------------------------------. | yyerrlab -- here on detecting error. | `--------------------------------------*/ yyerrlab: /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); /* If not already recovering from an error, report this error. */ if (!yyerrstatus) { ++yynerrs; #if ! YYERROR_VERBOSE yyerror (YY_("syntax error")); #else # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ yyssp, yytoken) { char const *yymsgp = YY_("syntax error"); int yysyntax_error_status; yysyntax_error_status = YYSYNTAX_ERROR; if (yysyntax_error_status == 0) yymsgp = yymsg; else if (yysyntax_error_status == 1) { if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); if (!yymsg) { yymsg = yymsgbuf; yymsg_alloc = sizeof yymsgbuf; yysyntax_error_status = 2; } else { yysyntax_error_status = YYSYNTAX_ERROR; yymsgp = yymsg; } } yyerror (yymsgp); if (yysyntax_error_status == 2) goto yyexhaustedlab; } # undef YYSYNTAX_ERROR #endif } if (yyerrstatus == 3) { /* If just tried and failed to reuse lookahead token after an error, discard it. */ if (yychar <= YYEOF) { /* Return failure if at end of input. */ if (yychar == YYEOF) YYABORT; } else { yydestruct ("Error: discarding", yytoken, &yylval); yychar = YYEMPTY; } } /* Else will try to reuse lookahead token after shifting the error token. */ goto yyerrlab1; /*---------------------------------------------------. | yyerrorlab -- error raised explicitly by YYERROR. | `---------------------------------------------------*/ yyerrorlab: /* Pacify compilers like GCC when the user code never invokes YYERROR and the label yyerrorlab therefore never appears in user code. */ if (/*CONSTCOND*/ 0) goto yyerrorlab; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ YYPOPSTACK (yylen); yylen = 0; YY_STACK_PRINT (yyss, yyssp); yystate = *yyssp; goto yyerrlab1; /*-------------------------------------------------------------. | yyerrlab1 -- common code for both syntax error and YYERROR. | `-------------------------------------------------------------*/ yyerrlab1: yyerrstatus = 3; /* Each real token shifted decrements this. */ for (;;) { yyn = yypact[yystate]; if (!yypact_value_is_default (yyn)) { yyn += YYTERROR; if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) { yyn = yytable[yyn]; if (0 < yyn) break; } } /* Pop the current state because it cannot handle the error token. */ if (yyssp == yyss) YYABORT; yydestruct ("Error: popping", yystos[yystate], yyvsp); YYPOPSTACK (1); yystate = *yyssp; YY_STACK_PRINT (yyss, yyssp); } YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN *++yyvsp = yylval; YY_IGNORE_MAYBE_UNINITIALIZED_END /* Shift the error token. */ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); yystate = yyn; goto yynewstate; /*-------------------------------------. | yyacceptlab -- YYACCEPT comes here. | `-------------------------------------*/ yyacceptlab: yyresult = 0; goto yyreturn; /*-----------------------------------. | yyabortlab -- YYABORT comes here. | `-----------------------------------*/ yyabortlab: yyresult = 1; goto yyreturn; #if !defined yyoverflow || YYERROR_VERBOSE /*-------------------------------------------------. | yyexhaustedlab -- memory exhaustion comes here. | `-------------------------------------------------*/ yyexhaustedlab: yyerror (YY_("memory exhausted")); yyresult = 2; /* Fall through. */ #endif yyreturn: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at user semantic actions for why this is necessary. */ yytoken = YYTRANSLATE (yychar); yydestruct ("Cleanup: discarding lookahead", yytoken, &yylval); } /* Do not reclaim the symbols of the rule whose action triggered this YYABORT or YYACCEPT. */ YYPOPSTACK (yylen); YY_STACK_PRINT (yyss, yyssp); while (yyssp != yyss) { yydestruct ("Cleanup: popping", yystos[*yyssp], yyvsp); YYPOPSTACK (1); } #ifndef yyoverflow if (yyss != yyssa) YYSTACK_FREE (yyss); #endif #if YYERROR_VERBOSE if (yymsg != yymsgbuf) YYSTACK_FREE (yymsg); #endif return yyresult; } #line 104 "stella.y" /* yacc.c:1906 */ stella-5.1.1/src/yacc/y.tab.h000066400000000000000000000055701324334165500157130ustar00rootroot00000000000000/* A Bison parser, made by GNU Bison 3.0.4. */ /* Bison interface for Yacc-like parsers in C Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work under terms of your choice, so long as that work isn't itself a parser generator using the skeleton or a modified version thereof as a parser skeleton. Alternatively, if you modify or redistribute the parser skeleton itself, you may (at your option) remove this special exception, which will cause the skeleton and the resulting Bison output files to be licensed under the GNU General Public License without this special exception. This special exception was added by the Free Software Foundation in version 2.2 of Bison. */ #ifndef YY_YY_Y_TAB_H_INCLUDED # define YY_YY_Y_TAB_H_INCLUDED /* Debug traces. */ #ifndef YYDEBUG # define YYDEBUG 0 #endif #if YYDEBUG extern int yydebug; #endif /* Token type. */ #ifndef YYTOKENTYPE # define YYTOKENTYPE enum yytokentype { NUMBER = 258, ERR = 259, EQUATE = 260, CART_METHOD = 261, CPU_METHOD = 262, TIA_METHOD = 263, FUNCTION = 264, LOG_OR = 265, LOG_AND = 266, LOG_NOT = 267, SHR = 268, SHL = 269, GTE = 270, LTE = 271, NE = 272, EQ = 273, DEREF = 274, UMINUS = 275 }; #endif /* Tokens. */ #define NUMBER 258 #define ERR 259 #define EQUATE 260 #define CART_METHOD 261 #define CPU_METHOD 262 #define TIA_METHOD 263 #define FUNCTION 264 #define LOG_OR 265 #define LOG_AND 266 #define LOG_NOT 267 #define SHR 268 #define SHL 269 #define GTE 270 #define LTE 271 #define NE 272 #define EQ 273 #define DEREF 274 #define UMINUS 275 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { #line 28 "stella.y" /* yacc.c:1909 */ int val; char* Equate; CartMethod cartMethod; CpuMethod cpuMethod; TiaMethod tiaMethod; Expression* exp; char* DefinedFunction; #line 104 "y.tab.h" /* yacc.c:1909 */ }; typedef union YYSTYPE YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_DECLARED 1 #endif extern YYSTYPE yylval; int yyparse (void); #endif /* !YY_YY_Y_TAB_H_INCLUDED */ stella-5.1.1/src/zlib/000077500000000000000000000000001324334165500145375ustar00rootroot00000000000000stella-5.1.1/src/zlib/README000066400000000000000000000121031324334165500154140ustar00rootroot00000000000000ZLIB DATA COMPRESSION LIBRARY zlib 1.2.11 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). All functions of the compression library are documented in the file zlib.h (volunteer to write man pages welcome, contact zlib@gzip.org). A usage example of the library is given in the file test/example.c which also tests that the library is working correctly. Another example is given in the file test/minigzip.c. The compression library itself is composed of all source files in the root directory. To compile all files and run the test program, follow the instructions given at the top of Makefile.in. In short "./configure; make test", and if that goes well, "make install" should work for most flavors of Unix. For Windows, use one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use make_vms.com. Questions about zlib should be sent to , or to Gilles Vollant for the Windows DLL version. The zlib home page is http://zlib.net/ . Before reporting a problem, please check this site to verify that you have the latest version of zlib; otherwise get the latest version and check whether the problem still exists or not. PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. Mark Nelson wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at http://marknelson.us/1997/01/01/zlib-engine/ . The changes made in version 1.2.11 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . zlib is available in Java using the java.util.zip package, documented at http://java.sun.com/developer/technicalArticles/Programming/compression/ . A Perl interface to zlib written by Paul Marquess is available at CPAN (Comprehensive Perl Archive Network) sites, including http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . A Python interface to zlib written by A.M. Kuchling is available in Python 1.5 and later versions, see http://docs.python.org/library/zlib.html . zlib is built into tcl: http://wiki.tcl.tk/4610 . An experimental package to read and write files in .zip format, written on top of zlib by Gilles Vollant , is available in the contrib/minizip directory of zlib. Notes for some targets: - For Windows DLL versions, please see win32/DLL_FAQ.txt - For 64-bit Irix, deflate.c must be compiled without any optimization. With -O, one libpng test fails. The test works in 32 bit mode (with the -n32 compiler flag). The compiler bug has been reported to SGI. - zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works when compiled with cc. - On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is necessary to get gzprintf working correctly. This is done by configure. - zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with other compilers. Use "make test" to check your compiler. - gzdopen is not supported on RISCOS or BEOS. - For PalmOs, see http://palmzlib.sourceforge.net/ Acknowledgments: The deflate format used by zlib was defined by Phil Katz. The deflate and zlib specifications were written by L. Peter Deutsch. Thanks to all the people who reported problems and suggested various improvements in zlib; they are too numerous to cite here. Copyright notice: (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu If you use the zlib library in a product, we would appreciate *not* receiving lengthy legal documents to sign. The sources are provided for free but without warranty of any kind. The library has been entirely written by Jean-loup Gailly and Mark Adler; it does not include third-party code. If you redistribute modified sources, we would appreciate that you include in the file ChangeLog history information documenting your changes. Please read the FAQ for more information on the distribution of modified source versions. stella-5.1.1/src/zlib/adler32.c000066400000000000000000000117651324334165500161510ustar00rootroot00000000000000/* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /* use NO_DIVIDE if your processor does not do division in hardware -- try it both ways to see which is faster */ #ifdef NO_DIVIDE /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 (thank you to John Reiser for pointing this out) */ # define CHOP(a) \ do { \ unsigned long tmp = a >> 16; \ a &= 0xffffUL; \ a += (tmp << 4) - tmp; \ } while (0) # define MOD28(a) \ do { \ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) # define MOD(a) \ do { \ CHOP(a); \ MOD28(a); \ } while (0) # define MOD63(a) \ do { /* this assumes a is not negative */ \ z_off64_t tmp = a >> 32; \ a &= 0xffffffffL; \ a += (tmp << 8) - (tmp << 5) + tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ uLong ZEXPORT adler32_z( uLong adler, const Bytef *buf, z_size_t len) { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32( uLong adler, const Bytef *buf, uInt len) { return adler32_z(adler, buf, len); } /* ========================================================================= */ local uLong adler32_combine_( uLong adler1, uLong adler2, z_off64_t len2) { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32_combine( uLong adler1, uLong adler2, z_off_t len2) { return adler32_combine_(adler1, adler2, len2); } uLong ZEXPORT adler32_combine64( uLong adler1, uLong adler2, z_off64_t len2) { return adler32_combine_(adler1, adler2, len2); } stella-5.1.1/src/zlib/compress.c000066400000000000000000000050701324334165500165400ustar00rootroot00000000000000/* compress.c -- compress a memory buffer * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least 0.1% larger than sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ int ZEXPORT compress2 ( Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level) { z_stream stream; int err; const uInt max = (uInt)-1; uLong left; left = *destLen; *destLen = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = deflateInit(&stream, level); if (err != Z_OK) return err; stream.next_out = dest; stream.avail_out = 0; stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; do { if (stream.avail_out == 0) { stream.avail_out = left > (uLong)max ? max : (uInt)left; left -= stream.avail_out; } if (stream.avail_in == 0) { stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; sourceLen -= stream.avail_in; } err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); } while (err == Z_OK); *destLen = stream.total_out; deflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== */ int ZEXPORT compress ( Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) { return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); } /* =========================================================================== If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ uLong ZEXPORT compressBound ( uLong sourceLen) { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13; } stella-5.1.1/src/zlib/crc32.c000066400000000000000000000330661324334165500156270ustar00rootroot00000000000000/* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results in about a * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for STDC and FAR definitions */ /* Definitions for doing the crc four data bytes at a time. */ #if !defined(NOBYFOUR) && defined(Z_U4) # define BYFOUR #endif #ifdef BYFOUR local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, z_size_t)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, z_size_t)); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ /* Local functions for crc concatenation */ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; local z_crc_t FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const z_crc_t FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ local void make_crc_table() { z_crc_t c; int n, k; z_crc_t poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* See if another task is already doing this (not thread-safe, but better than nothing -- significantly reduces duration of vulnerability in case the advice about DYNAMIC_CRC_TABLE is ignored) */ if (first) { first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0; for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) poly |= (z_crc_t)1 << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (z_crc_t)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = ZSWAP32(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = ZSWAP32(c); } } #endif /* BYFOUR */ crc_table_empty = 0; } else { /* not first */ /* wait for the other guy to finish (not efficient, but rare) */ while (crc_table_empty) ; } #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "local const z_crc_t FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH local void write_table( FILE *out, const z_crc_t FAR *table) { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", (unsigned long)(table[n]), n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ const z_crc_t FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t FAR *)crc_table; } /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long ZEXPORT crc32_z( unsigned long crc, const unsigned char FAR *buf, z_size_t len) { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { z_crc_t endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } /* ========================================================================= */ unsigned long ZEXPORT crc32( unsigned long crc, const unsigned char FAR *buf, uInt len) { return crc32_z(crc, buf, len); } #ifdef BYFOUR /* This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit integer pointer type. This violates the strict aliasing rule, where a compiler can assume, for optimization purposes, that two pointers to fundamentally different types won't ever point to the same memory. This can manifest as a problem only if one of the pointers is written to. This code only reads from those pointers. So long as this code remains isolated in this compilation unit, there won't be a problem. For this reason, this code should not be copied and pasted into a compilation unit in which other code writes to the buffer that is passed to these routines. */ /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ local unsigned long crc32_little( unsigned long crc, const unsigned char FAR *buf, z_size_t len) { z_crc_t c; const z_crc_t FAR *buf4; c = (z_crc_t)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *buf4++; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ local unsigned long crc32_big( unsigned long crc, const unsigned char FAR *buf, z_size_t len) { z_crc_t c; const z_crc_t FAR *buf4; c = ZSWAP32((z_crc_t)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(ZSWAP32(c)); } #endif /* BYFOUR */ #define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ /* ========================================================================= */ local unsigned long gf2_matrix_times( unsigned long *mat, unsigned long vec) { unsigned long sum; sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } /* ========================================================================= */ local void gf2_matrix_square( unsigned long *square, unsigned long *mat) { int n; for (n = 0; n < GF2_DIM; n++) square[n] = gf2_matrix_times(mat, mat[n]); } /* ========================================================================= */ local uLong crc32_combine_( uLong crc1, uLong crc2, z_off64_t len2) { int n; unsigned long row; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ /* degenerate case (also disallow negative lengths) */ if (len2 <= 0) return crc1; /* put operator for one zero bit in odd */ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ row = 1; for (n = 1; n < GF2_DIM; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even) */ do { /* apply zeros operator for this bit of len2 */ gf2_matrix_square(even, odd); if (len2 & 1) crc1 = gf2_matrix_times(even, crc1); len2 >>= 1; /* if no more bits set, then done */ if (len2 == 0) break; /* another iteration of the loop with odd and even swapped */ gf2_matrix_square(odd, even); if (len2 & 1) crc1 = gf2_matrix_times(odd, crc1); len2 >>= 1; /* if no more bits set, then done */ } while (len2 != 0); /* return combined crc */ crc1 ^= crc2; return crc1; } /* ========================================================================= */ uLong ZEXPORT crc32_combine( uLong crc1, uLong crc2, z_off_t len2) { return crc32_combine_(crc1, crc2, len2); } uLong ZEXPORT crc32_combine64( uLong crc1, uLong crc2, z_off64_t len2) { return crc32_combine_(crc1, crc2, len2); } stella-5.1.1/src/zlib/crc32.h000066400000000000000000000735421324334165500156370ustar00rootroot00000000000000/* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const z_crc_t FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; stella-5.1.1/src/zlib/deflate.c000066400000000000000000002307641324334165500163230ustar00rootroot00000000000000/* deflate.c -- compress data using the deflation algorithm * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process depends on being able to identify portions * of the input text which are identical to earlier input (within a * sliding window trailing behind the input currently being processed). * * The most straightforward technique turns out to be the fastest for * most input files: try all possible matches and select the longest. * The key feature of this algorithm is that insertions into the string * dictionary are very simple and thus fast, and deletions are avoided * completely. Insertions are performed at each input character, whereas * string matches are performed only when the previous match ends. So it * is preferable to spend more time in matches to allow very fast string * insertions and avoid deletions. The matching algorithm for small * strings is inspired from that of Rabin & Karp. A brute force approach * is used to find longer strings when a small match has been found. * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze * (by Leonid Broukhis). * A previous version of this file used a more sophisticated algorithm * (by Fiala and Greene) which is guaranteed to run in linear amortized * time, but has a larger average cost, uses more memory and is patented. * However the F&G algorithm may be faster for some highly redundant * files if the parameter max_chain_length (described below) is too large. * * ACKNOWLEDGEMENTS * * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and * I found it in 'freeze' written by Leonid Broukhis. * Thanks to many people for bug reports and testing. * * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. * * Fiala,E.R., and Greene,D.H. * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 * */ /* @(#) $Id$ */ #include "deflate.h" #define register const char deflate_copyright[] = " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* =========================================================================== * Function prototypes. */ typedef enum { need_more, /* block not completed, need more input or more output */ block_done, /* block flush performed */ finish_started, /* finish started, need only more output at next deflate */ finish_done /* finish done, accept no more input or output */ } block_state; typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ local int deflateStateCheck OF((z_streamp strm)); local void slide_hash OF((deflate_state *s)); local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); #ifndef FASTEST local block_state deflate_slow OF((deflate_state *s, int flush)); #endif local block_state deflate_rle OF((deflate_state *s, int flush)); local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV # pragma message("Assembler code may have bugs -- use at your own risk") void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif #ifdef ZLIB_DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif /* =========================================================================== * Local data */ #define NIL 0 /* Tail of hash chains */ #ifndef TOO_FAR # define TOO_FAR 4096 #endif /* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ /* Values for max_lazy_match, good_match and max_chain_length, depending on * the desired pack level (0..9). The values given below have been tuned to * exclude worst case performance for pathological files. Better values may be * found for specific files. */ typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; compress_func func; } config; #ifdef FASTEST local const config configuration_table[2] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ #else local const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ /* 2 */ {4, 5, 16, 8, deflate_fast}, /* 3 */ {4, 6, 32, 32, deflate_fast}, /* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ /* 5 */ {8, 16, 32, 32, deflate_slow}, /* 6 */ {8, 16, 128, 128, deflate_slow}, /* 7 */ {8, 32, 128, 256, deflate_slow}, /* 8 */ {32, 128, 258, 1024, deflate_slow}, /* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ #endif /* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to UPDATE_HASH are made with consecutive input * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== * Insert string str in the dictionary and set match_head to the previous head * of the hash chain (the most recent string with same hash key). Return * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. * IN assertion: all calls to INSERT_STRING are made with consecutive input * characters and the first MIN_MATCH bytes of str are valid (except for * the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #else #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ s->head[s->ins_h] = (Pos)(str)) #endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* =========================================================================== * Slide the hash table when sliding the window down (could be avoided with 32 * bit values at the expense of memory usage). We slide even when level == 0 to * keep the hash table consistent if we switch back to level > 0 later. */ local void slide_hash( deflate_state *s) { unsigned n, m; Posf *p; uInt wsize = s->w_size; n = s->hash_size; p = &s->head[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m - wsize : NIL); } while (--n); n = wsize; #ifndef FASTEST p = &s->prev[n]; do { m = *--p; *p = (Pos)(m >= wsize ? m - wsize : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } while (--n); #endif } /* ========================================================================= */ int ZEXPORT deflateInit_( z_streamp strm, int level, const char *version, int stream_size) { return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); /* To do: ignore strm->next_in if we use it as window */ } /* ========================================================================= */ int ZEXPORT deflateInit2_( z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size) { deflate_state *s; int wrap = 1; static const char my_version[] = ZLIB_VERSION; ushf *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; windowBits = -windowBits; } #ifdef GZIP else if (windowBits > 15) { wrap = 2; /* write gzip wrapper instead */ windowBits -= 16; } #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; s->status = INIT_STATE; /* to pass state test in deflateReset() */ s->wrap = wrap; s->gzhead = Z_NULL; s->w_bits = (uInt)windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->high_water = 0; /* nothing written to s->window yet */ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); s->pending_buf = (uchf *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE; strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; } s->d_buf = overlay + s->lit_bufsize/sizeof(ush); s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ local int deflateStateCheck ( z_streamp strm) { deflate_state *s; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; s = strm->state; if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && #ifdef GZIP s->status != GZIP_STATE && #endif s->status != EXTRA_STATE && s->status != NAME_STATE && s->status != COMMENT_STATE && s->status != HCRC_STATE && s->status != BUSY_STATE && s->status != FINISH_STATE)) return 1; return 0; } /* ========================================================================= */ int ZEXPORT deflateSetDictionary ( z_streamp strm, const Bytef *dictionary, uInt dictLength) { deflate_state *s; uInt str, n; int wrap; unsigned avail; z_const unsigned char *next; if (deflateStateCheck(strm) || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) return Z_STREAM_ERROR; /* when using zlib wrappers, compute Adler-32 for provided dictionary */ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength); s->wrap = 0; /* avoid computing Adler-32 in read_buf */ /* if dictionary would fill window, just replace the history */ if (dictLength >= s->w_size) { if (wrap == 0) { /* already empty otherwise */ CLEAR_HASH(s); s->strstart = 0; s->block_start = 0L; s->insert = 0; } dictionary += dictLength - s->w_size; /* use the tail */ dictLength = s->w_size; } /* insert dictionary into window and hash */ avail = strm->avail_in; next = strm->next_in; strm->avail_in = dictLength; strm->next_in = (z_const Bytef *)dictionary; fill_window(s); while (s->lookahead >= MIN_MATCH) { str = s->strstart; n = s->lookahead - (MIN_MATCH-1); do { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; } while (--n); s->strstart = str; s->lookahead = MIN_MATCH-1; fill_window(s); } s->strstart += s->lookahead; s->block_start = (long)s->strstart; s->insert = s->lookahead; s->lookahead = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; strm->next_in = next; strm->avail_in = avail; s->wrap = wrap; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateGetDictionary ( z_streamp strm, Bytef *dictionary, uInt *dictLength) { deflate_state *s; uInt len; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; len = s->strstart + s->lookahead; if (len > s->w_size) len = s->w_size; if (dictionary != Z_NULL && len) zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); if (dictLength != Z_NULL) *dictLength = len; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateResetKeep ( z_streamp strm) { deflate_state *s; if (deflateStateCheck(strm)) { return Z_STREAM_ERROR; } strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } s->status = #ifdef GZIP s->wrap == 2 ? GZIP_STATE : #endif s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); s->last_flush = Z_NO_FLUSH; _tr_init(s); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateReset ( z_streamp strm) { int ret; ret = deflateResetKeep(strm); if (ret == Z_OK) lm_init(strm->state); return ret; } /* ========================================================================= */ int ZEXPORT deflateSetHeader ( z_streamp strm, gz_headerp head) { if (deflateStateCheck(strm) || strm->state->wrap != 2) return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePending ( z_streamp strm, unsigned *pending, int *bits) { if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) *bits = strm->state->bi_valid; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflatePrime ( z_streamp strm, int bits, int value) { deflate_state *s; int put; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do { put = Buf_size - s->bi_valid; if (put > bits) put = bits; s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); s->bi_valid += put; _tr_flush_bits(s); value >>= put; bits -= put; } while (bits); return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateParams( z_streamp strm, int level, int strategy) { deflate_state *s; compress_func func; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST if (level != 0) level = 1; #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && s->high_water) { /* Flush the last buffer: */ int err = deflate(strm, Z_BLOCK); if (err == Z_STREAM_ERROR) return err; if (strm->avail_out == 0) return Z_BUF_ERROR; } if (s->level != level) { if (s->level == 0 && s->matches != 0) { if (s->matches == 1) slide_hash(s); else CLEAR_HASH(s); s->matches = 0; } s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; s->nice_match = configuration_table[level].nice_length; s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; return Z_OK; } /* ========================================================================= */ int ZEXPORT deflateTune( z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain) { deflate_state *s; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; s->good_match = (uInt)good_length; s->max_lazy_match = (uInt)max_lazy; s->nice_match = nice_length; s->max_chain_length = (uInt)max_chain; return Z_OK; } /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. * They are coded as constants here for a reason--if the #define's are * changed, then this function needs to be changed as well. The return * value for 15 and 8 only works for those exact settings. * * For any setting other than those defaults for windowBits and memLevel, * the value returned is a conservative worst case for the maximum expansion * resulting from using fixed blocks instead of stored blocks, which deflate * can emit on compressed data for some combinations of the parameters. * * This function could be more sophisticated to provide closer upper bounds for * every combination of windowBits and memLevel. But even the conservative * upper bound of about 14% expansion does not seem onerous for output buffer * allocation. */ uLong ZEXPORT deflateBound( z_streamp strm, uLong sourceLen) { deflate_state *s; uLong complen, wraplen; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ if (deflateStateCheck(strm)) return complen + 6; /* compute wrapper length */ s = strm->state; switch (s->wrap) { case 0: /* raw deflate */ wraplen = 0; break; case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; #ifdef GZIP case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ Bytef *str; if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; if (str != Z_NULL) do { wraplen++; } while (*str++); str = s->gzhead->comment; if (str != Z_NULL) do { wraplen++; } while (*str++); if (s->gzhead->hcrc) wraplen += 2; } break; #endif default: /* for compiler happiness */ wraplen = 6; } /* if not default parameters, return conservative bound */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) return complen + wraplen; /* default settings: return tight bound for that case */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } /* ========================================================================= * Put a short in the pending buffer. The 16-bit value is put in MSB order. * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ local void putShortMSB ( deflate_state *s, uInt b) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } /* ========================================================================= * Flush as much pending output as possible. All deflate() output, except for * some deflate_stored() output, goes through this function so some * applications may wish to modify it to avoid allocating a large * strm->next_out buffer and copying into it. (See also read_buf()). */ local void flush_pending( z_streamp strm) { unsigned len; deflate_state *s = strm->state; _tr_flush_bits(s); len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len; s->pending_out += len; strm->total_out += len; strm->avail_out -= len; s->pending -= len; if (s->pending == 0) { s->pending_out = s->pending_buf; } } /* =========================================================================== * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. */ #define HCRC_UPDATE(beg) \ do { \ if (s->gzhead->hcrc && s->pending > (beg)) \ strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ s->pending - (beg)); \ } while (0) /* ========================================================================= */ int ZEXPORT deflate ( z_streamp strm, int flush) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || (strm->avail_in != 0 && strm->next_in == Z_NULL) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); old_flush = s->last_flush; s->last_flush = flush; /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) { /* Since avail_out is 0, deflate will be called again with * more output space, but possibly with both pending and * avail_in equal to zero. There won't be anything to do, * but this is not an error situation so make sure we * return OK instead of BUF_ERROR at next call of deflate: */ s->last_flush = -1; return Z_OK; } /* Make sure there is something to do and avoid duplicate consecutive * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); } /* User must not provide more input after the first FINISH: */ if (s->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Write the header */ if (s->status == INIT_STATE) { /* zlib header */ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) level_flags = 0; else if (s->level < 6) level_flags = 1; else if (s->level == 6) level_flags = 2; else level_flags = 3; header |= (level_flags << 6); if (s->strstart != 0) header |= PRESET_DICT; header += 31 - (header % 31); putShortMSB(s, header); /* Save the adler32 of the preset dictionary: */ if (s->strstart != 0) { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } strm->adler = adler32(0L, Z_NULL, 0); s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } #ifdef GZIP if (s->status == GZIP_STATE) { /* gzip header */ strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); if (s->gzhead == Z_NULL) { put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, 0); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, OS_CODE); s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } else { put_byte(s, (s->gzhead->text ? 1 : 0) + (s->gzhead->hcrc ? 2 : 0) + (s->gzhead->extra == Z_NULL ? 0 : 4) + (s->gzhead->name == Z_NULL ? 0 : 8) + (s->gzhead->comment == Z_NULL ? 0 : 16) ); put_byte(s, (Byte)(s->gzhead->time & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); put_byte(s, s->level == 9 ? 2 : (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? 4 : 0)); put_byte(s, s->gzhead->os & 0xff); if (s->gzhead->extra != Z_NULL) { put_byte(s, s->gzhead->extra_len & 0xff); put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); } if (s->gzhead->hcrc) strm->adler = crc32(strm->adler, s->pending_buf, s->pending); s->gzindex = 0; s->status = EXTRA_STATE; } } if (s->status == EXTRA_STATE) { if (s->gzhead->extra != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; while (s->pending + left > s->pending_buf_size) { uInt copy = s->pending_buf_size - s->pending; zmemcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, copy); s->pending = s->pending_buf_size; HCRC_UPDATE(beg); s->gzindex += copy; flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; left -= copy; } zmemcpy(s->pending_buf + s->pending, s->gzhead->extra + s->gzindex, left); s->pending += left; HCRC_UPDATE(beg); s->gzindex = 0; } s->status = NAME_STATE; } if (s->status == NAME_STATE) { if (s->gzhead->name != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { HCRC_UPDATE(beg); flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; } val = s->gzhead->name[s->gzindex++]; put_byte(s, val); } while (val != 0); HCRC_UPDATE(beg); s->gzindex = 0; } s->status = COMMENT_STATE; } if (s->status == COMMENT_STATE) { if (s->gzhead->comment != Z_NULL) { ulg beg = s->pending; /* start of bytes to update crc */ int val; do { if (s->pending == s->pending_buf_size) { HCRC_UPDATE(beg); flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } beg = 0; } val = s->gzhead->comment[s->gzindex++]; put_byte(s, val); } while (val != 0); HCRC_UPDATE(beg); } s->status = HCRC_STATE; } if (s->status == HCRC_STATE) { if (s->gzhead->hcrc) { if (s->pending + 2 > s->pending_buf_size) { flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); strm->adler = crc32(0L, Z_NULL, 0); } s->status = BUSY_STATE; /* Compression must start with an empty pending buffer */ flush_pending(strm); if (s->pending != 0) { s->last_flush = -1; return Z_OK; } } #endif /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; bstate = s->level == 0 ? deflate_stored(s, flush) : s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : s->strategy == Z_RLE ? deflate_rle(s, flush) : (*(configuration_table[s->level].func))(s, flush); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; } if (bstate == need_more || bstate == finish_started) { if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ } return Z_OK; /* If flush != Z_NO_FLUSH && avail_out == 0, the next call * of deflate should use the same flush parameter to make sure * that the flush is complete. So we don't have to output an * empty block here, this will be done at next call. This also * ensures that for a very small output buffer, we emit at most * one empty block. */ } if (bstate == block_done) { if (flush == Z_PARTIAL_FLUSH) { _tr_align(s); } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ _tr_stored_block(s, (char*)0, 0L, 0); /* For a full flush, this empty block will be recognized * as a special marker by inflate_sync(). */ if (flush == Z_FULL_FLUSH) { CLEAR_HASH(s); /* forget history */ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L; s->insert = 0; } } } flush_pending(strm); if (strm->avail_out == 0) { s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ return Z_OK; } } } if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; /* Write the trailer */ #ifdef GZIP if (s->wrap == 2) { put_byte(s, (Byte)(strm->adler & 0xff)); put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); put_byte(s, (Byte)(strm->total_in & 0xff)); put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); } else #endif { putShortMSB(s, (uInt)(strm->adler >> 16)); putShortMSB(s, (uInt)(strm->adler & 0xffff)); } flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ return s->pending != 0 ? Z_OK : Z_STREAM_END; } /* ========================================================================= */ int ZEXPORT deflateEnd ( z_streamp strm) { int status; if (deflateStateCheck(strm)) return Z_STREAM_ERROR; status = strm->state->status; /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } /* ========================================================================= * Copy the source state to the destination state. * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ int ZEXPORT deflateCopy ( z_streamp dest, z_streamp source) { #ifdef MAXSEG_64K return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; ushf *overlay; if (deflateStateCheck(source) || dest == Z_NULL) { return Z_STREAM_ERROR; } ss = source->state; zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); ds->pending_buf = (uchf *) overlay; if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { deflateEnd (dest); return Z_MEM_ERROR; } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; ds->bl_desc.dyn_tree = ds->bl_tree; return Z_OK; #endif /* MAXSEG_64K */ } /* =========================================================================== * Read a new buffer from the current input stream, update the adler32 * and total number of bytes read. All deflate() input goes through * this function so some applications may wish to modify it to avoid * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ local unsigned read_buf( z_streamp strm, Bytef *buf, unsigned size) { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) { strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) { strm->adler = crc32(strm->adler, buf, len); } #endif strm->next_in += len; strm->total_in += len; return len; } /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ local void lm_init ( deflate_state *s) { s->window_size = (ulg)2L*s->w_size; CLEAR_HASH(s); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; #ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif #endif } #ifndef FASTEST /* =========================================================================== * Set match_start to the longest match starting at the given string and * return its length. Matches shorter or equal to prev_length are discarded, * in which case the result is equal to prev_length and match_start is * garbage. * IN assertions: cur_match is the head of the hash chain for the current * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ #ifndef ASMV /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ local uInt longest_match( deflate_state *s, IPos cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ int best_len = (int)s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ Posf *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; register ush scan_end = *(ushf*)(scan+best_len-1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2. Note that the checks below * for insufficient lookahead only occur occasionally for performance * reasons. Therefore uninitialized memory will be accessed, and * conditional jumps will be made that depend on those values. * However the length of the match is limited to the lookahead, so * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ushf*)(match+best_len-1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && *(ushf*)(scan+=2) == *(ushf*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ushf*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length != 0); if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } #endif /* ASMV */ #else /* FASTEST */ /* --------------------------------------------------------------------------- * Optimized version for FASTEST only */ local uInt longest_match( deflate_state *s, IPos cur_match) { register Bytef *scan = s->window + s->strstart; /* current string */ register Bytef *match; /* matched string */ register int len; /* length of current match */ register Bytef *strend = s->window + s->strstart + MAX_MATCH; /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Return failure if the match length is less than 2: */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match += 2; Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); if (len < MIN_MATCH) return MIN_MATCH - 1; s->match_start = cur_match; return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; } #endif /* FASTEST */ #ifdef ZLIB_DEBUG #define EQUAL 0 /* result of memcmp for equal strings */ /* =========================================================================== * Check that the match at match_start is indeed a match. */ local void check_match( deflate_state *s, IPos start, IPos match, int length) { /* check that the match is indeed a match */ if (zmemcmp(s->window + match, s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); } while (--length != 0); z_error("invalid match"); } if (z_verbose > 1) { fprintf(stderr,"\\[%d,%d]", start-match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } #else # define check_match(s, start, match, length) #endif /* ZLIB_DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. * Updates strstart and lookahead. * * IN assertion: lookahead < MIN_LOOKAHEAD * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD * At least one byte has been read, or avail_in == 0; reads are * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ local void fill_window( deflate_state *s) { unsigned n; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (sizeof(int) <= 2) { if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = wsize; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if * strstart == 0 && lookahead == 1 (input done a byte at time) */ more--; } } /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ if (s->strstart >= wsize+MAX_DIST(s)) { zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; slide_hash(s); more += wsize; } if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); s->lookahead += n; /* Initialize the hash value now that we have some input: */ if (s->lookahead + s->insert >= MIN_MATCH) { uInt str = s->strstart - s->insert; s->ins_h = s->window[str]; UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif while (s->insert) { UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); #ifndef FASTEST s->prev[str & s->w_mask] = s->head[s->ins_h]; #endif s->head[s->ins_h] = (Pos)str; str++; s->insert--; if (s->lookahead + s->insert < MIN_MATCH) break; } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted. */ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); /* If the WIN_INIT bytes after the end of the current data have never been * written, then zero those bytes in order to avoid memory check reports of * the use of uninitialized (or uninitialised as Julian writes) bytes by * the longest match routines. Update the high water mark for the next * time through here. WIN_INIT is set to MAX_MATCH since the longest match * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. */ if (s->high_water < s->window_size) { ulg curr = s->strstart + (ulg)(s->lookahead); ulg init; if (s->high_water < curr) { /* Previous high water mark below current data -- zero WIN_INIT * bytes or up to end of window, whichever is less. */ init = s->window_size - curr; if (init > WIN_INIT) init = WIN_INIT; zmemzero(s->window + curr, (unsigned)init); s->high_water = curr + init; } else if (s->high_water < (ulg)curr + WIN_INIT) { /* High water mark at or above current data, but below current data * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up * to end of window, whichever is less. */ init = (ulg)curr + WIN_INIT - s->high_water; if (init > s->window_size - s->high_water) init = s->window_size - s->high_water; zmemzero(s->window + s->high_water, (unsigned)init); s->high_water += init; } } Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, "not enough room for search"); } /* =========================================================================== * Flush the current block, with given end-of-file flag. * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK_ONLY(s, last) { \ _tr_flush_block(s, (s->block_start >= 0L ? \ (charf *)&s->window[(unsigned)s->block_start] : \ (charf *)Z_NULL), \ (ulg)((long)s->strstart - s->block_start), \ (last)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ Tracev((stderr,"[FLUSH]")); \ } /* Same but force premature exit if necessary. */ #define FLUSH_BLOCK(s, last) { \ FLUSH_BLOCK_ONLY(s, last); \ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } /* Maximum stored block length in deflate format (not including header). */ #define MAX_STORED 65535 /* Minimum of a and b. */ #define MIN(a, b) ((a) > (b) ? (b) : (a)) /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. * * In case deflateParams() is used to later switch to a non-zero compression * level, s->matches (otherwise unused when storing) keeps track of the number * of hash table slides to perform. If s->matches is 1, then one hash table * slide will be done when switching. If s->matches is 2, the maximum value * allowed here, then the hash table will be cleared, since two or more slides * is the same as a clear. * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which * maximizes the opportunites to have a single copy from next_in to next_out. */ local block_state deflate_stored( deflate_state *s, int flush) { /* Smallest worthy block size when not flushing or finishing. By default * this is 32K. This can be as small as 507 bytes for memLevel == 1. For * large input and output buffers, the stored block size will be larger. */ unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); /* Copy as many min_block or larger stored blocks directly to next_out as * possible. If flushing, copy the remaining available input to next_out as * stored blocks, if there is enough space. */ unsigned len, left, have, last = 0; unsigned used = s->strm->avail_in; do { /* Set len to the maximum size block that we can copy directly with the * available input data and output space. Set left to how much of that * would be copied from what's left in the window. */ len = MAX_STORED; /* maximum deflate stored block length */ have = (s->bi_valid + 42) >> 3; /* number of header bytes */ if (s->strm->avail_out < have) /* need room for header */ break; /* maximum stored block length that will fit in avail_out: */ have = s->strm->avail_out - have; left = s->strstart - s->block_start; /* bytes left in window */ if (len > (ulg)left + s->strm->avail_in) len = left + s->strm->avail_in; /* limit len to the input */ if (len > have) len = have; /* limit len to the output */ /* If the stored block would be less than min_block in length, or if * unable to copy all of the available input when flushing, then try * copying to the window and the pending buffer instead. Also don't * write an empty block when flushing -- deflate() does that. */ if (len < min_block && ((len == 0 && flush != Z_FINISH) || flush == Z_NO_FLUSH || len != left + s->strm->avail_in)) break; /* Make a dummy stored block in pending to get the header bytes, * including any pending bits. This also updates the debugging counts. */ last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; _tr_stored_block(s, (char *)0, 0L, last); /* Replace the lengths in the dummy stored block with len. */ s->pending_buf[s->pending - 4] = len; s->pending_buf[s->pending - 3] = len >> 8; s->pending_buf[s->pending - 2] = ~len; s->pending_buf[s->pending - 1] = ~len >> 8; /* Write the stored block header bytes. */ flush_pending(s->strm); #ifdef ZLIB_DEBUG /* Update debugging counts for the data about to be copied. */ s->compressed_len += len << 3; s->bits_sent += len << 3; #endif /* Copy uncompressed bytes from the window to next_out. */ if (left) { if (left > len) left = len; zmemcpy(s->strm->next_out, s->window + s->block_start, left); s->strm->next_out += left; s->strm->avail_out -= left; s->strm->total_out += left; s->block_start += left; len -= left; } /* Copy uncompressed bytes directly from next_in to next_out, updating * the check value. */ if (len) { read_buf(s->strm, s->strm->next_out, len); s->strm->next_out += len; s->strm->avail_out -= len; s->strm->total_out += len; } } while (last == 0); /* Update the sliding window with the last s->w_size bytes of the copied * data, or append all of the copied data to the existing window if less * than s->w_size bytes were copied. Also update the number of bytes to * insert in the hash tables, in the event that deflateParams() switches to * a non-zero compression level. */ used -= s->strm->avail_in; /* number of input bytes directly copied */ if (used) { /* If any input was used, then no unused input remains in the window, * therefore s->block_start == s->strstart. */ if (used >= s->w_size) { /* supplant the previous history */ s->matches = 2; /* clear hash */ zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); s->strstart = s->w_size; } else { if (s->window_size - s->strstart <= used) { /* Slide the window down. */ s->strstart -= s->w_size; zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ } zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); s->strstart += used; } s->block_start = s->strstart; s->insert += MIN(used, s->w_size - s->insert); } if (s->high_water < s->strstart) s->high_water = s->strstart; /* If the last block was written to next_out, then done. */ if (last) return finish_done; /* If flushing and all input has been consumed, then done. */ if (flush != Z_NO_FLUSH && flush != Z_FINISH && s->strm->avail_in == 0 && (long)s->strstart == s->block_start) return block_done; /* Fill the window with any remaining input. */ have = s->window_size - s->strstart - 1; if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { /* Slide the window down. */ s->block_start -= s->w_size; s->strstart -= s->w_size; zmemcpy(s->window, s->window + s->w_size, s->strstart); if (s->matches < 2) s->matches++; /* add a pending slide_hash() */ have += s->w_size; /* more space now */ } if (have > s->strm->avail_in) have = s->strm->avail_in; if (have) { read_buf(s->strm, s->window + s->strstart, have); s->strstart += have; } if (s->high_water < s->strstart) s->high_water = s->strstart; /* There was not enough avail_out to write a complete worthy or flushed * stored block to next_out. Write a stored block to pending instead, if we * have enough input for a worthy block, or if flushing and there is enough * room for the remaining input as a stored block in the pending buffer. */ have = (s->bi_valid + 42) >> 3; /* number of header bytes */ /* maximum stored block length that will fit in pending: */ have = MIN(s->pending_buf_size - have, MAX_STORED); min_block = MIN(have, s->w_size); left = s->strstart - s->block_start; if (left >= min_block || ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && s->strm->avail_in == 0 && left <= have)) { len = MIN(left, have); last = flush == Z_FINISH && s->strm->avail_in == 0 && len == left ? 1 : 0; _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); s->block_start += len; flush_pending(s->strm); } /* We've done all we can with the available input and output. */ return last ? finish_started : need_more; } /* =========================================================================== * Compress as much as possible from the input stream, return the current * block state. * This function does not perform lazy evaluation of matches and inserts * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ local block_state deflate_fast( deflate_state *s, int flush) { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); _tr_tally_dist(s, s->strstart - s->match_start, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ #ifndef FASTEST if (s->match_length <= s->max_insert_length && s->lookahead >= MIN_MATCH) { s->match_length--; /* string at strstart already in table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. */ } while (--s->match_length != 0); s->strstart++; } else #endif { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ } } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #ifndef FASTEST /* =========================================================================== * Same as above, but achieves better compression. We use a lazy * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ local block_state deflate_slow( deflate_state *s, int flush) { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; if (s->lookahead >= MIN_MATCH) { INSERT_STRING(s, s->strstart, hash_head); } /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ s->match_length = longest_match (s, hash_head); /* longest_match() sets match_start */ if (s->match_length <= 5 && (s->strategy == Z_FILTERED #if TOO_FAR <= 32767 || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR) #endif )) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ check_match(s, s->strstart-1, s->prev_match, s->prev_length); _tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ s->lookahead -= s->prev_length-1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { INSERT_STRING(s, s->strstart, hash_head); } } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return need_more; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { Tracevv((stderr,"%c", s->window[s->strstart-1])); _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } #endif /* FASTEST */ /* =========================================================================== * For Z_RLE, simply look for runs of bytes, generate matches only of distance * one. Do not maintain a hash table. (It will be regenerated if this run of * deflate switches away from Z_RLE.) */ local block_state deflate_rle( deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ uInt prev; /* byte at distance one to match */ Bytef *scan, *strend; /* scan goes up to strend for length of run */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the longest run, plus one for the unrolled loop. */ if (s->lookahead <= MAX_MATCH) { fill_window(s); if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */ } /* See how many times the previous byte repeats */ s->match_length = 0; if (s->lookahead >= MIN_MATCH && s->strstart > 0) { scan = s->window + s->strstart - 1; prev = *scan; if (prev == *++scan && prev == *++scan && prev == *++scan) { strend = s->window + s->strstart + MAX_MATCH; do { } while (prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); s->match_length = MAX_MATCH - (uInt)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->strstart - 1, s->match_length); _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); s->lookahead -= s->match_length; s->strstart += s->match_length; s->match_length = 0; } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } /* =========================================================================== * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. * (It will be regenerated if this run of deflate switches away from Huffman.) */ local block_state deflate_huff( deflate_state *s, int flush) { int bflush; /* set if current block must be flushed */ for (;;) { /* Make sure that we have a literal to write. */ if (s->lookahead == 0) { fill_window(s); if (s->lookahead == 0) { if (flush == Z_NO_FLUSH) return need_more; break; /* flush the current block */ } } /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); _tr_tally_lit (s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } s->insert = 0; if (flush == Z_FINISH) { FLUSH_BLOCK(s, 1); return finish_done; } if (s->last_lit) FLUSH_BLOCK(s, 0); return block_done; } stella-5.1.1/src/zlib/deflate.h000066400000000000000000000315361324334165500163240ustar00rootroot00000000000000/* deflate.h -- internal compression state * Copyright (C) 1995-2016 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef DEFLATE_H #define DEFLATE_H #include "zutil.h" /* define NO_GZIP when compiling if you want to disable gzip header and trailer creation by deflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip encoding should be left enabled. */ #ifndef NO_GZIP # define GZIP #endif /* =========================================================================== * Internal compression state. */ #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256 /* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30 /* number of distance codes */ #define BL_CODES 19 /* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ #define Buf_size 16 /* size of bit buffer in bi_buf */ #define INIT_STATE 42 /* zlib header -> BUSY_STATE */ #ifdef GZIP # define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ #endif #define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ #define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ #define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ #define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ #define BUSY_STATE 113 /* deflate -> FINISH_STATE */ #define FINISH_STATE 666 /* stream complete */ /* Stream status */ /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } FAR ct_data; #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ const static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; typedef Pos FAR Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to * save space in the various tables. IPos is used only for parameter passing. */ typedef struct internal_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ ulg pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ ulg gzindex; /* where in extra, name, or comment */ Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Bytef *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Posf *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Posf *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ struct tree_desc_s l_desc; /* desc. for literal tree */ struct tree_desc_s d_desc; /* desc. for distance tree */ struct tree_desc_s bl_desc; /* desc. for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uchf *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt last_lit; /* running index in l_buf */ ushf *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ #ifdef ZLIB_DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ ulg high_water; /* High water mark offset in window for initialized bytes -- bytes above * this are set to zero in order to avoid memory check warnings when * longest match routines access bytes past the input. This is then * updated to the new high water mark. */ } FAR deflate_state; /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ #define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) /* Minimum amount of lookahead, except at the end of the input file. * See deflate.c for comments about the MIN_MATCH+1. */ #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) /* In order to simplify the code, particularly on 16 bit machines, match * distances are limited to MAX_DIST instead of WSIZE. */ #define WIN_INIT MAX_MATCH /* Number of bytes after end of data in window to initialize in order to avoid memory checker errors from longest match routines */ /* in trees.c */ void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last)); #define d_code(dist) \ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) /* Mapping from a distance to a distance code. dist is the distance - 1 and * must not have side effects. _dist_code[256] and _dist_code[257] are never * used. */ #ifndef ZLIB_DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) extern uch ZLIB_INTERNAL _length_code[]; extern uch ZLIB_INTERNAL _dist_code[]; #else extern const uch ZLIB_INTERNAL _length_code[]; extern const uch ZLIB_INTERNAL _dist_code[]; #endif # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ s->d_buf[s->last_lit] = 0; \ s->l_buf[s->last_lit++] = cc; \ s->dyn_ltree[cc].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ flush = (s->last_lit == s->lit_bufsize-1); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) # define _tr_tally_dist(s, distance, length, flush) \ flush = _tr_tally(s, distance, length) #endif #endif /* DEFLATE_H */ stella-5.1.1/src/zlib/gzclose.c000066400000000000000000000012411324334165500163470ustar00rootroot00000000000000/* gzclose.c -- zlib gzclose() function * Copyright (C) 2004, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* gzclose() is in a separate file so that it is linked in only if it is used. That way the other gzclose functions can be used instead to avoid linking in unneeded compression or decompression routines. */ int ZEXPORT gzclose( gzFile file) { #ifndef NO_GZCOMPRESS gz_statep state; if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); #else return gzclose_r(file); #endif } stella-5.1.1/src/zlib/gzguts.h000066400000000000000000000152431324334165500162400ustar00rootroot00000000000000/* gzguts.h -- zlib internal header definitions for gz* operations * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #ifdef _LARGEFILE64_SOURCE # ifndef _LARGEFILE_SOURCE # define _LARGEFILE_SOURCE 1 # endif # ifdef _FILE_OFFSET_BITS # undef _FILE_OFFSET_BITS # endif #endif #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include #include "zlib.h" #ifdef STDC # include # include # include #endif #ifndef _POSIX_SOURCE # define _POSIX_SOURCE #endif #include #ifdef _WIN32 # include #endif #if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) # include #endif #if defined(_WIN32) || defined(__CYGWIN__) # define WIDECHAR #endif #ifdef WINAPI_FAMILY # define open _open # define read _read # define write _write # define close _close #endif #ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif #if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(__CYGWIN__) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) # ifndef HAVE_VSNPRINTF # define HAVE_VSNPRINTF # endif #endif #ifndef HAVE_VSNPRINTF # ifdef MSDOS /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), but for now we just assume it doesn't. */ # define NO_vsnprintf # endif # ifdef __TURBOC__ # define NO_vsnprintf # endif # ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ # if !defined(vsnprintf) && !defined(NO_vsnprintf) # if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) # define vsnprintf _vsnprintf # endif # endif # endif # ifdef __SASC # define NO_vsnprintf # endif # ifdef VMS # define NO_vsnprintf # endif # ifdef __OS400__ # define NO_vsnprintf # endif # ifdef __MVS__ # define NO_vsnprintf # endif #endif /* unlike snprintf (which is required in C99), _snprintf does not guarantee null termination of the result -- however this is only used in gzlib.c where the result is assured to fit in the space provided */ #if defined(_MSC_VER) && _MSC_VER < 1900 # define snprintf _snprintf #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ /* gz* functions always use library allocation functions */ #ifndef STDC extern voidp malloc OF((uInt size)); extern void free OF((voidpf ptr)); #endif /* get errno and strerror definition */ #if defined UNDER_CE # include # define zstrerror() gz_strwinerror((DWORD)GetLastError()) #else # ifndef NO_STRERROR # include # define zstrerror() strerror(errno) # else # define zstrerror() "stdio error (consult errno)" # endif #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); #endif /* default memLevel */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default i/o buffer size -- double this for output when reading (this and twice this must be able to fit in an unsigned type) */ #define GZBUFSIZE 8192 /* gzip modes, also provide a little integrity check on the passed structure */ #define GZ_NONE 0 #define GZ_READ 7247 #define GZ_WRITE 31153 #define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ /* values for gz_state how */ #define LOOK 0 /* look for a gzip header */ #define COPY 1 /* copy input directly */ #define GZIP 2 /* decompress a gzip stream */ /* internal gzip file state data structure */ typedef struct { /* exposed contents for gzgetc() macro */ struct gzFile_s x; /* "x" for exposed */ /* x.have: number of bytes available at x.next */ /* x.next: next output data to deliver or write */ /* x.pos: current position in uncompressed data */ /* used for both reading and writing */ int mode; /* see gzip modes above */ int fd; /* file descriptor */ char *path; /* path or fd for error messages */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ unsigned char *in; /* input buffer (double-sized when writing) */ unsigned char *out; /* output buffer (double-sized when reading) */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ int how; /* 0: get header, 1: copy, 2: decompress */ z_off64_t start; /* where the gzip data started, for rewinding */ int eof; /* true if end of input file reached */ int past; /* true if read requested past end */ /* just for writing */ int level; /* compression level */ int strategy; /* compression strategy */ /* seek request */ z_off64_t skip; /* amount to skip (already rewound if backwards) */ int seek; /* true if seek request pending */ /* error information */ int err; /* error code */ char *msg; /* error message */ /* zlib inflate or deflate stream */ z_stream strm; /* stream structure in-place (not a pointer) */ } gz_state; typedef gz_state FAR *gz_statep; /* shared functions */ void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); #if defined UNDER_CE char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); #endif /* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t value -- needed when comparing unsigned to z_off64_t, which is signed (possible z_off64_t types off_t, off64_t, and long are all signed) */ #ifdef INT_MAX # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) #else unsigned ZLIB_INTERNAL gz_intmax OF((void)); # define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) #endif stella-5.1.1/src/zlib/gzlib.c000066400000000000000000000400341324334165500160130ustar00rootroot00000000000000/* gzlib.c -- zlib functions common to reading and writing gzip files * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" #if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__) # define LSEEK _lseeki64 #else #if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 # define LSEEK lseek64 #else # define LSEEK lseek #endif #endif /* Local functions */ local void gz_reset OF((gz_statep)); local gzFile gz_open OF((const void *, int, const char *)); #if defined UNDER_CE /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to gz_strwinerror The gz_strwinerror function does not change the current setting of GetLastError. */ char ZLIB_INTERNAL *gz_strwinerror ( DWORD error) { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, 0, /* Default language */ (LPVOID)&msgbuf, 0, NULL); if (chars != 0) { /* If there is an \r\n appended, zap it. */ if (chars >= 2 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { chars -= 2; msgbuf[chars] = 0; } if (chars > sizeof (buf) - 1) { chars = sizeof (buf) - 1; msgbuf[chars] = 0; } wcstombs(buf, msgbuf, chars + 1); LocalFree(msgbuf); } else { sprintf(buf, "unknown win32 error (%ld)", error); } SetLastError(lasterr); return buf; } #endif /* UNDER_CE */ /* Reset gzip file state */ local void gz_reset( gz_statep state) { state->x.have = 0; /* no output data available */ if (state->mode == GZ_READ) { /* for reading ... */ state->eof = 0; /* not at end of file */ state->past = 0; /* have not read past end yet */ state->how = LOOK; /* look for gzip header */ } state->seek = 0; /* no seek request pending */ gz_error(state, Z_OK, NULL); /* clear error */ state->x.pos = 0; /* no uncompressed data yet */ state->strm.avail_in = 0; /* no input data yet */ } /* Open a gzip file either by name or file descriptor. */ local gzFile gz_open( const void *path, int fd, const char *mode) { gz_statep state; z_size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; #endif #ifdef O_EXCL int exclusive = 0; #endif /* check input */ if (path == NULL) return NULL; /* allocate gzFile structure to return */ state = (gz_statep)malloc(sizeof(gz_state)); if (state == NULL) return NULL; state->size = 0; /* no buffers allocated yet */ state->want = GZBUFSIZE; /* requested buffer size */ state->msg = NULL; /* no error message yet */ /* interpret mode */ state->mode = GZ_NONE; state->level = Z_DEFAULT_COMPRESSION; state->strategy = Z_DEFAULT_STRATEGY; state->direct = 0; while (*mode) { if (*mode >= '0' && *mode <= '9') state->level = *mode - '0'; else switch (*mode) { case 'r': state->mode = GZ_READ; break; #ifndef NO_GZCOMPRESS case 'w': state->mode = GZ_WRITE; break; case 'a': state->mode = GZ_APPEND; break; #endif case '+': /* can't read and write at the same time */ free(state); return NULL; case 'b': /* ignore -- will request binary anyway */ break; #ifdef O_CLOEXEC case 'e': cloexec = 1; break; #endif #ifdef O_EXCL case 'x': exclusive = 1; break; #endif case 'f': state->strategy = Z_FILTERED; break; case 'h': state->strategy = Z_HUFFMAN_ONLY; break; case 'R': state->strategy = Z_RLE; break; case 'F': state->strategy = Z_FIXED; break; case 'T': state->direct = 1; break; default: /* could consider as an error, but just ignore */ ; } mode++; } /* must provide an "r", "w", or "a" */ if (state->mode == GZ_NONE) { free(state); return NULL; } /* can't force transparent read */ if (state->mode == GZ_READ) { if (state->direct) { free(state); return NULL; } state->direct = 1; /* for empty file */ } /* save the path name for error messages */ #ifdef WIDECHAR if (fd == -2) { len = wcstombs(NULL, path, 0); if (len == (z_size_t)-1) len = 0; } else #endif len = strlen((const char *)path); state->path = (char *)malloc(len + 1); if (state->path == NULL) { free(state); return NULL; } #ifdef WIDECHAR if (fd == -2) if (len) wcstombs(state->path, path, len + 1); else *(state->path) = 0; else #endif #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(state->path, len + 1, "%s", (const char *)path); #else strcpy(state->path, path); #endif /* compute the flags for open() */ oflag = #ifdef O_LARGEFILE O_LARGEFILE | #endif #ifdef O_BINARY O_BINARY | #endif #ifdef O_CLOEXEC (cloexec ? O_CLOEXEC : 0) | #endif (state->mode == GZ_READ ? O_RDONLY : (O_WRONLY | O_CREAT | #ifdef O_EXCL (exclusive ? O_EXCL : 0) | #endif (state->mode == GZ_WRITE ? O_TRUNC : O_APPEND))); /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( #ifdef WIDECHAR fd == -2 ? _wopen(path, oflag, 0666) : #endif open((const char *)path, oflag, 0666)); if (state->fd == -1) { free(state->path); free(state); return NULL; } if (state->mode == GZ_APPEND) { LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ state->mode = GZ_WRITE; /* simplify later checks */ } /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { state->start = LSEEK(state->fd, 0, SEEK_CUR); if (state->start == -1) state->start = 0; } /* initialize stream */ gz_reset(state); /* return stream */ return (gzFile)state; } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen( const char *path, const char *mode) { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzopen64( const char *path, const char *mode) { return gz_open(path, -1, mode); } /* -- see zlib.h -- */ gzFile ZEXPORT gzdopen( int fd, const char *mode) { char *path; /* identifier for error messages */ gzFile gz; if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); #else sprintf(path, "", fd); /* for debugging */ #endif gz = gz_open(path, fd, mode); free(path); return gz; } /* -- see zlib.h -- */ #ifdef WIDECHAR gzFile ZEXPORT gzopen_w( const wchar_t *path, const char *mode) { return gz_open(path, -2, mode); } #endif /* -- see zlib.h -- */ int ZEXPORT gzbuffer( gzFile file, unsigned size) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* make sure we haven't already allocated memory */ if (state->size != 0) return -1; /* check and set requested size */ if ((size << 1) < size) return -1; /* need to be able to double it */ if (size < 2) size = 2; /* need two bytes to check magic header */ state->want = size; return 0; } /* -- see zlib.h -- */ int ZEXPORT gzrewind( gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* back up and start over */ if (LSEEK(state->fd, state->start, SEEK_SET) == -1) return -1; gz_reset(state); return 0; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzseek64( gzFile file, z_off64_t offset, int whence) { unsigned n; z_off64_t ret; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* check that there's no error */ if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* can only seek from start or relative to current position */ if (whence != SEEK_SET && whence != SEEK_CUR) return -1; /* normalize offset to a SEEK_CUR specification */ if (whence == SEEK_SET) offset -= state->x.pos; else if (state->seek) offset += state->skip; state->seek = 0; /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; state->eof = 0; state->past = 0; state->seek = 0; gz_error(state, Z_OK, NULL); state->strm.avail_in = 0; state->x.pos += offset; return state->x.pos; } /* calculate skip amount, rewinding if needed for back seek when reading */ if (offset < 0) { if (state->mode != GZ_READ) /* writing -- can't go backwards */ return -1; offset += state->x.pos; if (offset < 0) /* before start of file! */ return -1; if (gzrewind(file) == -1) /* rewind, then skip to offset */ return -1; } /* if reading, skip what's in output buffer (one less gzgetc() check) */ if (state->mode == GZ_READ) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? (unsigned)offset : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; offset -= n; } /* request skip (if not zero) */ if (offset) { state->seek = 1; state->skip = offset; } return state->x.pos + offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzseek( gzFile file, z_off_t offset, int whence) { z_off64_t ret; ret = gzseek64(file, (z_off64_t)offset, whence); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gztell64( gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* return position */ return state->x.pos + (state->seek ? state->skip : 0); } /* -- see zlib.h -- */ z_off_t ZEXPORT gztell( gzFile file) { z_off64_t ret; ret = gztell64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ z_off64_t ZEXPORT gzoffset64( gzFile file) { z_off64_t offset; gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return -1; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return -1; /* compute and return effective offset in file */ offset = LSEEK(state->fd, 0, SEEK_CUR); if (offset == -1) return -1; if (state->mode == GZ_READ) /* reading */ offset -= state->strm.avail_in; /* don't count buffered input */ return offset; } /* -- see zlib.h -- */ z_off_t ZEXPORT gzoffset( gzFile file) { z_off64_t ret; ret = gzoffset64(file); return ret == (z_off_t)ret ? (z_off_t)ret : -1; } /* -- see zlib.h -- */ int ZEXPORT gzeof( gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return 0; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return 0; /* return end-of-file state */ return state->mode == GZ_READ ? state->past : 0; } /* -- see zlib.h -- */ const char * ZEXPORT gzerror( gzFile file, int *errnum) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return NULL; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return NULL; /* return error information */ if (errnum != NULL) *errnum = state->err; return state->err == Z_MEM_ERROR ? "out of memory" : (state->msg == NULL ? "" : state->msg); } /* -- see zlib.h -- */ void ZEXPORT gzclearerr( gzFile file) { gz_statep state; /* get internal structure and check integrity */ if (file == NULL) return; state = (gz_statep)file; if (state->mode != GZ_READ && state->mode != GZ_WRITE) return; /* clear error and end-of-file */ if (state->mode == GZ_READ) { state->eof = 0; state->past = 0; } gz_error(state, Z_OK, NULL); } /* Create an error message in allocated memory and set state->err and state->msg accordingly. Free any previous error message already there. Do not try to free or allocate space if the error is Z_MEM_ERROR (out of memory). Simply save the error message as a static string. If there is an allocation failure constructing the error message, then convert the error to out of memory. */ void ZLIB_INTERNAL gz_error( gz_statep state, int err, const char *msg) { /* free previously allocated message and clear */ if (state->msg != NULL) { if (state->err != Z_MEM_ERROR) free(state->msg); state->msg = NULL; } /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ if (err != Z_OK && err != Z_BUF_ERROR) state->x.have = 0; /* set error code, and if no message, then done */ state->err = err; if (msg == NULL) return; /* for an out of memory error, return literal string when requested */ if (err == Z_MEM_ERROR) return; /* construct error message with path */ if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == NULL) { state->err = Z_MEM_ERROR; return; } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, "%s%s%s", state->path, ": ", msg); #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif } #ifndef INT_MAX /* portably return maximum value for an int (when limits.h presumed not available) -- we need to do this to cover cases where 2's complement not used, since C standard permits 1's complement and sign-bit representations, otherwise we could just use ((unsigned)-1) >> 1 */ unsigned ZLIB_INTERNAL gz_intmax() { unsigned p, q; p = 1; do { q = p; p <<= 1; p++; } while (p > q); return q >> 1; } #endif stella-5.1.1/src/zlib/gzread.c000066400000000000000000000474651324334165500161770ustar00rootroot00000000000000/* gzread.c -- zlib functions for reading gzip files * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); local int gz_avail OF((gz_statep)); local int gz_look OF((gz_statep)); local int gz_decomp OF((gz_statep)); local int gz_fetch OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. This function needs to loop on read(), since read() is not guaranteed to read the number of bytes requested, depending on the type of descriptor. */ local int gz_load( gz_statep state, unsigned char *buf, unsigned len, unsigned *have) { int ret; unsigned get, max = ((unsigned)-1 >> 2) + 1; *have = 0; do { get = len - *have; if (get > max) get = max; ret = read(state->fd, buf + *have, get); if (ret <= 0) break; *have += (unsigned)ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } if (ret == 0) state->eof = 1; return 0; } /* Load up input buffer and set eof flag if last data loaded -- return -1 on error, 0 otherwise. Note that the eof flag is set when the end of the input file is reached, even though there may be unused data in the buffer. Once that data has been used, no more attempts will be made to read the file. If strm->avail_in != 0, then the current data is moved to the beginning of the input buffer, and then the remainder of the buffer is loaded with the available data from the input file. */ local int gz_avail( gz_statep state) { unsigned got; z_streamp strm = &(state->strm); if (state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; if (state->eof == 0) { if (strm->avail_in) { /* copy what's there to the start */ unsigned char *p = state->in; unsigned const char *q = strm->next_in; unsigned n = strm->avail_in; do { *p++ = *q++; } while (--n); } if (gz_load(state, state->in + strm->avail_in, state->size - strm->avail_in, &got) == -1) return -1; strm->avail_in += got; strm->next_in = state->in; } return 0; } /* Look for gzip header, set up for inflate or copy. state->x.have must be 0. If this is the first time in, allocate required memory. state->how will be left unchanged if there is no more input data available, will be set to COPY if there is no gzip header and direct copying will be performed, or it will be set to GZIP for decompression. If direct copying, then leftover input data from the input buffer will be copied to the output buffer. In that case, all further file reads will be directly to either the output buffer or a user buffer. If decompressing, the inflate state will be initialized. gz_look() will return 0 on success or -1 on failure. */ local int gz_look( gz_statep state) { z_streamp strm = &(state->strm); /* allocate read buffers and inflate memory */ if (state->size == 0) { /* allocate buffers */ state->in = (unsigned char *)malloc(state->want); state->out = (unsigned char *)malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } state->size = state->want; /* allocate inflate memory */ state->strm.zalloc = Z_NULL; state->strm.zfree = Z_NULL; state->strm.opaque = Z_NULL; state->strm.avail_in = 0; state->strm.next_in = Z_NULL; if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ free(state->out); free(state->in); state->size = 0; gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } } /* get at least the magic bytes in the input buffer */ if (strm->avail_in < 2) { if (gz_avail(state) == -1) return -1; if (strm->avail_in == 0) return 0; } /* look for gzip magic bytes -- if there, do gzip decoding (note: there is a logical dilemma here when considering the case of a partially written gzip file, to wit, if a single 31 byte is written, then we cannot tell whether this is a single-byte file, or just a partially written gzip file -- for here we assume that if a gzip file is being written, then the header will be written in a single operation, so that reading a single byte is sufficient indication that it is not a gzip file) */ if (strm->avail_in > 1 && strm->next_in[0] == 31 && strm->next_in[1] == 139) { inflateReset(strm); state->how = GZIP; state->direct = 0; return 0; } /* no gzip header -- if we were decoding gzip before, then this is trailing garbage. Ignore the trailing garbage and finish. */ if (state->direct == 0) { strm->avail_in = 0; state->eof = 1; state->x.have = 0; return 0; } /* doing raw i/o, copy any leftover input to output -- this assumes that the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; if (strm->avail_in) { memcpy(state->x.next, strm->next_in, strm->avail_in); state->x.have = strm->avail_in; strm->avail_in = 0; } state->how = COPY; state->direct = 1; return 0; } /* Decompress from input to the provided next_out and avail_out in the state. On return, state->x.have and state->x.next point to the just decompressed data. If the gzip stream completes, state->how is reset to LOOK to look for the next gzip stream or raw data, once state->x.have is depleted. Returns 0 on success, -1 on failure. */ local int gz_decomp( gz_statep state) { int ret = Z_OK; unsigned had; z_streamp strm = &(state->strm); /* fill output buffer up to end of deflate stream */ had = strm->avail_out; do { /* get more input for inflate() */ if (strm->avail_in == 0 && gz_avail(state) == -1) return -1; if (strm->avail_in == 0) { gz_error(state, Z_BUF_ERROR, "unexpected end of file"); break; } /* decompress and handle errors */ ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { gz_error(state, Z_STREAM_ERROR, "internal error: inflate stream corrupt"); return -1; } if (ret == Z_MEM_ERROR) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ gz_error(state, Z_DATA_ERROR, strm->msg == NULL ? "compressed data error" : strm->msg); return -1; } } while (strm->avail_out && ret != Z_STREAM_END); /* update available output */ state->x.have = had - strm->avail_out; state->x.next = strm->next_out - state->x.have; /* if the gzip stream completed successfully, look for another */ if (ret == Z_STREAM_END) state->how = LOOK; /* good decompression */ return 0; } /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. Data is either copied from the input file or decompressed from the input file depending on state->how. If state->how is LOOK, then a gzip header is looked for to determine whether to copy or decompress. Returns -1 on error, otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the end of the input file has been reached and all data has been processed. */ local int gz_fetch( gz_statep state) { z_streamp strm = &(state->strm); do { switch(state->how) { case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ if (gz_look(state) == -1) return -1; if (state->how == LOOK) return 0; break; case COPY: /* -> COPY */ if (gz_load(state, state->out, state->size << 1, &(state->x.have)) == -1) return -1; state->x.next = state->out; return 0; case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ strm->avail_out = state->size << 1; strm->next_out = state->out; if (gz_decomp(state) == -1) return -1; } } while (state->x.have == 0 && (!state->eof || strm->avail_in)); return 0; } /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ local int gz_skip( gz_statep state, z_off64_t len) { unsigned n; /* skip over len bytes or reach end-of-file, whichever comes first */ while (len) /* skip over whatever is in output buffer */ if (state->x.have) { n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? (unsigned)len : state->x.have; state->x.have -= n; state->x.next += n; state->x.pos += n; len -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) break; /* need more data to skip -- load up output buffer */ else { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return -1; } return 0; } /* Read len bytes into buf from file, or less than len up to the end of the input. Return the number of bytes read. If zero is returned, either the end of file was reached, or there was an error. state->err must be consulted in that case to determine which. */ local z_size_t gz_read( gz_statep state, voidp buf, z_size_t len) { z_size_t got; unsigned n; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return 0; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { /* set n to the maximum amount of len that fits in an unsigned int */ n = -1; if (n > len) n = len; /* first just try copying data from the output buffer */ if (state->x.have) { if (state->x.have < n) n = state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ else if (state->eof && state->strm.avail_in == 0) { state->past = 1; /* tried to read past end */ break; } /* need output data -- for small len or new stream load up our output buffer */ else if (state->how == LOOK || n < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) return 0; continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ } /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ if (gz_load(state, (unsigned char *)buf, n, &n) == -1) return 0; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ state->strm.avail_out = n; state->strm.next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) return 0; n = state->x.have; state->x.have = 0; } /* update progress */ len -= n; buf = (char *)buf + n; got += n; state->x.pos += n; } while (len); /* return number of bytes read into user buffer */ return got; } /* -- see zlib.h -- */ int ZEXPORT gzread( gzFile file, voidp buf, unsigned len) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); return -1; } /* read len or fewer bytes to buf */ len = gz_read(state, buf, len); /* check for an error */ if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) return -1; /* return the number of bytes read (this is assured to fit in an int) */ return (int)len; } /* -- see zlib.h -- */ z_size_t ZEXPORT gzfread( voidp buf, z_size_t size, z_size_t nitems, gzFile file) { z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return 0; /* compute bytes to read -- error on overflow */ len = nitems * size; if (size && len / size != nitems) { gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); return 0; } /* read len or fewer bytes to buf, return the number of full items read */ return len ? gz_read(state, buf, len) / size : 0; } /* -- see zlib.h -- */ #ifdef Z_PREFIX_SET # undef z_gzgetc #else # undef gzgetc #endif int ZEXPORT gzgetc( gzFile file) { int ret; unsigned char buf[1]; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* try output buffer (no need to check for skip request) */ if (state->x.have) { state->x.have--; state->x.pos++; return *(state->x.next)++; } /* nothing there -- try gz_read() */ ret = gz_read(state, buf, 1); return ret < 1 ? -1 : buf[0]; } int ZEXPORT gzgetc_( gzFile file) { return gzgetc(file); } /* -- see zlib.h -- */ int ZEXPORT gzungetc( int c, gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return -1; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return -1; } /* can't push EOF */ if (c < 0) return -1; /* if output buffer empty, put byte at end (allows more pushing) */ if (state->x.have == 0) { state->x.have = 1; state->x.next = state->out + (state->size << 1) - 1; state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; } /* if no room, give up (must have already done a gzungetc()) */ if (state->x.have == (state->size << 1)) { gz_error(state, Z_DATA_ERROR, "out of room to push characters"); return -1; } /* slide output data if needed and insert byte before existing data */ if (state->x.next == state->out) { unsigned char *src = state->out + state->x.have; unsigned char *dest = state->out + (state->size << 1); while (src > state->out) *--dest = *--src; state->x.next = dest; } state->x.have++; state->x.next--; state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; } /* -- see zlib.h -- */ char * ZEXPORT gzgets( gzFile file, char *buf, int len) { unsigned left, n; char *str; unsigned char *eol; gz_statep state; /* check parameters and get internal structure */ if (file == NULL || buf == NULL || len < 1) return NULL; state = (gz_statep)file; /* check that we're reading and that there's no (serious) error */ if (state->mode != GZ_READ || (state->err != Z_OK && state->err != Z_BUF_ERROR)) return NULL; /* process a skip request */ if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) return NULL; } /* copy output bytes up to new line or len - 1, whichever comes first -- append a terminating zero to the string (we don't check for a zero in the contents, let the user worry about that) */ str = buf; left = (unsigned)len - 1; if (left) do { /* assure that something is in the output buffer */ if (state->x.have == 0 && gz_fetch(state) == -1) return NULL; /* error */ if (state->x.have == 0) { /* end of file */ state->past = 1; /* read past end */ break; /* return what we have */ } /* look for end-of-line in current output buffer */ n = state->x.have > left ? left : state->x.have; eol = (unsigned char *)memchr(state->x.next, '\n', n); if (eol != NULL) n = (unsigned)(eol - state->x.next) + 1; /* copy through end-of-line, or remainder if not found */ memcpy(buf, state->x.next, n); state->x.have -= n; state->x.next += n; state->x.pos += n; left -= n; buf += n; } while (left && eol == NULL); /* return terminated string, or if nothing, end of file */ if (buf == str) return NULL; buf[0] = 0; return str; } /* -- see zlib.h -- */ int ZEXPORT gzdirect( gzFile file) { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* if the state is not known, but we can find out, then do so (this is mainly for right after a gzopen() or gzdopen()) */ if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) (void)gz_look(state); /* return 1 if transparent, 0 if processing a gzip stream */ return state->direct; } /* -- see zlib.h -- */ int ZEXPORT gzclose_r( gzFile file) { int ret, err; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're reading */ if (state->mode != GZ_READ) return Z_STREAM_ERROR; /* free memory and close file */ if (state->size) { inflateEnd(&(state->strm)); free(state->out); free(state->in); } err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; gz_error(state, Z_OK, NULL); free(state->path); ret = close(state->fd); free(state); return ret ? Z_ERRNO : err; } stella-5.1.1/src/zlib/gzwrite.c000066400000000000000000000452701324334165500164060ustar00rootroot00000000000000/* gzwrite.c -- zlib functions for writing gzip files * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "gzguts.h" /* Local functions */ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); local int gz_zero OF((gz_statep, z_off64_t)); local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); /* Initialize state for writing a gzip file. Mark initialization by setting state->size to non-zero. Return -1 on a memory allocation failure, or 0 on success. */ local int gz_init( gz_statep state) { int ret; z_streamp strm = &(state->strm); /* allocate input buffer (double size for gzprintf) */ state->in = (unsigned char *)malloc(state->want << 1); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* only need output buffer and deflate state if compressing */ if (!state->direct) { /* allocate output buffer */ state->out = (unsigned char *)malloc(state->want); if (state->out == NULL) { free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } /* allocate deflate memory, set up for gzip compression */ strm->zalloc = Z_NULL; strm->zfree = Z_NULL; strm->opaque = Z_NULL; ret = deflateInit2(strm, state->level, Z_DEFLATED, MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); if (ret != Z_OK) { free(state->out); free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } strm->next_in = NULL; } /* mark state as initialized */ state->size = state->want; /* initialize write buffer if compressing */ if (!state->direct) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = strm->next_out; } return 0; } /* Compress whatever is at avail_in and next_in and write to the output file. Return -1 if there is an error writing to the output file or if gz_init() fails to allocate memory, otherwise 0. flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, then the deflate() state is reset to start a new gzip stream. If gz->direct is true, then simply write to the output file without compressing, and ignore flush. */ local int gz_comp( gz_statep state, int flush) { int ret, writ; unsigned have, put, max = ((unsigned)-1 >> 2) + 1; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return -1; /* write directly if requested */ if (state->direct) { while (strm->avail_in) { put = strm->avail_in > max ? max : strm->avail_in; writ = write(state->fd, strm->next_in, put); if (writ < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } strm->avail_in -= (unsigned)writ; strm->next_in += writ; } return 0; } /* run deflate() on provided input until it produces no more output */ ret = Z_OK; do { /* write out current buffer contents if full, or if flushing, but if doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { while (strm->next_out > state->x.next) { put = strm->next_out - state->x.next > (int)max ? max : (unsigned)(strm->next_out - state->x.next); writ = write(state->fd, state->x.next, put); if (writ < 0) { gz_error(state, Z_ERRNO, zstrerror()); return -1; } state->x.next += writ; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; state->x.next = state->out; } } /* compress */ have = strm->avail_out; ret = deflate(strm, flush); if (ret == Z_STREAM_ERROR) { gz_error(state, Z_STREAM_ERROR, "internal error: deflate stream corrupt"); return -1; } have -= strm->avail_out; } while (have); /* if that completed a deflate stream, allow another to start */ if (flush == Z_FINISH) deflateReset(strm); /* all done, no errors */ return 0; } /* Compress len zeros to output. Return -1 on a write error or memory allocation failure by gz_comp(), or 0 on success. */ local int gz_zero( gz_statep state, z_off64_t len) { int first; unsigned n; z_streamp strm = &(state->strm); /* consume whatever's left in the input buffer */ if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return -1; /* compress len zeros (len guaranteed > 0) */ first = 1; while (len) { n = GT_OFF(state->size) || (z_off64_t)state->size > len ? (unsigned)len : state->size; if (first) { memset(state->in, 0, n); first = 0; } strm->avail_in = n; strm->next_in = state->in; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return -1; len -= n; } return 0; } /* Write len bytes from buf to file. Return the number of bytes written. If the returned value is less than len, then there was an error. */ local z_size_t gz_write( gz_statep state, voidpc buf, z_size_t len) { z_size_t put = len; /* if len is zero, avoid unnecessary operations */ if (len == 0) return 0; /* allocate memory if this is the first time through */ if (state->size == 0 && gz_init(state) == -1) return 0; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return 0; } /* for small len, copy to input buffer, otherwise compress directly */ if (len < state->size) { /* copy to input buffer, compress when full */ do { unsigned have, copy; if (state->strm.avail_in == 0) state->strm.next_in = state->in; have = (unsigned)((state->strm.next_in + state->strm.avail_in) - state->in); copy = state->size - have; if (copy > len) copy = len; memcpy(state->in + have, buf, copy); state->strm.avail_in += copy; state->x.pos += copy; buf = (const char *)buf + copy; len -= copy; if (len && gz_comp(state, Z_NO_FLUSH) == -1) return 0; } while (len); } else { /* consume whatever's left in the input buffer */ if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ state->strm.next_in = (z_const Bytef *)buf; do { unsigned n = (unsigned)-1; if (n > len) n = len; state->strm.avail_in = n; state->x.pos += n; if (gz_comp(state, Z_NO_FLUSH) == -1) return 0; len -= n; } while (len); } /* input was all buffered or compressed */ return put; } /* -- see zlib.h -- */ int ZEXPORT gzwrite( gzFile file, voidpc buf, unsigned len) { gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* since an int is returned, make sure len fits in one, otherwise return with an error (this avoids a flaw in the interface) */ if ((int)len < 0) { gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); return 0; } /* write len bytes from buf (the return value will fit in an int) */ return (int)gz_write(state, buf, len); } /* -- see zlib.h -- */ z_size_t ZEXPORT gzfwrite( voidpc buf, z_size_t size, z_size_t nitems, gzFile file) { z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return 0; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return 0; /* compute bytes to read -- error on overflow */ len = nitems * size; if (size && len / size != nitems) { gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); return 0; } /* write len bytes to buf, return the number of full items written */ return len ? gz_write(state, buf, len) / size : 0; } /* -- see zlib.h -- */ int ZEXPORT gzputc( gzFile file, int c) { unsigned have; unsigned char buf[1]; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return -1; } /* try writing to input buffer for speed (state->size == 0 if buffer not initialized) */ if (state->size) { if (strm->avail_in == 0) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); if (have < state->size) { state->in[have] = (unsigned char)c; strm->avail_in++; state->x.pos++; return c & 0xff; } } /* no room in buffer or not initialized, use gz_write() */ buf[0] = (unsigned char)c; if (gz_write(state, buf, 1) != 1) return -1; return c & 0xff; } /* -- see zlib.h -- */ int ZEXPORT gzputs( gzFile file, const char *str) { int ret; z_size_t len; gz_statep state; /* get internal structure */ if (file == NULL) return -1; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return -1; /* write string */ len = strlen(str); ret = gz_write(state, str, len); return ret == 0 && len != 0 ? -1 : ret; } #if defined(STDC) || defined(Z_HAVE_STDARG_H) #include /* -- see zlib.h -- */ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { int len; unsigned left; char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return state->err; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* do the printf() into the input buffer, put length in len -- the input buffer is double-sized just for this function, so there is guaranteed to be state->size bytes available after the current contents */ if (strm->avail_in == 0) strm->next_in = state->in; next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); next[state->size - 1] = 0; #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void (void)vsprintf(next, format, va); for (len = 0; len < state->size; len++) if (next[len] == 0) break; # else len = vsprintf(next, format, va); # endif #else # ifdef HAS_vsnprintf_void (void)vsnprintf(next, state->size, format, va); len = strlen(next); # else len = vsnprintf(next, state->size, format, va); # endif #endif /* check that printf() results fit in buffer */ if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) return 0; /* update buffer and position, compress first half if past that */ strm->avail_in += (unsigned)len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; memcpy(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return len; } int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) { va_list va; int ret; va_start(va, format); ret = gzvprintf(file, format, va); va_end(va); return ret; } #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ int ZEXPORTVA gzprintf ( gzFile file, const char *format, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20) { unsigned len, left; char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that can really pass pointer in ints */ if (sizeof(int) != sizeof(void *)) return Z_STREAM_ERROR; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) return state->error; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->error; } /* do the printf() into the input buffer, put length in len -- the input buffer is double-sized just for this function, so there is guaranteed to be state->size bytes available after the current contents */ if (strm->avail_in == 0) strm->next_in = state->in; next = (char *)(strm->next_in + strm->avail_in); next[state->size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) if (next[len] == 0) break; # else len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); len = strlen(next); # else len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif /* check that printf() results fit in buffer */ if (len == 0 || len >= state->size || next[state->size - 1] != 0) return 0; /* update buffer and position, compress first half if past that */ strm->avail_in += len; state->x.pos += len; if (strm->avail_in >= state->size) { left = strm->avail_in - state->size; strm->avail_in = state->size; if (gz_comp(state, Z_NO_FLUSH) == -1) return state->err; memcpy(state->in, state->in + state->size, left); strm->next_in = state->in; strm->avail_in = left; } return (int)len; } #endif /* -- see zlib.h -- */ int ZEXPORT gzflush( gzFile file, int flush) { gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* check flush parameter */ if (flush < 0 || flush > Z_FINISH) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* compress remaining data with requested flush */ (void)gz_comp(state, flush); return state->err; } /* -- see zlib.h -- */ int ZEXPORT gzsetparams( gzFile file, int level, int strategy) { gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) return Z_STREAM_ERROR; /* if no change is requested, then do nothing */ if (level == state->level && strategy == state->strategy) return Z_OK; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) return state->err; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) return state->err; deflateParams(strm, level, strategy); } state->level = level; state->strategy = strategy; return Z_OK; } /* -- see zlib.h -- */ int ZEXPORT gzclose_w( gzFile file) { int ret = Z_OK; gz_statep state; /* get internal structure */ if (file == NULL) return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing */ if (state->mode != GZ_WRITE) return Z_STREAM_ERROR; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) ret = state->err; } /* flush, free memory, and close file */ if (gz_comp(state, Z_FINISH) == -1) ret = state->err; if (state->size) { if (!state->direct) { (void)deflateEnd(&(state->strm)); free(state->out); } free(state->in); } gz_error(state, Z_OK, NULL); free(state->path); if (close(state->fd) == -1) ret = Z_ERRNO; free(state); return ret; } stella-5.1.1/src/zlib/infback.c000066400000000000000000000542201324334165500163030ustar00rootroot00000000000000/* infback.c -- inflate using a call-back interface * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* This code is largely copied from inflate.c. Normally either infback.o or inflate.o would be linked into an application--not both. The interface with inffast.c is retained so that optimized assembler-coded versions of inflate_fast() can be used with either inflate.c or infback.c. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state)); /* strm provides memory allocation functions in zalloc and zfree, or Z_NULL to use the library memory allocation functions. windowBits is in the range 8..15, and window is a user-supplied window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_( z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size) { struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL || window == Z_NULL || windowBits < 8 || windowBits > 15) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; state->whave = 0; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables( struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } /* Macros for inflateBack(): */ /* Load returned state from inflate_fast() */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Set state from registers for inflate_fast() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Assure that some input is available. If input is requested, but denied, then return a Z_BUF_ERROR from inflateBack(). */ #define PULL() \ do { \ if (have == 0) { \ have = in(in_desc, &next); \ if (have == 0) { \ next = Z_NULL; \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflateBack() with an error if there is no input available. */ #define PULLBYTE() \ do { \ PULL(); \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflateBack() with an error. */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* Assure that some output space is available, by writing out the window if it's full. If the write fails, return from inflateBack() with a Z_BUF_ERROR. */ #define ROOM() \ do { \ if (left == 0) { \ put = state->window; \ left = state->wsize; \ state->whave = left; \ if (out(out_desc, put, left)) { \ ret = Z_BUF_ERROR; \ goto inf_leave; \ } \ } \ } while (0) /* strm provides the memory allocation functions and window buffer on input, and provides information on the unused input on return. For Z_DATA_ERROR returns, strm will also provide an error message. in() and out() are the call-back input and output functions. When inflateBack() needs more input, it calls in(). When inflateBack() has filled the window with output, or when it completes with data in the window, it calls out() to write out the data. The application must not change the provided input until in() is called again or inflateBack() returns. The application must not change the window/output buffer until inflateBack() returns. in() and out() are called with a descriptor parameter provided in the inflateBack() call. This parameter can be a structure that provides the information required to do the read or write, as well as accumulated information on the input and output such as totals and check values. in() should return zero on failure. out() should return non-zero on failure. If either in() or out() fails, than inflateBack() returns a Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it was in() or out() that caused in the error. Otherwise, inflateBack() returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format error, or Z_MEM_ERROR if it could not allocate memory for the state. inflateBack() can also return Z_STREAM_ERROR if the input parameters are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack( z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* Check that the strm exists and that the state was initialized */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* Reset the state */ strm->msg = Z_NULL; state->mode = TYPE; state->last = 0; state->whave = 0; next = strm->next_in; have = next != Z_NULL ? strm->avail_in : 0; hold = 0; bits = 0; put = state->window; left = state->wsize; /* Inflate until end of block marked as last */ for (;;) switch (state->mode) { case TYPE: /* determine and dispatch block type */ if (state->last) { BYTEBITS(); state->mode = DONE; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN; /* decode codes */ break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: /* get and verify stored block length */ BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); /* copy stored block from input to output */ while (state->length != 0) { copy = state->length; PULL(); ROOM(); if (copy > have) copy = have; if (copy > left) copy = left; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: /* get dynamic table entries descriptor */ NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); /* get code length code lengths (not a typo) */ state->have = 0; while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); /* get length and distance code code lengths */ state->have = 0; while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = (unsigned)(state->lens[state->have - 1]); copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (code const FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (code const FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN; case LEN: /* use inflate_fast() if we have enough input and output */ if (have >= 6 && left >= 258) { RESTORE(); if (state->whave < state->wsize) state->whave = state->wsize - left; inflate_fast(strm, state->wsize); LOAD(); break; } /* get a literal, length, or end-of-block code */ for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); state->length = (unsigned)here.val; /* process literal */ if (here.op == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); ROOM(); *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; } /* process end of block */ if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } /* invalid code */ if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } /* length code -- get extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); } Tracevv((stderr, "inflate: length %u\n", state->length)); /* get distance code */ for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); } DROPBITS(here.bits); if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; /* get distance extra bits, if any */ state->extra = (unsigned)(here.op) & 15; if (state->extra != 0) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); } if (state->offset > state->wsize - (state->whave < state->wsize ? left : 0)) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } Tracevv((stderr, "inflate: distance %u\n", state->offset)); /* copy match from window to output */ do { ROOM(); copy = state->wsize - state->offset; if (copy < left) { from = put + copy; copy = left - copy; } else { from = put - state->offset; copy = left; } if (copy > state->length) copy = state->length; state->length -= copy; left -= copy; do { *put++ = *from++; } while (--copy); } while (state->length != 0); break; case DONE: /* inflate stream terminated properly -- write leftover output */ ret = Z_STREAM_END; if (left < state->wsize) { if (out(out_desc, state->window, state->wsize - left)) ret = Z_BUF_ERROR; } goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; default: /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } /* Return unused input */ inf_leave: strm->next_in = next; strm->avail_in = have; return ret; } int ZEXPORT inflateBackEnd( z_streamp strm) { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } stella-5.1.1/src/zlib/inffast.c000066400000000000000000000311611324334165500163370ustar00rootroot00000000000000/* inffast.c -- fast decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef ASMINF # pragma message("Assembler code may have bugs -- use at your own risk") #else /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast( z_streamp strm, unsigned start) { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in; last = in + (strm->avail_in - 5); out = strm->next_out; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op == 0) { /* literal */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); *out++ = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = dcode[hold & dmask]; dodist: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op & 16) { /* distance base */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { *out++ = 0; } while (--len); continue; } len -= op - whave; do { *out++ = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { *out++ = *from++; } while (--len); continue; } #endif } from = window; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { *out++ = *from++; } while (--op); from = window; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { *out++ = *from++; *out++ = *from++; *out++ = *from++; len -= 3; } if (len) { *out++ = *from++; if (len > 1) *out++ = *from++; } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ *out++ = *from++; *out++ = *from++; *out++ = *from++; len -= 3; } while (len > 2); if (len) { *out++ = *from++; if (len > 1) *out++ = *from++; } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode[here.val + (hold & ((1U << op) - 1))]; goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode[here.val + (hold & ((1U << op) - 1))]; goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in; strm->next_out = out; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ #endif /* !ASMINF */ stella-5.1.1/src/zlib/inffast.h000066400000000000000000000006531324334165500163460ustar00rootroot00000000000000/* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); stella-5.1.1/src/zlib/inffixed.h000066400000000000000000000142741324334165500165140ustar00rootroot00000000000000 /* inffixed.h -- table for decoding fixed codes * Generated automatically by makefixed(). */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of this library and is subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {0,9,255} }; static const code distfix[32] = { {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {22,5,193},{64,5,0} }; stella-5.1.1/src/zlib/inflate.c000066400000000000000000001526221324334165500163350ustar00rootroot00000000000000/* inflate.c -- zlib decompression * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ local int inflateStateCheck OF((z_streamp strm)); local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, unsigned copy)); #ifdef BUILDFIXED void makefixed OF((void)); #endif local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); local int inflateStateCheck( z_streamp strm) { struct inflate_state FAR *state; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; state = (struct inflate_state FAR *)strm->state; if (state == Z_NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC) return 1; return 0; } int ZEXPORT inflateResetKeep( z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset( z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; return inflateResetKeep(strm); } int ZEXPORT inflateReset2( z_streamp strm, int windowBits) { int wrap; struct inflate_state FAR *state; /* get the state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 5; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_( z_streamp strm, int windowBits, const char *version, int stream_size) { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->strm = strm; state->window = Z_NULL; state->mode = HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_( z_streamp strm, const char *version, int stream_size) { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime( z_streamp strm, int bits, int value) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += (unsigned)value << state->bits; state->bits += (uInt)bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables( struct inflate_state FAR *state) { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed() { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow( z_streamp strm, const Bytef *end, unsigned copy) { struct inflate_state FAR *state; unsigned dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char FAR *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ if (copy >= state->wsize) { zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, end - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate( z_streamp strm, int flush) { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (inflateStateCheck(strm) || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ if (state->wbits == 0) state->wbits = 15; state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; if (len > 15 || len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if ((state->wrap & 4) && hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (const code FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if ((state->wrap & 4) && ( #ifdef GUNZIP state->flags ? hold : #endif ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if (hold != (state->total & 0xffffffffUL)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (out != strm->avail_out && state->mode < BAD && (state->mode < CHECK || flush != Z_FINISH))) if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd( z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateGetDictionary( z_streamp strm, Bytef *dictionary, uInt *dictLength) { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ if (state->whave && dictionary != Z_NULL) { zmemcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); zmemcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); } if (dictLength != Z_NULL) *dictLength = state->whave; return Z_OK; } int ZEXPORT inflateSetDictionary( z_streamp strm, const Bytef *dictionary, uInt dictLength) { struct inflate_state FAR *state; unsigned long dictid; int ret; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary identifier */ if (state->mode == DICT) { dictid = adler32(0L, Z_NULL, 0); dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; } /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ ret = updatewindow(strm, dictionary + dictLength, dictLength); if (ret) { state->mode = MEM; return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader( z_streamp strm, gz_headerp head) { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch( unsigned FAR *have, const unsigned char FAR *buf, unsigned len) { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync( z_streamp strm) { unsigned len; /* number of bytes to look at or looked at */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint( z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy( z_streamp dest, z_streamp source) { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (inflateStateCheck(source) || dest == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; /* allocate space */ copy = (struct inflate_state FAR *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); copy->strm = dest; if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine( z_streamp strm, int subvert) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR state->sane = !subvert; return Z_OK; #else (void)subvert; state->sane = 1; return Z_DATA_ERROR; #endif } int ZEXPORT inflateValidate( z_streamp strm, int check) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (check) state->wrap |= 4; else state->wrap &= ~4; return Z_OK; } long ZEXPORT inflateMark( z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return -(1L << 16); state = (struct inflate_state FAR *)strm->state; return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } unsigned long ZEXPORT inflateCodesUsed( z_streamp strm) { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return (unsigned long)-1; state = (struct inflate_state FAR *)strm->state; return (unsigned long)(state->next - state->codes); } stella-5.1.1/src/zlib/inflate.h000066400000000000000000000147321324334165500163410ustar00rootroot00000000000000/* inflate.h -- internal inflate state definition * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif /* Possible inflate modes between inflate() calls */ typedef enum { HEAD = 16180, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ EXLEN, /* i: waiting for extra length (gzip) */ EXTRA, /* i: waiting for extra bytes (gzip) */ NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ TYPEDO, /* i: same, but skip check to exit inflate on new block */ STORED, /* i: waiting for stored size (length and complement) */ COPY_, /* i/o: same as COPY below, but only first time in */ COPY, /* i/o: waiting for input or output to copy stored block */ TABLE, /* i: waiting for dynamic block table lengths */ LENLENS, /* i: waiting for code length code lengths */ CODELENS, /* i: waiting for length/lit and distance code lengths */ LEN_, /* i: same as LEN below, but only first time in */ LEN, /* i: waiting for length/lit/eob code */ LENEXT, /* i: waiting for length extra bits */ DIST, /* i: waiting for distance code */ DISTEXT, /* i: waiting for distance extra bits */ MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> HCRC -> TYPE (zlib) -> DICTID or TYPE DICTID -> DICT -> TYPE (raw) -> TYPEDO Read deflate blocks: TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK STORED -> COPY_ -> COPY -> TYPE TABLE -> LENLENS -> CODELENS -> LEN_ LEN_ -> LEN Read deflate codes in fixed or dynamic block: LEN -> LENEXT or LIT or TYPE LENEXT -> DIST -> DISTEXT -> MATCH -> LEN LIT -> LEN Process trailer: CHECK -> LENGTH -> DONE */ /* State maintained between inflate() calls -- approximately 7K bytes, not including the allocated sliding window, which is up to 32K bytes. */ struct inflate_state { z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if needed */ /* bit accumulator */ unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ /* for string and stored block copying */ unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ /* fixed and dynamic code tables */ code const FAR *lencode; /* starting table for length/literal codes */ code const FAR *distcode; /* starting table for distance codes */ unsigned lenbits; /* index bits for lencode */ unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ unsigned have; /* number of code lengths in lens[] */ code FAR *next; /* next available space in codes[] */ unsigned short lens[320]; /* temporary storage for code lengths */ unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ int sane; /* if false, allow invalid distance too far */ int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; stella-5.1.1/src/zlib/inftrees.c000066400000000000000000000312721324334165500165270ustar00rootroot00000000000000/* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table( codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work) { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ unsigned match; /* use base and extra for symbol >= match */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ match = 20; break; case LENS: base = lbase; extra = lext; match = 257; break; default: /* DISTS */ base = dbase; extra = dext; match = 0; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if (work[sym] + 1U < match) { here.op = (unsigned char)0; here.val = work[sym]; } else if (work[sym] >= match) { here.op = (unsigned char)(extra[work[sym] - match]); here.val = base[work[sym] - match]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ if (huff != 0) { here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; next[huff] = here; } /* set return parameters */ *table += used; *bits = root; return 0; } stella-5.1.1/src/zlib/inftrees.h000066400000000000000000000055601324334165500165350ustar00rootroot00000000000000/* inftrees.h -- header to use inftrees.c * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* Structure for decoding tables. Each entry provides either the information needed to do the operation requested by the code that indexed that table entry, or it provides a pointer to another table that indexes more bits of the code. op indicates whether the entry is a pointer to another table, a literal, a length or distance, an end-of-block, or an invalid code. For a table pointer, the low four bits of op is the number of index bits of that table. For a length or distance, the low four bits of op is the number of extra bits to get after the code. bits is the number of bits in this code or part of the code to drop off of the bit buffer. val is the actual byte to output in the case of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { unsigned char op; /* operation, extra bits, table bits */ unsigned char bits; /* bits in this part of the code */ unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work)); stella-5.1.1/src/zlib/module.mk000066400000000000000000000006721324334165500163620ustar00rootroot00000000000000MODULE := src/zlib MODULE_OBJS := \ src/zlib/adler32.o \ src/zlib/compress.o \ src/zlib/crc32.o \ src/zlib/gzclose.o \ src/zlib/gzlib.o \ src/zlib/gzread.o \ src/zlib/gzwrite.o \ src/zlib/uncompr.o \ src/zlib/deflate.o \ src/zlib/trees.o \ src/zlib/zutil.o \ src/zlib/inflate.o \ src/zlib/infback.o \ src/zlib/inftrees.o \ src/zlib/inffast.o MODULE_DIRS += \ src/zlib # Include common rules include $(srcdir)/common.rules stella-5.1.1/src/zlib/trees.c000066400000000000000000001231741324334165500160350ustar00rootroot00000000000000/* trees.c -- output deflated data using Huffman coding * Copyright (C) 1995-2017 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ /* * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. */ /* @(#) $Id$ */ /* #define GEN_TREES_H */ #include "deflate.h" #ifdef ZLIB_DEBUG # include #endif #define register /* =========================================================================== * Constants */ #define MAX_BL_BITS 7 /* Bit length codes must not exceed MAX_BL_BITS bits */ #define END_BLOCK 256 /* end of block literal code */ #define REP_3_6 16 /* repeat previous bit length 3-6 times (2 bits of repeat count) */ #define REPZ_3_10 17 /* repeat a zero length 3-10 times (3 bits of repeat count) */ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; local const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; local const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. */ /* =========================================================================== * Local data. These are initialized only once. */ #define DIST_CODE_LEN 512 /* see definition of array dist_code below */ #if defined(GEN_TREES_H) || !defined(STDC) /* non ANSI compilers may not accept trees.h */ local ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see _tr_init * below). */ local ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ uch _dist_code[DIST_CODE_LEN]; /* Distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ uch _length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ local int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ local int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ #else # include "trees.h" #endif /* GEN_TREES_H */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ const intf *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; local const static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local const static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local const static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ local void tr_static_init OF((void)); local void init_block OF((deflate_state *s)); local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); local void build_tree OF((deflate_state *s, tree_desc *desc)); local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); local int build_bl_tree OF((deflate_state *s)); local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, int blcodes)); local void compress_block OF((deflate_state *s, const ct_data *ltree, const ct_data *dtree)); local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif #ifndef ZLIB_DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ #else /* !ZLIB_DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } #endif /* =========================================================================== * Output a short LSB first on the stream. * IN assertion: there is enough room in pendingBuf. */ #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } /* =========================================================================== * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ #ifdef ZLIB_DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits( deflate_state *s, int value, int length) { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (ush)value << s->bi_valid; put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= (ush)value << s->bi_valid; s->bi_valid += length; } } #else /* !ZLIB_DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ int val = (int)value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ s->bi_valid += len - Buf_size;\ } else {\ s->bi_buf |= (ush)(value) << s->bi_valid;\ s->bi_valid += len;\ }\ } #endif /* ZLIB_DEBUG */ /* the arguments must not have side effects */ /* =========================================================================== * Initialize the various 'constant' tables. */ local void tr_static_init() { #if defined(GEN_TREES_H) || !defined(STDC) static int static_init_done = 0; int n; /* iterates over tree elements */ int bits; /* bit counter */ int length; /* length value */ int code; /* code value */ int dist; /* distance index */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ if (static_init_done) return; /* For some embedded targets, global variables are not initialized: */ #ifdef NO_INIT_GLOBAL_POINTERS static_l_desc.static_tree = static_ltree; static_l_desc.extra_bits = extra_lbits; static_d_desc.static_tree = static_dtree; static_d_desc.extra_bits = extra_dbits; static_bl_desc.extra_bits = extra_blbits; #endif /* Initialize the mapping length (0..255) -> length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { _dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "tr_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse((unsigned)n, 5); } static_init_done = 1; # ifdef GEN_TREES_H gen_trees_header(); # endif #endif /* defined(GEN_TREES_H) || !defined(STDC) */ } /* =========================================================================== * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG # include # endif # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ ((i) % (width) == (width)-1 ? ",\n" : ", ")) void gen_trees_header() { FILE *header = fopen("trees.h", "w"); int i; Assert (header != NULL, "Can't open trees.h"); fprintf(header, "/* header created automatically with -DGEN_TREES_H */\n\n"); fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); for (i = 0; i < L_CODES+2; i++) { fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); } fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); } fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); for (i = 0; i < DIST_CODE_LEN; i++) { fprintf(header, "%2u%s", _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); } fprintf(header, "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { fprintf(header, "%2u%s", _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); } fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); for (i = 0; i < LENGTH_CODES; i++) { fprintf(header, "%1u%s", base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); } fprintf(header, "local const int base_dist[D_CODES] = {\n"); for (i = 0; i < D_CODES; i++) { fprintf(header, "%5u%s", base_dist[i], SEPARATOR(i, D_CODES-1, 10)); } fclose(header); } #endif /* GEN_TREES_H */ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ void ZLIB_INTERNAL _tr_init( deflate_state *s) { tr_static_init(); s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } /* =========================================================================== * Initialize a new block. */ local void init_block( deflate_state *s) { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->last_lit = s->matches = 0; } #define SMALLEST 1 /* Index within the heap array of least frequent node in the Huffman tree */ /* =========================================================================== * Remove the smallest element from the heap and recreate the heap with * one less element. Updates heap and heap_len. */ #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } /* =========================================================================== * Compares to subtrees, using the tree depth as tie breaker when * the subtrees have equal frequency. This minimizes the worst case length. */ #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) /* =========================================================================== * Restore the heap property by moving down the tree starting at node k, * exchanging a node with the smallest of its two sons if necessary, stopping * when the heap property is re-established (each father smaller than its * two sons). */ local void pqdownheap( deflate_state *s, ct_data *tree, int k) { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } /* =========================================================================== * Compute the optimal bit lengths for a tree and update the total bit length * for the current block. * IN assertion: the fields freq and dad are set, heap[heap_max] and * above are the tree nodes sorted by increasing frequency. * OUT assertions: the field len is set to the optimal bit length, the * array bl_count contains the frequencies for each bit length. * The length opt_len is updated; static_len is also updated if stree is * not null. */ local void gen_bitlen( deflate_state *s, tree_desc *desc) { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; const intf *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); } if (overflow == 0) return; Tracev((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } /* =========================================================================== * Generate the codes for a given tree and bit counts (which need not be * optimal). * IN assertion: the array bl_count contains the bit length statistics for * the given tree and the field len is set for all tree elements. * OUT assertion: the field code is set for all tree elements of non * zero code length. */ local void gen_codes ( ct_data *tree, int max_code, ushf *bl_count) { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ unsigned code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { code = (code + bl_count[bits-1]) << 1; next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[node].Freq = 1; s->depth[node] = 0; s->opt_len--; if (stree) s->static_len -= stree[node].Len; /* node is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ node = elems; /* next internal node of the tree */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? s->depth[n] : s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } /* =========================================================================== * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ local void scan_tree ( deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ local void send_tree ( deflate_state *s, ct_data *tree, int max_code) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } /* =========================================================================== * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ local int build_bl_tree( deflate_state *s) { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); return max_blindex; } /* =========================================================================== * Send the header for a block using dynamic Huffman trees: the counts, the * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ local void send_all_trees( deflate_state *s, int lcodes, int dcodes, int blcodes) { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } /* =========================================================================== * Send a stored block */ void ZLIB_INTERNAL _tr_stored_block( deflate_state *s, charf *buf, ulg stored_len, int last) { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); s->pending += stored_len; #ifdef ZLIB_DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; s->bits_sent += stored_len<<3; #endif } /* =========================================================================== * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) */ void ZLIB_INTERNAL _tr_flush_bits( deflate_state *s) { bi_flush(s); } /* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer. */ void ZLIB_INTERNAL _tr_align( deflate_state *s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); #ifdef ZLIB_DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); } /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static * trees or store, and write out the encoded block. */ void ZLIB_INTERNAL _tr_flush_block( deflate_state *s, charf *buf, ulg stored_len, int last) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { /* Check if the file is binary or text */ if (s->strm->data_type == Z_UNKNOWN) s->strm->data_type = detect_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, s->static_len)); build_tree(s, (tree_desc *)(&(s->d_desc))); Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, s->static_len)); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ opt_lenb = (s->opt_len+3+7)>>3; static_lenb = (s->static_len+3+7)>>3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->last_lit)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else if (stored_len+4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ _tr_stored_block(s, buf, stored_len, last); #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { send_bits(s, (DYN_TREES<<1)+last, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->opt_len; #endif } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); /* The above check is made mod 2^32, for files larger than 512 MB * and uLong implemented on 32 bits. */ init_block(s); if (last) { bi_windup(s); #ifdef ZLIB_DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ int ZLIB_INTERNAL _tr_tally ( deflate_state *s, unsigned dist, unsigned lc) { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } #ifdef TRUNCATE_BLOCK /* Try to guess if it is profitable to stop the current block here */ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)((long)s->strstart - s->block_start); int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", s->last_lit, in_length, out_length, 100L - out_length*100L/in_length)); if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } #endif return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } /* =========================================================================== * Send the block data compressed using the given Huffman trees */ local void compress_block( deflate_state *s, const ct_data *ltree, const ct_data *dtree) { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= (unsigned)base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); } /* =========================================================================== * Check if the data type is TEXT or BINARY, using the following algorithm: * - TEXT if the two conditions below are satisfied: * a) There are no non-portable control characters belonging to the * "black list" (0..6, 14..25, 28..31). * b) There is at least one printable character belonging to the * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). * - BINARY otherwise. * - The following partially-portable control characters form a * "gray list" that is ignored in this detection algorithm: * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). * IN assertion: the fields Freq of dyn_ltree are set. */ local int detect_data_type( deflate_state *s) { /* black_mask is the bit mask of black-listed bytes * set bits 0..6, 14..25, and 28..31 * 0xf3ffc07f = binary 11110011111111111100000001111111 */ unsigned long black_mask = 0xf3ffc07fUL; int n; /* Check for non-textual ("black-listed") bytes. */ for (n = 0; n <= 31; n++, black_mask >>= 1) if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) return Z_BINARY; /* Check for textual ("white-listed") bytes. */ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 || s->dyn_ltree[13].Freq != 0) return Z_TEXT; for (n = 32; n < LITERALS; n++) if (s->dyn_ltree[n].Freq != 0) return Z_TEXT; /* There are no "black-listed" or "white-listed" bytes: * this stream either is empty or has tolerated ("gray-listed") bytes only. */ return Z_BINARY; } /* =========================================================================== * Reverse the first len bits of a code, using straightforward code (a faster * method would use a table) * IN assertion: 1 <= len <= 15 */ local unsigned bi_reverse( unsigned code, int len) { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ local void bi_flush( deflate_state *s) { if (s->bi_valid == 16) { put_short(s, s->bi_buf); s->bi_buf = 0; s->bi_valid = 0; } else if (s->bi_valid >= 8) { put_byte(s, (Byte)s->bi_buf); s->bi_buf >>= 8; s->bi_valid -= 8; } } /* =========================================================================== * Flush the bit buffer and align the output on a byte boundary */ local void bi_windup( deflate_state *s) { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } stella-5.1.1/src/zlib/trees.h000066400000000000000000000204301324334165500160310ustar00rootroot00000000000000/* header created automatically with -DGEN_TREES_H */ local const ct_data static_ltree[L_CODES+2] = { {{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, {{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, {{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, {{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, {{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, {{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, {{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, {{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, {{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, {{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, {{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, {{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, {{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, {{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, {{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, {{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, {{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, {{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, {{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, {{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, {{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, {{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, {{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, {{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, {{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, {{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, {{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, {{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, {{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, {{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, {{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, {{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, {{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, {{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, {{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, {{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, {{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, {{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, {{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, {{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, {{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, {{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, {{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, {{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, {{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, {{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, {{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, {{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, {{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, {{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, {{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, {{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, {{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, {{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, {{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, {{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, {{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, {{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} }; local const ct_data static_dtree[D_CODES] = { {{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, {{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, {{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, {{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, {{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, {{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} }; const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 }; const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 }; local const int base_length[LENGTH_CODES] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 }; local const int base_dist[D_CODES] = { 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 }; stella-5.1.1/src/zlib/uncompr.c000066400000000000000000000055241324334165500163740ustar00rootroot00000000000000/* uncompr.c -- decompress a memory buffer * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #define ZLIB_INTERNAL #include "zlib.h" /* =========================================================================== Decompresses the source buffer into the destination buffer. *sourceLen is the byte length of the source buffer. Upon entry, *destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, *destLen is the size of the decompressed data and *sourceLen is the number of source bytes consumed. Upon return, source + *sourceLen points to the first unused input byte. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ int ZEXPORT uncompress2 ( Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen) { z_stream stream; int err; const uInt max = (uInt)-1; uLong len, left; Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ len = *sourceLen; if (*destLen) { left = *destLen; *destLen = 0; } else { left = 1; dest = buf; } stream.next_in = (z_const Bytef *)source; stream.avail_in = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; stream.opaque = (voidpf)0; err = inflateInit(&stream); if (err != Z_OK) return err; stream.next_out = dest; stream.avail_out = 0; do { if (stream.avail_out == 0) { stream.avail_out = left > (uLong)max ? max : (uInt)left; left -= stream.avail_out; } if (stream.avail_in == 0) { stream.avail_in = len > (uLong)max ? max : (uInt)len; len -= stream.avail_in; } err = inflate(&stream, Z_NO_FLUSH); } while (err == Z_OK); *sourceLen -= len + stream.avail_in; if (dest != buf) *destLen = stream.total_out; else if (stream.total_out && err == Z_BUF_ERROR) left = 1; inflateEnd(&stream); return err == Z_STREAM_END ? Z_OK : err == Z_NEED_DICT ? Z_DATA_ERROR : err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : err; } int ZEXPORT uncompress ( Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen) { return uncompress2(dest, destLen, source, &sourceLen); } stella-5.1.1/src/zlib/zconf.h000066400000000000000000000401141324334165500160270ustar00rootroot00000000000000/* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H /* Added by SA: 2017-07-09 */ #if defined(BSPF_UNIX) || defined(BSPF_MAC_OSX) #define HAVE_UNISTD_H #endif #define HAVE_STDARG_H /***************************/ /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. * Even better than compiling with -DZ_PREFIX would be to use configure to set * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET /* all linked symbols and init macros */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align # define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block # define _tr_tally z__tr_tally # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 # define adler32_z z_adler32_z # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit # define deflateInit2 z_deflateInit2 # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams # define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset # define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table # ifndef Z_SOLO # define gz_error z_gz_error # define gz_intmax z_gz_intmax # define gz_strwinerror z_gz_strwinerror # define gzbuffer z_gzbuffer # define gzclearerr z_gzclearerr # define gzclose z_gzclose # define gzclose_r z_gzclose_r # define gzclose_w z_gzclose_w # define gzdirect z_gzdirect # define gzdopen z_gzdopen # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush # define gzfread z_gzfread # define gzfwrite z_gzfwrite # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets # define gzoffset z_gzoffset # define gzoffset64 z_gzoffset64 # define gzopen z_gzopen # define gzopen64 z_gzopen64 # ifdef _WIN32 # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread # define gzrewind z_gzrewind # define gzseek z_gzseek # define gzseek64 z_gzseek64 # define gzsetparams z_gzsetparams # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc # define gzvprintf z_gzvprintf # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit z_inflateBackInit # define inflateBackInit_ z_inflateBackInit_ # define inflateCodesUsed z_inflateCodesUsed # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetDictionary z_inflateGetDictionary # define inflateGetHeader z_inflateGetHeader # define inflateInit z_inflateInit # define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflateValidate z_inflateValidate # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress # define uncompress2 z_uncompress2 # endif # define zError z_zError # ifndef Z_SOLO # define zcalloc z_zcalloc # define zcfree z_zcfree # endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion /* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte # define Bytef z_Bytef # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func # ifndef Z_SOLO # define gzFile z_gzFile # endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func # define intf z_intf # define out_func z_out_func # define uInt z_uInt # define uIntf z_uIntf # define uLong z_uLong # define uLongf z_uLongf # define voidp z_voidp # define voidpc z_voidpc # define voidpf z_voidpf /* all zlib structs in zlib.h and zconf.h */ # define gz_header_s z_gz_header_s # define internal_state z_internal_state #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) # define OS2 #endif #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) # ifndef WIN32 # define WIN32 # endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) # ifndef SYS16BIT # define SYS16BIT # endif # endif #endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ #ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # ifndef STDC99 # define STDC99 # endif # endif #endif #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC #endif #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) # define STDC #endif #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) # define STDC #endif #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) # define STDC #endif #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ # define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ # define const /* note: need a more gentle solution here */ # endif #endif #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO typedef unsigned long z_size_t; #else # define z_longlong long long # if defined(NO_SIZE_T) typedef unsigned NO_SIZE_T z_size_t; # elif defined(STDC) # include typedef size_t z_size_t; # else typedef unsigned long z_size_t; # endif # undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K # define MAX_MEM_LEVEL 8 # else # define MAX_MEM_LEVEL 9 # endif #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ /* Type declarations */ #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ #ifdef SYS16BIT # if defined(M_I86SM) || defined(M_I86MM) /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER # define FAR _far # else # define FAR far # endif # endif # if (defined(__SMALL__) || defined(__MEDIUM__)) /* Turbo C small or medium model */ # define SMALL_MEDIUM # ifdef __BORLANDC__ # define FAR _far # else # define FAR far # endif # endif #endif #if defined(WINDOWS) || defined(WIN32) /* If building or using zlib as a DLL, define ZLIB_DLL. * This is not mandatory, but it offers a little performance increase. */ # ifdef ZLIB_DLL # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) # ifdef ZLIB_INTERNAL # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif # endif # endif /* ZLIB_DLL */ /* If building or using zlib with the WINAPI/WINAPIV calling convention, * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) # ifdef ZLIB_DLL # ifdef ZLIB_INTERNAL # define ZEXPORT __declspec(dllexport) # define ZEXPORTVA __declspec(dllexport) # else # define ZEXPORT __declspec(dllimport) # define ZEXPORTVA __declspec(dllimport) # endif # endif #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef FAR # define FAR #endif #if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void const *voidpc; typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte const *voidpc; typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) # include # if (UINT_MAX == 0xffffffffUL) # define Z_U4 unsigned # elif (ULONG_MAX == 0xffffffffUL) # define Z_U4 unsigned long # elif (USHRT_MAX == 0xffffffffUL) # define Z_U4 unsigned short # endif #endif #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_STDARG_H #endif #ifdef STDC # ifndef Z_SOLO # include /* for off_t */ # endif #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO # include /* for va_list */ # endif #endif #ifdef _WIN32 # ifndef Z_SOLO # include /* for wchar_t */ # endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) # define Z_HAVE_UNISTD_H #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif # endif #endif #if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 # define Z_LFS64 #endif #if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) # define Z_LARGE64 #endif #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) # define Z_WANT64 #endif #if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) #pragma map(deflateInit_,"DEIN") #pragma map(deflateInit2_,"DEIN2") #pragma map(deflateEnd,"DEEND") #pragma map(deflateBound,"DEBND") #pragma map(inflateInit_,"ININ") #pragma map(inflateInit2_,"ININ2") #pragma map(inflateEnd,"INEND") #pragma map(inflateSync,"INSY") #pragma map(inflateSetDictionary,"INSEDI") #pragma map(compressBound,"CMBND") #pragma map(inflate_table,"INTABL") #pragma map(inflate_fast,"INFA") #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ stella-5.1.1/src/zlib/zlib.h000066400000000000000000002737571324334165500156750ustar00rootroot00000000000000/* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.11, January 15th, 2017 Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.2.11" #define ZLIB_VERNUM 0x12b0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 11 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip and raw deflate streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in the case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte will go here */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text for deflate, or the decoding state for inflate */ uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header FAR *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. In that case, zlib is thread-safe. When zalloc and zfree are Z_NULL on entry to the initialization function, they are set to internal routines that use the standard library functions malloc() and free(). On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use by the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field for deflate() */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Generate more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary. Some output may be provided even if flush is zero. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), which can be used if desired to determine whether or not there is more ouput in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed codes block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used in the first deflate call after deflateInit if all the compression is to be done in a single step. In order to complete in one call, avail_out must be at least the value returned by deflateBound (see below). Then deflate is guaranteed to return Z_STREAM_END. If not enough output space is provided, deflate will not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the Adler-32 checksum of all input read so far (that is, total_in bytes). If a gzip stream is being generated, then strm->adler will be the CRC-32 checksum of the input read so far. (See deflateInit2 below.) deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL or the state was inadvertently written over by the application), or Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. In the current version of inflate, the provided input is not read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the first call). If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression. Actual decompression will be done by inflate(). So next_in, and avail_in, next_out, and avail_out are unused and unchanged. The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), then next_in and avail_in are updated accordingly, and processing will resume at this point for the next call of inflate(). - Generate more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. If the caller of inflate() does not provide both available input and available output space, it is possible that there will be no progress made. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. To assist in this, on return inflate() always sets strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the stream completes, which reduces inflate's memory footprint. If the stream does not complete, either because not all of the stream is provided or not enough output space is provided, then a sliding window will be allocated and inflate() can be called again to continue the operation as if Z_NO_FLUSH had been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the effects of the flush parameter in this implementation are on the return value of inflate() as noted below, when inflate() returns early when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed Adler-32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained unless inflateGetHeader() is used. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output produced so far. The CRC-32 is checked against the gzip trailer, as is the uncompressed length, modulo 2^32. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value, in which case strm->msg points to a string with a more specific error), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL, or the state was inadvertently written over by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress was possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is to be attempted. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state was inconsistent. */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. For the current implementation of deflate(), a windowBits value of 8 (a window size of 256 bytes) is not supported. As a result, a request for 8 will result in 9 (a 512-byte window). In that case, providing 8 to inflateInit2() will result in an error when the zlib header with 9 is checked against the initialization of inflate(). The remedy is to not use 8 with deflateInit2() with this initialization, or at least in that case use 9 with inflateInit2(). windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute a check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to the appropriate value, if the operating system was determined at compile time. If a gzip stream is being written, strm->adler is a CRC-32 instead of an Adler-32. For raw deflate or gzip encoding, a request for a 256-byte window is rejected as invalid, since only the zlib header provides a means of transmitting the window size to the decompressor. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been consumed and all output has been delivered when using any of the flush options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the Adler-32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The Adler-32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the Adler-32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by deflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similary, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up to 258 bytes less in that case, due to how zlib's implementation of deflate manages the sliding window and lookahead for matches, where matches can be up to 258 bytes long. If the application needs the last window-size bytes of input, then that would need to be saved by the application outside of zlib. deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been set unchanged. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression approach (which is a function of the level) or the strategy is changed, and if any input has been consumed in a previous deflate() call, then the input available so far is compressed with the old level and strategy using deflate(strm, Z_BLOCK). There are three approaches for the compression levels 0, 1..3, and 4..9 respectively. The new level and strategy will take effect at the next call of deflate(). If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does not have enough output space to complete, then the parameter change will not take effect. In this case, deflateParams() can be called again with the same parameters and more output space to try again. In order to assure a change in the parameters on the first try, the deflate stream should be flushed using deflate() with Z_BLOCK or other flush request until strm.avail_out is not zero, before calling deflateParams(). Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be applied to the the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if there was not enough output space to complete the compression of the available input data before a change in the strategy or approach. Note that in the case of a Z_BUF_ERROR, the parameters are not changed. A return value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be retried with more output space. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). If that first deflate() call is provided the sourceLen input bytes, an output buffer allocated to the size returned by deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed to return Z_STREAM_END. Note that it is possible for the compressed size to be larger than the value returned by deflateBound() if flush options other than Z_FINISH or Z_NO_FLUSH are used. */ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, unsigned *pending, int *bits)); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not provided would be due to the available output space having being consumed. The number of bits of output not provided are between 0 and 7, where they await more bits to join them in order to fill out a full byte. If pending or bits are Z_NULL, then those values are not set. deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head)); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an Adler-32 or a CRC-32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see below), inflate() will not automatically decode concatenated gzip streams. inflate() will return Z_STREAM_END at the end of the gzip stream. The state would need to be reset to continue decoding a subsequent gzip stream. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the Adler-32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similary, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync searches for a 00 00 FF FF pattern in the compressed data. All full flush points have this pattern, but not all occurrences of this pattern are full flush points. inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, int windowBits)); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. If the window size is changed, then the memory allocated for the window is freed, and the window will be reallocated by inflate() if needed. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, int bits, int value)); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above, or -65536 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, gz_headerp head)); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func) OF((void FAR *, z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than inflate() for file i/o applications, in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. inflate() can be faster on modern CPUs when used with large buffers. inflateBack() trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the default behavior of inflate(), which expects a zlib header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero -- buf is ignored in that case -- and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: ZLIB_DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ #ifndef Z_SOLO /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress() is equivalent to compress2() with a level parameter of Z_DEFAULT_COMPRESSION. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed data. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point. */ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen)); /* Same as uncompress, except that sourceLen is a pointer, where the length of the source is *sourceLen. On return, *sourceLen is the number of source bytes consumed. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) 'T' will request transparent writing or appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. The addition of "x" when writing will create the file exclusively, which fails if the file already exists. On systems that support it, the addition of "e" when reading or writing will set the flag to close the file on an execve() call. These functions, as well as gzip, will read and decode a sequence of gzip streams in a file. The append function of gzopen() can be used to create such a file. (Also see gzflush() for another way to do this.) When appending, gzopen does not test whether the file begins with a gzip stream, nor does it look for the end of the gzip streams to begin appending. gzopen will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. When reading, this will be detected automatically by looking for the magic two- byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* gzdopen associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. If you are using fileno() to get the file descriptor from a FILE *, then you will have to use dup() to avoid double-close()ing the file descriptor. Both gzclose() and fclose() will close the associated file descriptor, so they need to have different file descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); /* Set the internal buffer size used by this library's functions. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Three times that size in buffer space is allocated. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. Previously provided data is flushed before the parameter change. gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not opened for writing, Z_ERRNO if there is an error writing the flushed data, or Z_MEM_ERROR if there is a memory allocation error. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream. Any number of gzip streams may be concatenated in the input file, and will all be decompressed by gzread(). If something other than a gzip stream is encountered after a gzip stream, that remaining trailing garbage is ignored (and no error is returned). gzread can be used to read a gzip file that is being concurrently written. Upon reaching the end of the input, gzread will return with the available data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then gzclearerr can be used to clear the end of file indicator in order to permit gzread to be tried again. Z_OK indicates that a gzip stream was completed on the last gzread. Z_BUF_ERROR indicates that the input file ended in the middle of a gzip stream. Note that gzread does not return -1 in the event of an incomplete gzip stream. This error is deferred until gzclose(), which will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip stream. Alternatively, gzerror can be used before gzclose to detect this case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. If len is too large to fit in an int, then nothing is read, -1 is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, gzFile file)); /* Read up to nitems items of size size from file to buf, otherwise operating as gzread() does. This duplicates the interface of stdio's fread(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfread() returns the number of full items read of size size, or zero if the end of the file was reached and a full item could not be read, or if there was an error. gzerror() must be consulted if zero is returned in order to determine if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is read, zero is returned, and the error state is set to Z_STREAM_ERROR. In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a multiple of size, then the final partial item is nevetheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written file, reseting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, z_size_t nitems, gzFile file)); /* gzfwrite() writes nitems items of size size from buf to file, duplicating the interface of stdio's fwrite(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfwrite() returns the number of full items written of size size, or zero if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is written, zero is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or a negative zlib error code in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len == 1, the string is terminated with a null character. If no characters are read due to an end-of-file or len < 1, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); /* Push one character back onto the stream to be read as the first character on the next read. At least one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatenated gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ /* ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); Returns the current offset in the file being read or written. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Returns true (1) if the end-of-file indicator has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). When writing, gzdirect() returns true (1) if transparent writing was requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: gzdirect() is not needed when writing. Transparent writing must be explicitly requested, so the application already knows the answer. When linking statically, using gzdirect() will include all of the zlib code for gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file and deallocates the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ #endif /* !Z_SOLO */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, z_size_t len)); /* Same as adler32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note that the z_off_t type (like off_t) is a signed integer. If len2 is negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, z_size_t len)); /* Same as crc32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); #ifdef Z_PREFIX_SET # define z_deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) # define z_inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #else # define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) # define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) # define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #endif #ifndef Z_SOLO /* gzgetc() macro and its supporting function and exposed data structure. Note * that the real internal state is much larger than the exposed structure. * This abbreviated structure exposes just enough for the gzgetc() macro. The * user should not mess with these exposed elements, since their names or * behavior could change in the future, perhaps even capriciously. They can * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #else # define gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) # ifdef Z_PREFIX_SET # define z_gzopen z_gzopen64 # define z_gzseek z_gzseek64 # define z_gztell z_gztell64 # define z_gzoffset z_gzoffset64 # define z_adler32_combine z_adler32_combine64 # define z_crc32_combine z_crc32_combine64 # else # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # endif # ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif #else /* Z_SOLO */ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif /* !Z_SOLO */ /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, const char *mode)); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, const char *format, va_list va)); # endif #endif #ifdef __cplusplus } #endif #endif /* ZLIB_H */ stella-5.1.1/src/zlib/zutil.c000066400000000000000000000160721324334165500160600ustar00rootroot00000000000000/* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2017 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #ifndef Z_SOLO # include "gzguts.h" #endif z_const char * const z_errmsg[10] = { (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ (z_const char *)"stream end", /* Z_STREAM_END 1 */ (z_const char *)"", /* Z_OK 0 */ (z_const char *)"file error", /* Z_ERRNO (-1) */ (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ (z_const char *)"" }; const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; } uLong ZEXPORT zlibCompileFlags() { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef ZLIB_DEBUG flags += 1 << 8; #endif #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif #ifdef ZLIB_WINAPI flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif #ifdef NO_GZIP flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; #endif #ifdef FASTEST flags += 1L << 21; #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifdef NO_vsnprintf flags += 1L << 25; # ifdef HAS_vsprintf_void flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void flags += 1L << 26; # endif # endif #else flags += 1L << 24; # ifdef NO_snprintf flags += 1L << 25; # ifdef HAS_sprintf_void flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void flags += 1L << 26; # endif # endif #endif return flags; } #ifdef ZLIB_DEBUG #include # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; void ZLIB_INTERNAL z_error ( char *m) { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char * ZEXPORT zError( int err) { return ERR_MSG(err); } #if defined(_WIN32_WCE) /* The Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ int errno = 0; #endif #ifndef HAVE_MEMCPY void ZLIB_INTERNAL zmemcpy( Bytef* dest, const Bytef* source, uInt len) { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } int ZLIB_INTERNAL zmemcmp( const Bytef* s1, const Bytef* s2, uInt len) { uInt j; for (j = 0; j < len; j++) { if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; } return 0; } void ZLIB_INTERNAL zmemzero( Bytef* dest, uInt len) { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } #endif #ifndef Z_SOLO #ifdef SYS16BIT #ifdef __TURBOC__ /* Turbo C in 16-bit mode */ # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes * and farmalloc(64K) returns a pointer with an offset of 8, so we * must fix the pointer. Warning: the pointer must be put back to its * original form in order to free it, use zcfree(). */ #define MAX_PTR 10 /* 10*64K = 640K */ local int next_ptr = 0; typedef struct ptr_table_s { voidpf org_ptr; voidpf new_ptr; } ptr_table; local ptr_table table[MAX_PTR]; /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; (void)opaque; /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ if (bsize < 65520L) { buf = farmalloc(bsize); if (*(ush*)&buf != 0) return buf; } else { buf = farmalloc(bsize + 16L); } if (buf == NULL || next_ptr >= MAX_PTR) return NULL; table[next_ptr].org_ptr = buf; /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { int n; (void)opaque; if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; } /* Find the original pointer */ for (n = 0; n < next_ptr; n++) { if (ptr != table[n].new_ptr) continue; farfree(table[n].org_ptr); while (++n < next_ptr) { table[n-1] = table[n]; } next_ptr--; return; } Assert(0, "zcfree: ptr not found"); } #endif /* __TURBOC__ */ #ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); } #endif /* M_I86 */ #endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC extern voidp malloc OF((uInt size)); extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif voidpf ZLIB_INTERNAL zcalloc ( voidpf opaque, unsigned items, unsigned size) { (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree ( voidpf opaque, voidpf ptr) { (void)opaque; free(ptr); } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ stella-5.1.1/src/zlib/zutil.h000066400000000000000000000157271324334165500160730ustar00rootroot00000000000000/* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef ZUTIL_H #define ZUTIL_H #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include "zlib.h" #if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include # endif # include # include #endif #ifdef Z_SOLO typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ #ifndef DEF_WBITS # define DEF_WBITS MAX_WBITS #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default memLevel */ #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 /* The three kinds of block type */ #define MIN_MATCH 3 #define MAX_MATCH 258 /* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ /* target dependencies */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 # ifndef Z_SOLO # if defined(__TURBOC__) || defined(__BORLANDC__) # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) /* Allow compilation with ANSI keywords only enabled */ void _Cdecl farfree( void *block ); void *_Cdecl farmalloc( unsigned long nbytes ); # else # include # endif # else /* MSC or DJGPP */ # include # endif # endif #endif #ifdef AMIGA # define OS_CODE 1 #endif #if defined(VAXC) || defined(VMS) # define OS_CODE 2 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif #ifdef __370__ # if __TARGET_LIB__ < 0x20000000 # define OS_CODE 4 # elif __TARGET_LIB__ < 0x40000000 # define OS_CODE 11 # else # define OS_CODE 8 # endif #endif #if defined(ATARI) || defined(atarist) # define OS_CODE 5 #endif #ifdef OS2 # define OS_CODE 6 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 7 # ifndef Z_SOLO # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fdopen */ # else # ifndef fdopen # define fdopen(fd,mode) NULL /* No fdopen() */ # endif # endif # endif #endif #ifdef __acorn # define OS_CODE 13 #endif #if defined(WIN32) && !defined(__CYGWIN__) # define OS_CODE 10 #endif #ifdef _BEOS_ # define OS_CODE 16 #endif #ifdef __TOS_OS400__ # define OS_CODE 18 #endif #ifdef __APPLE__ # define OS_CODE 19 #endif #if defined(_BEOS_) || defined(RISCOS) # define fdopen(fd,mode) NULL /* No fdopen() */ #endif #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ # ifndef _PTRDIFF_T_DEFINED typedef int ptrdiff_t; # define _PTRDIFF_T_DEFINED # endif # else # define fdopen(fd,type) _fdopen(fd,type) # endif #endif #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif /* common defaults */ #ifndef OS_CODE # define OS_CODE 3 /* assume Unix */ #endif #ifndef F_OPEN # define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ #if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) /* Use our own functions for small and medium model with MSC <= 5.0. * You may have to use the same strategy for Borland C (untested). * The __SC__ check is for Symantec. */ # define NO_MEMCPY #endif #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) # define HAVE_MEMCPY #endif #ifdef HAVE_MEMCPY # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ # define zmemcpy _fmemcpy # define zmemcmp _fmemcmp # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); #endif /* Diagnostic functions */ #ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif #ifndef Z_SOLO voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} /* Reverse the bytes in a 32-bit value */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */